Yo! Life kept me more than busy, but now I’ve got a little more time on my hands. I decided to do a write-up on the following binary, because it taught me some new things, compared to the easy reversemes I did before.

Note : Re-write due to dead links

Binary

The binary is the one below and can reversed into its binary form by doing:

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

Initial Analysis

The file command reveals that it is a 32-bit ELF binary that is not stripped.

$ file bomb bomb: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.15, BuildID[sha1]=e6a360ee322cefe6f3bb6110b5b587bc891d08fe, not stripped

First run

When first running the binary we can directly see that it is a multi stage binary consisting of 4 phases. It looks like only when we are able to figure out all 4 phases we will solve the challenge

So let’s start one by one

Analysis phase 1 - Yellow

When selecting the yellow option in the main menu we’re prompted for a password. So I loaded the whole thing into BinaryNinja and took a look at the yellow routine.

As yellow_preflight shows, this subroutine reads 10 bytes (0xa) user input from stdin via fgets and stores it into something BinaryNinja labeled as buffer. Afterwards, the input is compared byte for byte against a “fixed” sequence. So we can just convert the hex values to ASCII as all seven of them are in valid ASCII range.

res = '' for i, v in enumerate([0x38, 0x34, 0x33, 0x37, 0x31, 0x30, 0x36, 0x35]): res += ''.join(chr(v)) print(res) 84371065

That’s that!

Analysis Phase 2 - Green

So next up to the green phase. Same routine again. We’re prompted for a password once again.

Let’s dive back into BinaryNinja again.

So basically the green_preflight one again uses fgets to prompt for user input from stdin again. At most 0x14 bytes. However, only the first 0x8 bytes are taken into consideration in the call to strncmp against a hardcoded value. As dcaotdae is already 0x8 bytes in length we can just use this one as a password without having to care about filling the remaining free bytes in the user controlled input buffer…

That said, when using dcaotdae as a password it is getting accepted but the decision is overriden by good old NOIZEV so we did not solve that one yet…

So what did we overlook?

When double checking the responsible assembly we notice that whatever is returned by the strncmp operation (stored in EAX!) is undergoing the test eax, eax before deciding where to jump.

In case of us using dcaotdae as the password the strncmp is returning 0 since:

The strcmp() and strncmp() functions return an integer less than, equal to, or greater than zero if s1 (or the first n bytes thereof) is found, respectively, to be less than, to match, or begreater than s2.

The directly following test eax, eax , which is doing a bitwise and on the two provided arguments and sets register flags accordingly:

TEST sets the zero flag, ZF, when the result of the AND operation is zero. If two operands are equal, their bitwise AND is zero when both are zero. TEST also sets the sign flag, SF, when the most significant bit is set in the result, and the parity flag,PF, when the number of set bits is even.

As test eax, eax == test 0, 0 == 0 & 0 which according to basic boolean logic is also 0 . As a result the ZERO flag is set. Hence the jne 0x804998e is not taken and instead the control flow is redirected to 0x8049946 , which is responsible for us still being stuck on the green phase.

call strncmp ; set eax==0 if match, else to 1 test eax, eax ; set ZF==1 if eax==0, else ZF==0 jne 0x804998e ; jump to 0x803998e if ZF==0

So the game plan is to take the jump to 0x804998e by forcing the strncmp to return != 0 right?

Wrong! So what is the deal here? Turns out us providing dcaotdae as the password is partially correct. To understand how to solve this properly we need to look very closely at what is responsible for re-engaging the ‘fuse’ and how local variables are setup on a function stack frame. Right now our situation looks like this:

Let’s backtrack! Assuming we’re still providing dcaotdae as the password, control flow would be redirected to this basic block:

At this point the following happens:

mov eax, [ebp-0x8] ; eax=1 and eax, 1 ; yields eax=1 test eax, eax ; doesn't set any flag sete al ; al=0 because it sets the byte in the operand to 1 if ZF is set, otherwise sets the operand to 0. movzx eax, al ; eax=0 mov [ebp-0x8], eax ; [ebp-0x8]=0 [...] mov eax, [ebp-0x8] ; eax=0 and eax, 0x1 ; and 0,1 --> eax=0 test eax, eax ; 0 & 0 --> ZF set sete al ; al=1, because ZF=1 movzx eax, al ; eax=1 mov [ebp-0x8], eax ; re-set [ebp-0x8]=1

So in this situation both eax and [ebp-0x8] are set to 1. The next direct jump to 0x804999a leads here:

mov eax, [ebp-0x8] ; eax=1 (still) test eax, eax ; ZF=0 jne 0x80499ad ; goto 0x80499ad

And with that we would return to the main menu and get another chance with the green fuse still in place. So how do we solve this?

