Contents

Dakotacon 2015 RE Challenge C2 Writeup

Contents

The Dakotacon C2 challenge was moderately difficult in that it actually required you to do a little programming work – most of the other C-based challenges in this CTF allowed you to set a breakpoint at a smart place (e.g. right before strcmp()), and view the key in-memory.

Instead of comparing your input with the actual key, this binary encodes your input and compares it with an encoded version of the key.

Here is the encoding algorithm, in IDA-assembly, with my psuedocode added as comment on the right:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
								 // i = 0;
.text:0123114D mov     ecx, 12   // r = 12;
.text:01231152
.text:01231152 loc_1231152:      // loop:                        ; CODE XREF: _main+DEj
.text:01231152 mov     dx, [eax] // 	tmp = input[i];
.text:01231155 rol     dx, cl    // 	tmp = tmp << r;
.text:01231158 mov     [eax], dx // 	input[i] = tmp;
.text:0123115B add     eax, 2	 // 	i += 2;
.text:0123115E mov     dx, [eax] // 	tmp = input[i];
.text:01231161 rol     dx, cl    // 	tmp = tmp << r;
.text:01231164 mov     [eax], dx // 	input[i] = tmp;
.text:01231167 add     eax, 2	 // 	i += 2
.text:0123116A dec     ecx		 // 	r--;
.text:0123116B cmp     ecx, 0    // while (r < 0): loop
.text:0123116E jge     short loc_1231152

So now we need to figure out the algorithmic inverse. It’s not difficult – all we need to do is change the direction of the rotates from left to right. Let’s do it in psuedocode real quick:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
i = 0;
r = 12;

loop:
  tmp = input[i];
  tmp = tmp >> r; // Note the rotate to the right.
  input[i] = tmp;
  i += 2;
  
  tmp = input[i];
  tmp = tmp >> r; // Note the rotate to the right.
  input[i] = tmp;
  i += 2;
  
  r--
while (r < 0): loop

Let’s turn that psuedocode into some actual C code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
for (r = 12; r > 0; r--)
{
  memcpy(&tmp, &buf[i], 2);
  printf("%x", tmp);
  
  tmp = rotate_right(tmp, r);

  memcpy(&buf[i], &tmp, 2);

  i += 2;

  memcpy(&tmp, &buf[i], 2);

  printf("%x\n", tmp);

  tmp = rotate_right(tmp, r);

  memcpy(&buf[i], &tmp, 2);

  i += 2;
}

Now all we need is the encoded key from the program, so we can run it through that decode loop. One way to get that encoded key is simply to set a breakpoint on the strncmp() at address 0x01231178, which is the check for the correct key. The first argument pushed onto the stack is a pointer to the encoded key – you can verify this by looking a few dozen instructions earlier, where you’ll see the arguments being set up/pushed onto the stack. If you’re following along in IDA, you should see something like this:

/images/2015/04/C3_1.png

Note the highlighted bytes in the lower-left-hand panel. That’s the encoded key, and what we want… those bytes were pushed onto the stack earlier in the program.

If we copy/paste those into our program, and we can take a shot at decoding them!

Here’s the complete decoder I wrote to solve this challenge.