© Noiche

char nick[] = "N0iche";

printf("https://www.root-me.org/%s\n", nick);

printf("%s\x40protonmail\x2ecom\n", nick);

[FCSC2020] - PWN - Patchinko

May 5, 2020 • Write-Up,FCSC-2020,PWN

Challenge details :

CTF Challenge Category Value Solves
FCSC2020 Patchinko PWN 141 117

Description

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

TL;DR

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 strlen

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 :

prompt

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 :

running

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… I used 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 system, with 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 main in radare2 again :

running

As you can see on this screenshot, the system call was followed by calls to fgets and strlen… Hum…

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 :

plt_system

Note that the offset for both entry were 0x0x004006c0 and 0x0x004006d0.

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 system call.

In my case, the call to 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 PLT)

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

The near call instruction was indeed jumping to 0x004006c0, as expected.

BUT, I wanted to transform that instruction into a near call to 0x004006d0. Since 0x004006c0 and 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 Ox43.

Here is the result, inspecting the patched binary into radare2 :

patched

At this point, I could simply run the binary and input sh instead of yes or no, and my input was passed as an argument to the system function.

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) :

flag

And here it is !

FCSC{b4cbc07a77bb0984b994c9e34b2897ab49f08524402c38621a38bc4475102998}