The answer lies within how local function variables are set up and that the provided user input via the fgets call is able to corrupt the value stored at [ebp-0x8] . How? Check this out:

It shows that the buffer, which is used for the fgets call and is provided to the green_preflight function is located at [ebp-0x14] . [ebp-0x8] , which as we saw is determining the outcome of this function is pretty darn close to the buffer:

> pcalc 0x14 - 0x8 12 0xc 0y1100

The difference between the buffer and the value stored at [ebp-0x8] is only 12 bytes, which logically makes it the buffer size too. However, remember that we’re able to provide 20 bytes (0x14) to fgets . That means we can easily overflow into [ebp-0x8] ! So we just saw that the value of [ebp-0x8] is set to 1 and even when providing the correct password ( dcaotdae ) this, let’s say “flag” value is breaking it for us. As it seemingly is inconvient for us when this [ebp-0x8] is 1 overflowing into it and setting it to 0 should “reverse” the actions and keep the defused green phase in tact!

Why does adding “AAA” work? The answer lies in man fgets :

[…]. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (’\0’) is stored after the last character in the buffer.

The added NULL byte is the one overflowing into [ebp-0x8] ! This also shows that any 3 additional bytes do the job! And with that we solved phase 2 of 4!

Analysis phase 3 - Blue

Right when selection the blue phase we’re greeted with:

As we do not know what the heck a circuit traversal path is at this point we just have to check the disassembly. Back to BinaryNinja:

blue_preflight offers nothing new as it just reads in up to 16 bytes into a buffer again. The main blue routine is quite a bit longer than all phases before but essentially it teaches us another very common data structure. So let’s step through this:

This part sets up a memory address labeled as graph in [ebp-0x4] . So what the graph look like?

The start address, which is put into [ebp-0x8] directly points to the greyish marked area. Let’s beautify this by quickly examining this memory in GDB:

This is already way more readable. But still looks kinda random. If you look closely you can see that the referenced addresses starting with 0x804cXXX are all within the graph space:

Afterwards the same memory address is loaded into eax and a value I labeled as start_val is put 4 bytes after the graph memory address.

int32_t start_val = 0x47bbfa96;

Then a loop construct is entered with at most 0xe iterations. As initially the loop counter is set to 0 control flow is continuing here:

Essentially, it loops over the user input via the loop counter and checks whether the current byte is an L , an R , or a newline character (==EOF).

Depending on the result the graph is accessed in different ways:

As an example, let’s say our user input would have been a single ‘L’ :

mov eax, [ebp-0x4] ; eax = 0x804c160 —▸ 0x804c19c —▸ ... mov eax, [eax] ; eax = 0x804c19c —▸ ... mov [ebp-0x4], eax ; set new head of graph to 0x804c19c —▸ ...

As an example, let’s say our user input would have been a single ‘R’ :

mov eax, [ebp-0x4] ; eax = 0x804c160 —▸ 0x804c19c —▸ ... mov eax, [eax+0x8] ; eax = 0x804c168 —▸ 0x804c178 —▸ ... mov [ebp-0x4], eax ; set new head of graph to 0x804c168 —▸ 0x804c178 —▸ ...

Then with the new head (start of the graph) set there are basically two interesting parts left.

The red box shows that whatever is the head of the graph in the current iteration is de-referenced at offset +0x4 and the value is XOR’d with the current value stored in start_val (I labeled it as “our_solution” in the screenshot). In the case of the loop breaking, either by fulfilling the loop condition or encountering a newline character the calculated value via multiple XOR operations is compared against a hard coded solution value:

uint32_t solution = 0x40475194;

So ultimately, we can narrow down the algorithm to something like this:

blue: start = 0x47bbfa96 goal = 0x40475194 loop_ctr = 0 while loop_ctr < 0x14 if L: head = Node->left else if R: head = Node->right else if

: goto check else: boom start = start ^ *head+0x4 loop_ctr += 1 check: return start == goal

We could manually calculate each step by following the head in GDB and XOR’ing it with the current value. As we do not know how to reach the expected value at the end brute-forcing this is a viable option. I did this with an IDAPython (for IDA7.5) script:

'''The number of possible combinations is 14 L or R’s because 1 byte is for ‘

’ and the final byte for the string terminator, therefore 2^14 which is 16384 possible combinations.''' from idc import get_wide_dword def evaluate(string): ea = 0x0804c160 x = 0x47bbfa96 for i in string: if i == 'L': ea = get_wide_dword(ea) if i == 'R': ea = get_wide_dword(ea+8) if i == '

': break x = get_wide_dword(ea+4) ^ x return x ans = 0x40475194 for i in range(2 ** 14): string = ''.join(map(lambda a: 'L' if int(a) else 'R', bin(i)[2:])) if evaluate(string) == ans: print(string)

This outputs a ton of combinations:

