08 Aug 2013 @ 8:52 PM 

Cross posted from my team site: http://seg.fault.in

I started looking at cone when I got frustrated with cnot. Initial analysis confirmed that it is a x64 binary, asks for a password when run, and prints whether the password was right or not.

Running through ltrace went fine and there was no trace for anti-dbg (like ptrace call from cnot).

1

Next logical step is to load into IDA and take a look at the disassembly.

No, not this madness again :/ (Both CNOT and CON are obfuscated x64 binaries).

Looking at the disassembly it looked similar to cnot, but expectedly lesser protection/obfuscation. From previous experience from cnot, I started to rename fgetc/fputc/calloc wrapper functions to get a better understanding. In the mean time, lets look at the ltrace logs.

2

There is one calloc just after the password prompt is printed and lot of callocs after the password is read. We can easily assume that lot of allocated memory will be used for password verification.

Now looking back at the disassembly and looking only at function calls we can get the flow of  fputc->calloc->fgetc function wrappers. Its time to start debugging as we have figured out where exactly our input is being read. I started debugging by putting breakpoint at the place where it checks for ‘\n’.

.text:0000000000404B0C         mov     qword ptr [rbp-58h], 0
.text:0000000000404B14         mov     dword ptr [rbp-58h], 0Ah
.text:0000000000404B1B         mov     r15d, [rbp-50h]
.text:0000000000404B1F         cmp     r15d, [rbp-58h]
.text:0000000000404B23         jz      short loc_404B36

Then traced down ignoring everything other than function calls (experience from cnot). I stepped into first function call and spent sometime trying to understand what it does, got frustrated and went back into disassembly to see whether the function calls return values is being used/checked at some place. As the check was there, I put BP on the next statement to see the return value. It turned to be 1, and the execution continues. The next function call is interesting one.

3Yes, we have our input in stack and its being referenced in couple of registers(I entered password as “abcd”). Now we can safely assume that call_404f89 does some operation on our password. Stepping into the function and tracing manually was a frustrating experience and decided to do what I previously did –  lets check the return value of the function. Return value was 0xa46c74bb and it is saved to stack. Tracing down the function, it ended up in doing a comparison with a hardcoded value.

4

Doing couple of more testing with different passwords verified that the password is split into 4bytes and passed to the function call_404f89, and the return values are compared with different hardcoded values. A total of 9 values are being compared – making our password 36 characters (including ‘\0’ – we will see how we got that later).

So essentially the algo should look like this:

char* szPassword = ReadPassword();
unsigned int hardcoded[] = {0x247BFB03, 0x8C33E4BB, 0xD49D047B,
                            0x7303FC73, 0x8C950303, 0x2304743B,
                            0x64647303, 0xA454949B, 0xD48CB5DB};
for(int i=0; i < 9; i++)
{
 retVals[i] = call_404f89(szPassword + (i * 4));
}
for(int i=0; i < 9; i++)
{
 if(retVals[i] != hardcoded[i])
 {
  //puts("Wrong!");
  //return -1;
 }
}
puts("Correct!");

As we have partially figured out the algo, the next big thing is to understand call_404f89. I tried to single step through the code but resulted in spending more time staring at the disassembly that doesn’t make much sense. Meantime I was also trying out the other challenges and partially solved compression (CRIME attack) and three_eyed_fish (didn’t complete both due to lack of time/resource :/). Revisiting the challenge again, I took a look at the ltrace log – well we havn’t looked at the calloc function calls yet. I put a BP on calloc wrapper function (0x400bc4). We should be worried about breaks only after call_404f89 starts. Once the call_404f89 started, I looked into the allocated memory to see if something interesting gets stored in those places. As the memory got allocated, I looked into the previous allocated space (when 3rd allocation happened, I looked into second allocated heap memory and so on). By the time the processing of call_404f89 got over, I had the full memory dump of all allocated memories. I ran couple of sample inputs and compared the output to make sure that I am not looking at heap headers rather than actual values. Clearly a pattern emerged as shown in the below pic.
5
While debugging at calloc return statement (jmp rdi), we can see that our password (4bytes) are used in somekind of operation and temporary results are stored in heap memory and eventually our calculated value (0xa46c74bb see above) is generated. While debugging after calloc and copy of 4bytes, I stumbled upon a piece of code which actually does an operation on our password values.
6It is a shift-arithmetic-right (sar val,0x15) which produced 0x323, which is present in the memory dump. Yiyeks! we have one operation figured. Looking at the disassembly near by, I figured some kind of pattern and found another operation by address 0x004019bf -> shl val, 0x0b. Now I restarted the debugging session with BP set on to 0x004019bf and 0x00401aea. BP on 0x004019bf hit first, and I can see the value (0x64636261 – “abcd”) is being left shifted with 0x0b resulting 0x1b130800 – which is again present in the memory dump. 2nd BP hit and we got 0x323. Now I looked at the memory dump to see if some info can be retrieved out of it. From the values in memory, I deduced the rest of the operation. Pure intuition and luck works sometime ;). Till now our algo is
value = 0x64636261;

t1 = value << 0x0b; //0x1b130800
t2 = value >> 0x15; //0x323

//next values in memory
//[0x1b130b23] - which is t1 ^ t2
//[0xdeadbeef] 
//[0xc5beb5cc] = 0x1b130b23 ^ 0xdeadbeef
//[0xdeadbeef] 
//[0xa46c74bb] = 0xc5beb5cc + 0xdeadbeef

We can rewrite the function as:
unsigned int call_404f89(char* password)
{
 unsigned int value = (unsigned int *)password;
 return ((((value << 0x0b)^(value >> 0x15))^ 0xdeadbeef)+ 0xdeadbeef);
}

Now we have the checking algo in  hand. Next is to write small script/program to do brute-forcing.
for (int i = rangeStart; i < rangeEnd; i++)
{
 for (int j = rangeStart; j < rangeEnd; j++)
 {
  for (int k = rangeStart; k < rangeEnd; k++)
  {
   for (int l = rangeStart; l < rangeEnd; l++)
   {
    val = (uint)(i << 0 | j << 8 | k << 16 | l << 24);
    t1 = val << 0x0b;
    t2 = val >> 0x15;
    t2 ^= t1;
    t2 ^= 0xdeadbeef;
    t2 += 0xdeadbeef;
    if (t2 == 0x247BFB03)  //change the hardcoded values to get next 4 chars.
    {
     MessageBox.Show("Got it: " + Convert.ToChar(i) +
                                  Convert.ToChar(j) + 
                                  Convert.ToChar(k) + 
                                  Convert.ToChar(l));
     goto done;
    }
   }
  }
 }
}

The last hadcoded value won’t be found through bruteforcing until you start with rangeStart=0; – the C string delimiter ‘\0’. Anyway last part can be easily guessed 🙂

Finally the password/flag is: pls_send_help_im_in_a_stack_machine

Posted By: Dan
Last Edit: 08 Aug 2013 @ 08:52 PM

EmailPermalink
Tags
Categories: CTF, Reverse Engineering


 

Responses to this post » (None)

 
Post a Comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


 Last 50 Posts
Change Theme...
  • Users » 1
  • Posts/Pages » 15
  • Comments » 39
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

About



    No Child Pages.