SharifCTF: dMd

This was the first reverse engineering challenge from SharifCTF. It was a pretty straightforward 64-bit ELF binary, and despite being decently easy, was still pretty fun and a great first-level RE challenge.

Analyzing the Execution

If we dump the beginning of main using objdump we can see it’s written in C++ and that it first prints out a message, takes our input, hahes it, and stores it in RAX.

$ objdump -d -M intel dMd | grep -A30 main.:

0000000000400e8d <main>:
  400e8d:   55                      push   rbp
  400e8e:   48 89 e5                mov    rbp,rsp
  400e91:   53                      push   rbx
  400e92:   48 83 ec 78             sub    rsp,0x78
  400e96:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
  400e9d:   00 00 
  400e9f:   48 89 45 e8             mov    QWORD PTR [rbp-0x18],rax
  400ea3:   31 c0                   xor    eax,eax
  400ea5:   be a8 28 40 00          mov    esi,0x4028a8
  400eaa:   bf 60 42 60 00          mov    edi,0x604260
  400eaf:   e8 0c fe ff ff          call   400cc0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  400eb4:   48 8d 45 b0             lea    rax,[rbp-0x50]
  400eb8:   48 89 c6                mov    rsi,rax
  400ebb:   bf 40 41 60 00          mov    edi,0x604140
  400ec0:   e8 3b fe ff ff          call   400d00 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_@plt>
  400ec5:   48 8d 45 8f             lea    rax,[rbp-0x71]
  400ec9:   48 89 c7                mov    rdi,rax
  400ecc:   e8 8f fe ff ff          call   400d60 <_ZNSaIcEC1Ev@plt>
  400ed1:   48 8d 55 8f             lea    rdx,[rbp-0x71]
  400ed5:   48 8d 4d b0             lea    rcx,[rbp-0x50]
  400ed9:   48 8d 45 90             lea    rax,[rbp-0x70]
  400edd:   48 89 ce                mov    rsi,rcx
  400ee0:   48 89 c7                mov    rdi,rax
  400ee3:   e8 08 fe ff ff          call   400cf0 <_ZNSsC1EPKcRKSaIcE@plt>
  400ee8:   48 8d 45 a0             lea    rax,[rbp-0x60]
  400eec:   48 8d 55 90             lea    rdx,[rbp-0x70]
  400ef0:   48 89 d6                mov    rsi,rdx
  400ef3:   48 89 c7                mov    rdi,rax
  400ef6:   e8 2b 16 00 00          call   402526 <_Z3md5Ss>
  400efb:   48 8d 45 a0             lea    rax,[rbp-0x60]

This gives us a pretty good idea of where this is heading, but let’s keep going just to be careful.

Looking ahead we can see a lot of comparisons happening between the bytes of our hashed input and some other hardcoded bytes:

  ...
  400f2f:   48 8b 45 a8             mov    rax,QWORD PTR [rbp-0x58]
  400f33:   0f b6 00                movzx  eax,BYTE PTR [rax]
  400f36:   3c 37                   cmp    al,0x37
  400f38:   0f 85 5d 03 00 00       jne    40129b <main+0x40e>
  400f3e:   48 8b 45 a8             mov    rax,QWORD PTR [rbp-0x58]
  400f42:   48 83 c0 01             add    rax,0x1
  400f46:   0f b6 00                movzx  eax,BYTE PTR [rax]
  400f49:   3c 38                   cmp    al,0x38
  400f4b:   0f 85 4a 03 00 00       jne    40129b <main+0x40e>
  400f51:   48 8b 45 a8             mov    rax,QWORD PTR [rbp-0x58]
  400f55:   48 83 c0 02             add    rax,0x2
  400f59:   0f b6 00                movzx  eax,BYTE PTR [rax]
  400f5c:   3c 30                   cmp    al,0x30
  400f5e:   0f 85 37 03 00 00       jne    40129b <main+0x40e>
  400f64:   48 8b 45 a8             mov    rax,QWORD PTR [rbp-0x58]
  400f68:   48 83 c0 03             add    rax,0x3
  400f6c:   0f b6 00                movzx  eax,BYTE PTR [rax]
  400f6f:   3c 34                   cmp    al,0x34
  400f71:   0f 85 24 03 00 00       jne    40129b <main+0x40e>
  400f77:   48 8b 45 a8             mov    rax,QWORD PTR [rbp-0x58]
  ...

Pulling out all of those bytes gives: 0x3738303433386435623665323964623038393862633466303232353933356330

Converting that back to ascii we get: 780438d5b6e29db0898bc4f0225935c0

That should be the md5 hash of our desired password. All we have to do is crack that hash and we sould have our flag. If we do a quick search online we find that what that hash is the md5x2 of the word grape. An md5x2 is the md5 operation applied twice:

With that in mind if we hash the word grape we should have the valid key, assuming no more checks were done.

Let’s Check:

$ echo $(echo -n "grape" | md5sum) | ./dMd

Enter the valid key!
The key is valid :)

It accepted our key! Our flag is:

b781cbb29054db12f88f08c6e161c199