Tags: re
Rating:
## crackme03 (RE, 150pts)
#### Challenge Description
tik-tok tik-tok can you defuse the bomb?
author: codacker
```
nc 104.154.106.182 7777
```
#### Overview
This challenge has a remote host unlike the first two, and the local binary doesn't contain the flag. After passing input that satisfies all the conditions, a flag file is read and printed out to you. The premise is fun - you must diffuse a bomb by passing 5 input checks, each progressively a little more difficult than the last. These checks are all stored in a table, and are as follows:
```
#1: sub_1286
#2: sub_12BD
#3: sub_12E6
#4: sub_1392
#5: sub_1410
```
We don't want to reach the "boom" function, which is `sub_1258`.
#### First check
The first check is `sub_1286` and just compares the first part of the string with a literal `"CRACKME02"`, so passing this check is easy.
```assembly
lea edx, (aCrackme02 - 4000h)[eax] ; "CRACKME02"
push edx ; s2
push [ebp+s1] ; s1
mov ebx, eax
call _strcmp
add esp, 10h
test eax, eax
jz short loc_12B7
call sub_1258
```
Input so far:
```
CRACKME02\n
```
#### Second check
The second check is `sub_12BD` and is also fairly easy, we just need to pass an integer of `0xDEADBEEF`.
```assembly
mov [ebp+var_C], 0DEADBEEFh
mov eax, [ebp+arg_0]
mov eax, ds:(off_4000 - 4000h)[eax]
cmp [ebp+var_C], eax
jz short loc_12E3
call sub_1258
```
Input so far:
```
CRACKME02\n\xEF\xBE\xAD\xDE\n
```
#### Third check
If we decompile the third check, which is `sub_12E6`, we'll see the following:
```c
int result; // eax
unsigned int v2; // et1
size_t i; // [esp+10h] [ebp-28h]
char s[4]; // [esp+17h] [ebp-21h]
unsigned int v5; // [esp+2Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
strcpy(s, "ZXytUb9fl78evgJy3KJN");
for ( i = 0; strlen(s) > i; ++i )
{
if ( s[i] != *(_BYTE *)(i + a1) )
sub_1258();
}
v2 = __readgsdword(0x14u);
result = v2 ^ v5;
if ( v2 != v5 )
sub_1670();
return result;
```
Essentially, we just need to make sure we pass `"ZXytUb9fl78evgJy3KJN"`. The XOR operation is for the stack cookie and is irrelevant to the challenge.
Input so far:
```
CRACKME02\n\xEF\xBE\xAD\xDE\nZXytUb9fl78evgJy3KJN\n
```
#### Fourth check
If we decompile `sub_1392`, which is the fourth check, we get:
```c
int v1; // ST1C_4
if ( strlen(s) > 3 )
sub_1258();
v1 = atoi(s);
if ( v1 * v1 * v1 + 2 * (2 * v1 * v1 - v1) - 3 )
sub_1258();
return puts("SUBSCRIBE TO PEWDIEPIE");
```
This means we need a string that's both longer than 3 characters and doesn't make that mathematical statement true. Let's try something simple like `1`.
```
= v1 * v1 * v1 + 2 * (2 * v1 * v1 - v1) - 3
= 1 * 1 * 1 + 2 * (2 * 1 * 1 - 1) - 3
= 3 + 2 * (1) - 3
= 3 + 2 - 3
= 2
```
This statement will be evaluated as false, so it'll pass.
Input so far:
```
CRACKME02\n\xEF\xBE\xAD\xDE\nZXytUb9fl78evgJy3KJN\n1\n
```
#### Fifth check
The fifth check is quite interesting, and is located in `sub_1410`. Here's the code:
```c
strncpy(&dest, a1, 0xAu);
puts("Validating Input 4");
if ( dest[0x0] + dest[0x8] != 0xD5 )
sub_1258();
if ( dest[0x1] + dest[0x7] != 0xCE )
sub_1258();
if ( dest[0x2] + dest[0x6] != 0xE7 )
sub_1258();
if ( dest[0x3] + dest[0x5] != 0xC9 )
sub_1258();
if ( dest[0x4] == 0x69 )
puts("you earned it");
```
Although it allows 0xA bytes in the strncpy, we only need to care about 8 of them. Given this code, our string needs to pass the following conditions:
```
dest[0] + dest[8] must add up to 0xD5
dest[1] + dest[7] must add up to 0xCE
dest[2] + dest[6] must add up to 0xE7
dest[3] + dest[5] must add up to 0xC9
dest[4] must be 0x69
```
What makes this challenge interesting though will require us to look at a bit of the disassembly. Let's look at the disassembly for the check against `dest[2]` and `dest[6]`, the others are similar but with different local variable references and compare intermediates.
```assembly
movzx eax, [ebp+var_15]
movsx edx, al
movzx eax, [ebp+var_F]
movsx eax, al
add eax, edx
cmp eax, 0CEh
```
Notice that it first moves with a zero extension, then moves with a sign extension. This means we must make sure every byte we use in this string to make these additions match up must be 0x7F or below. If they're 0x80 or higher in value, they'll move 0xFF's into the upper 3 bytes and the checks will fail. Below is the string I came up with:
```
dest[0] = 0x56, dest[8] = 0x7F. 0x7F + 0x56 = 0xD5
dest[1] = 0x67, dest[7] = 0x67. 0x67 + 0x67 = 0xCE
dest[2] = 0x73, dest[6] = 0x74. 0x73 + 0x74 = 0xE7
dest[3] = 0x64, dest[5] = 0x65. 0x64 + 0x65 = 0xC9
dest[4] = 0x69
Which gives us: \x56\x67\x73\x64\x69\x65\x74\x67\x7F
```
#### Flag
Finally, when we put this all together, we get:
```
CRACKME02\n\xEF\xBE\xAD\xDE\nZXytUb9fl78evgJy3KJN\n1\n\x56\x67\x73\x64\x69\x65\x74\x67\x7F
```
If we use python to send this to the given IP and port, we'll get the flag.
```
$ python -c 'print "CRACKME02\n" + "\xef\xbe\xad\xde\n" + "ZXytUb9fl78evgJy3KJN\n" + "1\n" + "\x56\x67\x73\x64\x69\x65\x74\x67\x7F"' | nc 104.154.106.182 7777
Hi!, i am a BOMB!
I will go boom if you don't give me right inputs
Enter input #0: Enter input #1: Enter input #2: Enter input #3: SUBSCRIBE TO PEWDIEPIE
Enter input #4: Validating Input 4
you earned it
encryptCTF{B0mB_D!ffu53d}
```
The flag:
```
encryptCTF{B0mB_D!ffu53d}
```