Writeup: TokyoWesterns 2019 - Easy Crack Me
Information
- category : reverse
- points : 88
Description
Cracking is easy for you.
File : easy_crack_me
Writeup
To analyze the binary I used both ghidra and cutter (radare2’s GUI).
In the binary there is only one interesting function and it’s the main. The graph overview of the main is the following :
Just seeing the graph I could tell that this crackme wasn’t easy as the title said.
The decompiler of the main function generated by ghidra is the following :
1 | undefined8 main(int param_1,long param_2) |
1st constraint
Our goal is to create a flag that passed to the program prints “correct”.
From now on I will rename various variable to make easier the understanding.
Let’s check what are the initial conditions to bypass.
1 | if (argc == 2) { |
We need to :
- pass to the program one argument –>
flag
- the length of the flag must be
0x27 = 39
- The first 6 byte of the flag are
"TWCTF{"
- The last byte of the flag must be
"}"
2nd constraint
From now on all operations will have a + 6
to remove the first 6 bytes "TWCTF{"
or the first 6 bytes are not considered, so I’ll set the flag to be 39 - 6 ("TWCTF{"
) - 1 ("}"
) = 32 bytes (Only the characters that we need to find).
1 | array_e8 = 0; |
What this nested while does in pseucode:
1 | array_freq = [16]; // array_e8 above |
So basically it constructs an array of frequencies of each character presented in string0
+ string1
.
Let’s see what’s inside 0x400f00. I used cutter in this case because with ghidra I had problem converting these values in little endian automatically.
1 | [0x00000003, 0x00000002, 0x00000002, 0x00000000, 0x00000003, 0x00000002, 0x00000001, 0x00000003, 0x00000003, 0x00000001, 0x00000001, 0x00000003, 0x00000001, 0x00000002, 0x00000002, 0x00000003] |
So basically there are three 0
, two 1
,…, two e
and three f
. There are other constraints to check to make sure that the flag is correct. To solve each of this constraints I used z3.
Sets the frequencies count in z3py was at first a pain. Luckily I found this code and I was able to make an “efficient and readable” code to impose the characters frequencies.
1 | #!/usr/bin/env python3 |
Ok so far everything is ok..
3rd and 4th constraint
1 | arrx = 0; |
Let’s rewrite the first nested while in pseudocode:
1 | i = 0; |
Basically it divides the flag in blocks of 4, and then it converts every characters of the block to int and sum/xor them. Then it checks if the sum and xor are equal to the values stored in 0x00400f40
and 0x00400f60
.
Content of 0x00400f40
and 0x00400f60
:
1 | [0x0000015e, 0x000000da, 0x0000012f, 0x00000131, 0x00000100, 0x00000131, 0x000000fb, 0x00000102] |
Second nested while in pseudocode:
1 | i = 0; |
So it sums:
1 | sum[0] = int(flag[0]) + int(flag[8]) + int(flag[16]) + int(flag[24]) |
The same for the xor.
Content of 0x00400fa0
and 0x00400f80
:
1 | [0x00000129, 0x00000103, 0x0000012b, 0x00000131, 0x00000135, 0x0000010b, 0x000000ff, 0x000000ff] |
z3 code :
1 | sum_1 = [0x0000015e, 0x000000da, 0x0000012f, 0x00000131, 0x00000100, 0x00000131, 0x000000fb, 0x00000102] |
5th constraint
1 | i3 = 0; |
Pseudocode:
1 | while(i < 32) |
So in a specific index there must be a number (0 --> 9)
or a char (a --> f)
.
number = 0xff, char = 0x80
0x00400fc0
content:
1 | [0x00000080, 0x00000080, 0x000000ff, 0x00000080, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x00000080, 0x000000ff, 0x000000ff, 0x00000080, 0x00000080, 0x000000ff, 0x000000ff, 0x00000080, 0x000000ff, 0x000000ff, 0x00000080, 0x000000ff, 0x00000080, 0x00000080, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x00000080, 0x000000ff, 0x000000ff, 0x000000ff, 0x00000080, 0x000000ff] |
z3 code:
1 | n_or_c = [0x00000080, 0x00000080, 0x000000ff, 0x00000080, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, |
6th constraint
1 | if ((((flag[0x25] != '5') || (flag[7] != 'f')) || (flag[0xb] != '8')) || |
Ok no need for pseudocode because is self explanatory.
z3 code:
1 | s.add(flag[1] == ord('f'),flag[5] == ord('8'), flag[6] == ord('7'), |
Ok we have finished to check the bonds of the crackme. Let’s write a final exploit
Exploit
1 | #!/usr/bin/env python3 |
Flag
TWCTF{df2b4877e71bd91c02f8ef6004b584a5}