Challenge details :
Come and test the brand new game machine : Patchinko ! Because the chances to win are almost zero, we are helping the players.
Prove that it is possible to compromise the system in order to read the flag file.
Note : the service allow you to patch a single byte of the binary before it runs.
Service : nc challenges1.france-cybersecurity-challenge.fr 4009
SHA256(patchinko.bin) = b09fe0d4228fa0a1ff58cee680f5d57cb6f2aa54e65f7c2c43d7c86e61b4ba1f.
File : patchinko.bin
This challenge was simply about patching the right byte with the right value in order to change the program behavior.
I guess several solutions were working, but I decided to patch a call to
strlen into a call to
system, since we had control over the string that was supposed to be the argument of
Patching time :)
At the beginning, I decided (as usual) to connect to the service and I got greeted with a prompt asking me to patch the binary :
Patching the first byte with 0x00 made the binary impossible to run, since the beginning of the ELF magic number got overwritten.
OK. It was time to run the program locally :
Well, they were indeed helping us guessing the number, but the binary wasn’t printing the flag anyway ahah.
I tried to send different inputs but it was always ending in that way and I could not overflow on any input…
radare2 to inspect what was happening but there was nothing interesting, no hidden function or whatever :/
I finally noticed that the first string was printed using a call to
echo [string] as parameter, then I remembered the name of the challenge and the fact that we were allowed to patch a byte, andtook a look at the
radare2 again :
As you can see on this screenshot, the
system call was followed by calls to
That call to
system was here on purpose, showing us the way for sure. I decided to examine the
PLT section, and I noticed that the
system entry was just next to the
strlen entry :
Note that the offset for both entry were
At this point, getting the flag was easy : I just had to patch the lowest significant byte in the offset of the
strlen call opcodes, to transform it into a
system call. Since the parameter of the
strlen function was my input, I could possibly give the argument I wanted for the
In my case, the
strlen was made at
0x00400888, and the instruction was coded with the bytes
e833feffff which is the little endian for
0xfffffe33 (you can check this out on the previous screenshot).
In order to transform the instruction, one must know about the way a
call instruction is constructed :
The first byte,
e8, tells the machine that the instruction is going to be a
near call. The rest of the bytes represent an offset.
When the computer reaches such a
near call, it takes the next instruction’s address and add the offset to it. The result will be the location of the function we want to call (when the function called is an extern function, that location is the
OK. Let’s use my binary as an example :
# 0x0040088d = address of the instruction following the call to strlen # 0xfffffe33 = offset to be add to this address # 0x004006c0 = address of the strlen function's entry in the PLT 0x0040088d + 0xfffffe33 = 0x0040088d - 0x000001cd = 0x004006c0
near call instruction was indeed jumping to
0x004006c0, as expected.
BUT, I wanted to transform that instruction into a
near call to
0x004006d0 are really close to each other, patching the lowest significant byte in the offset made that transformation possible :
# 0x0040088d = address of the instruction following the call to strlen # 0xfffffe43 = patched offset (43 instead of 33 at the end) # 0x004006d0 = address of the system function's entry in the PLT # 0x004006d0 - 0x004006c0 = 0x10, which is why I replaced 0xfffffe33 with 0xfffffe43 0x0040088d + 0xfffffe43 = 0x0040088d - 0x000001bd = 0x004006d0
The last step was to use an hexadecimal editor, such as
hexeditor : I quickly found that the
0x33 byte was located at the offset 0x889 in the editor and I patched it with
Here is the result, inspecting the patched binary into
At this point, I could simply run the binary and input
sh instead of
no, and my input was passed as an argument to the
To get the flag, I had to connect to the service using
nc and simply tell which byte I wanted to patch (with it’s value) :
And here it is !