Python>from idc import get_wide_dword def evaluate(string): ea = 0x0804c160 x = 0x47bbfa96 for i in string: if i == 'L': ea = get_wide_dword(ea) if i == 'R': ea = get_wide_dword(ea+8) if i == '

': break x = get_wide_dword(ea+4) ^ x return x ans = 0x40475194 for i in range(2 ** 14): string = ''.join(map(lambda a: 'L' if int(a) else 'R', bin(i)[2:])) if evaluate(string) == ans: print(string) Python> LLRR LLRRRRRR LLRRLRLR LLRRRLLRLL LLRLLRRRLL LLRLLRLLRR LRLRRRLRLRLL LRLRRRLLRLRL LRLRLRLRRRLL LRLRLRLRLLRR LRLRLLRRRLRL LRLRLLRLRLRR LLRRRRRRRRRR LLRRRRRRLRLR LLRRRRLRRRLR LLRRRRLRLRRR LLRRRLRLRLRL LLRRRLLLLLLL LLRRLRRRRRLR LLRRLRRRLRRR LLRRLRLRRRRR LLRRLRLRLRLR LLRLRLRRRLRL LLRLRLRLRLRR LLRLLLLRRLLL LLRLLLLLLLLR LLLLRRLLRLLL LLLLRRLLLLLL LLLLLLRRRLLL LLLLLLRLLLLR LLLLLLLLRRLL LLLLLLLLLLRR LRLRRRLRLLLLLL LRLRRRLLLLLRLL LRLRLRLLLRRLLL LRLRLRLLLLLLLR LRLRLLLLRRLRLL LRLRLLLLLRLLLR LRLLLRRLRLRLLL LRLLLRRLRLLLLL LRLLLRRLLRLRLL LRLLLRRLLLLLRL LRLLLLRLRRRLLL LRLLLLRLRLLLLR LRLLLLRLLLRRLL LRLLLLRLLLLLRR LRLLLLLRRRLRLL LRLLLLLRLRLLLR LRLLLLLLLRRLRL LRLLLLLLLLRLRR LLRRRRRRRLLRLL LLRRRRRLLRRRLL LLRRRRRLLRLLRR LLRRRRLRLLLRLL LLRRRRLLLRRLLL LLRRRLRLLLLRLL LLRRRLLRRRRRLL LLRRRLLRRRLLRR LLRRRLLRRLRLLL LLRRRLLRLLRRRR LLRRLRRRLLLRLL LLRRLRRLLRRLLL LLRRLRLRRLLRLL LLRRLRLLLRRRLL LLRRLRLLLRLLRR LLRRLLLRRRRLLL LLRRLLLRRLRRLL LLRRLLLRRLLLRR LLRRLLLRLLRRLR LLRLRLLLRRLRLL LLRLRLLLLRLLLR LLRLLRRRRRRRLL LLRLLRRRRRLLRR LLRLLRRRRLRLLL LLRLLRRRLLRRRR LLRLLRRLRRRLLL LLRLLRRLRLRRLL LLRLLRRLRLLLRR LLRLLRRLLLRRLR LLRLLRLLRRRRRR LLRLLRLLRRLRLR LLLRLLLLRLLLRR LLLLRRLRLRLRLL LLLLRRLRLLLLRL LLLLLRLRRRLRLL LLLLLRLRLRLLLR LLLLLRLLLRRLRL LLLLLRLLLLRLRR

One possible solution to finish this phase is ‘LLRR’.

Analysis phase 4 - Red

If you made it up to here: Welcome to the last Phase! Don’t worry this one is way shorter. We will be done soon!

red_preflight calls rand() three times without seeding the random number generator, which according to the man 3 rand page results in the seed always defaulting to 1 and hence stable values across invocations. The resulting random values are used to fill an array r[3]. At the end here the array is being looped over with each of the array fields being accessed by [loop_ctr * 4 + 0x804c264] with 0 < loop_ctr <= 2 . Also we can see the array “field width” indicated by the offset 4 meaning that each value in the array is 4 bytes (== 32 bit integer size).

The main routine back in red is a simple algorithm that we can directly translate into a python script like this:

data_set = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" r = [0x6B8B4567, 0x327B23C6, 0x643C9869] flag = "" for i in range(19): flag += data_set[r[2] & 0x1f] r[2] = (r[2] >> 5) | (r[1] << 27) r[1] = (r[1] >> 5) | (r[0] << 27) result = r[0] >> 5 r[0] = r[0] >> 5 print(flag) KDG3DU32D38EVVXJM64

Final words

That’s the end. We managed to get through all 4 phases and enjoy this little reverseme style binary that teaches A LOT of fundamentals. If you’re reading this and are new to binary analysis and reversing make sure to understand each step!

Flags: