Sunday, 31 January 2016

CTF Writeup - HackIM 2016 - ZorroPub (RE 100)


  • Name - Zorro Pub
  • Category - Reverse Engineering
  • Points - 100
  • Description - N/A
  • Binary - Download here

Running the 64-bit ELF:

root@kali: ~/Desktop
root@kali:~/Desktop# ./zorro_bin Welcome to Pub Zorro!! Straight to the point. How many drinks you want?5 OK. I need details of all the drinks. Give me 5 drink ids:100 200 300 400 500 Looks like its a dangerous combination of drinks right there. Get Out, you will get yourself killed root@kali:~/Desktop#


The binary first accepts an integer, the number of drinks, and asks for a number of drink IDs equal to the first number. In the above example I've put '5' as the number of drinks and hence it expects 5 drink IDs. Let's load it in IDA.

Starting from the bottom, it's clear where we need to get to. Also, it shows that the flag is computed during the program's execution; "strings" will not do the job.


Let's look at the top part of the binary now:


The program scans for an integer and moves onto the next section if it is greater than 0, if not it prints "You are too drunk!! Get Out!!" and exits. The next part is the main logic of the program. I've colour-coded the boxes to make it easier (hopefully) to decipher what's happening.



The colour-scheme legend:
  • Blue - Start of logic; Scans for input; call this Algorithm A
  • Pink - Call this Algorithm B
  • White - Final decision box
  • Red - Error boxes; program exits straight after
  • Green - Destination

Right after we give the program our first input (# of drinks) we arrive at the blue box at the top and Algorithm A starts. This simply scans for a digit, makes sure it's between 0x10 and 0xFFFF and XORes it with the previous input which, in the first round is 0x00. The process is repeated a number of times equal to the first parameter. The result of Alogrithm A is the XOR of all our drink IDs. When done, the program jumps to the pink boxes, Algorithm B.

Algorithm B grabs the resultant, say X, from Algorithm A and does the following:
  • X AND (X-1) = new X
  • Increment Counter
  • If X is not 0, repeat
  • If X is 0, stop
When Alogirthm B finishes, we end up in the white box in the middle. If the Counter in Algorithm B is not equal to 0xA, it displays "Looks like its a dangerous combination", else it moves onto the green box, our goal for the time being. The hurdle here is to force Algorithm B to repeat itself exactly 0xA times. This happens only when the algorithm is fed a number who's binary representation contains exactly 10 1's.

In the green box, the result from Algorithm A is used as a seed (srand()). The logic that comes after this is not of interest to us as it does not depend on our input. It's there to convolute the flag. So we know the following about the value(s) that can make it successfully to the green box function:
  • It doesn't matter if we input X as the drink ID or X1 and X2, where X1 ^ X2 = X
  • The value(s) should be between 0x10 and 0xFFFF
  • The value(s) must contain 0xA number of 1's when represented in binary format
I've chosen to input a single number as it's easier. Since the number can be between 16 and 65,535 I've used a bash 1-liner to brute-force the answer. As the range is very small I didn't bother limiting the input to only those numbers which contain 10 1's. I personally felt that this section of the RE challenge was not well made. Most of the interesting complications of the binary's workings were invalidated by the small search-space and not even required to obtain the flag.


root@kali: ~/Desktop
root@kali:~/Desktop# for i in `seq 1 65535`; do echo $i >> answers.txt; ./zorro_bin <<< $'1\n'$i$'\n' | grep -i 'choose right mix' >> answers.txt; done


Few minutes later we end up with the flag in answers.txt : You choose right mix and here is your reward: The flag is nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}

1 comment: