Codehead's Corner
Random ramblings on hacking, coding, fighting with infrastructure and general tech
SharifCTF 2016 – dMd – Reverse Engineering – 50 points
Posted: 7 Feb 2016 at 22:58 by Codehead

I hadn’t played SharifCTF before, but these guys put on a good competition.

Unfortunately I had other commitments, but I managed to spend a little bit of time looking at some of the challenges.

dMd was a reverse engineering challenge worth 50 points. A binary was provided with the description:

Flag is : The valid input.

file told me that the binary was an x86-64 ELF, so I threw it at my Fedora install and pulled up the disassembly in IDA.

Running the binary resulted in a prompt for a valid key. A few wild guesses resulted in ‘Invalid Key’ responses, so it was time to look under the bonnet.

IDA handled the binary with no issues. Looking at main() we can see the input being handled by std::iostream routines. The user’s input gets MD5 hashed at 0x0000000000400EF6 and then converted to a CString.

Next, there’s a huge run of CMP checks against constant values. These checks are offset from the base of the CString so we’re basically doing a strcmp() without actually calling the function, I guess this is an attempt to hide the purpose of the code.

.text:0000000000400EF6 call _Z3md5Ss ; md5(std::string)
.text:0000000000400EFB lea rax, [rbp+MD5_Result?]
.text:0000000000400EFF mov rdi, rax ; this
.text:0000000000400F02 call __ZNKSs5c_strEv ; std::string::c_str(void)
.text:0000000000400F07 mov [rbp+C_str_MD5_Result?], rax
.text:0000000000400F0B lea rax, [rbp+MD5_Result?]
.text:0000000000400F0F mov rdi, rax ; this
.text:0000000000400F12 call __ZNSsD1Ev ; std::string::~string()
.text:0000000000400F17 lea rax, [rbp+user_input?]
.text:0000000000400F1B mov rdi, rax ; this
.text:0000000000400F1E call __ZNSsD1Ev ; std::string::~string()
.text:0000000000400F23 lea rax, [rbp+var_71]
.text:0000000000400F27 mov rdi, rax
.text:0000000000400F2A call __ZNSaIcED1Ev ; std::allocator::~allocator()
.text:0000000000400F2F mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F33 movzx eax, byte ptr [rax]
.text:0000000000400F36 cmp al, 37h
.text:0000000000400F38 jnz loc_40129B
.text:0000000000400F3E mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F42 add rax, 1
.text:0000000000400F46 movzx eax, byte ptr [rax]
.text:0000000000400F49 cmp al, 38h
.text:0000000000400F4B jnz loc_40129B
.text:0000000000400F51 mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F55 add rax, 2
.text:0000000000400F59 movzx eax, byte ptr [rax]
.text:0000000000400F5C cmp al, 30h
.text:0000000000400F5E jnz loc_40129B
.text:0000000000400F64 mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F68 add rax, 3
.text:0000000000400F6C movzx eax, byte ptr [rax]
.text:0000000000400F6F cmp al, 34h
.text:0000000000400F71 jnz loc_40129B
.text:0000000000400F77 mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F7B add rax, 4
.text:0000000000400F7F movzx eax, byte ptr [rax]
.text:0000000000400F82 cmp al, 33h
.text:0000000000400F84 jnz loc_40129B
.text:0000000000400F8A mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400F8E add rax, 5
.text:0000000000400F92 movzx eax, byte ptr [rax]
.text:0000000000400F95 cmp al, 38h
.text:0000000000400F97 jnz loc_40129B
.text:0000000000400F9D mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400FA1 add rax, 6
.text:0000000000400FA5 movzx eax, byte ptr [rax]
.text:0000000000400FA8 cmp al, 64h
.text:0000000000400FAA jnz loc_40129B
.text:0000000000400FB0 mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400FB4 add rax, 7
.text:0000000000400FB8 movzx eax, byte ptr [rax]
.text:0000000000400FBB cmp al, 35h
.text:0000000000400FBD jnz loc_40129B
.text:0000000000400FC3 mov rax, [rbp+C_str_MD5_Result?]
.text:0000000000400FC7 add rax, 8
.text:0000000000400FCB movzx eax, byte ptr [rax]
.text:0000000000400FCE cmp al, 62h
.text:0000000000400FD0 jnz loc_40129B

We can extract those constants from the CMP AL calls with a little bit of bash:

objdump -d dMd | grep cmp | grep %al | awk '{print $3}' | xxd -r -p

That gives us the folowing string:

780438d5b6e29db0898bc4f0225935c0

That looks like a hash, so let’s throw it at one of the many online hash databases.

Hashkiller found a match within seconds: md5(md5(‘grape’)) that was a bit confusing, but md5(‘grape’) resolves to b781cbb29054db12f88f08c6e161c199, and entering that string into the binary results in the 780438d5b6e29db0898bc4f0225935c0 hash, which is validated by the checks and is the final flag for the challenge.

Categories: CTF Hacking



Site powered by Hugo.
Polymer theme by pdevty, tweaked by Codehead