Renaud11232.github.io

View on GitHub

Crack Me 2

~$ cd ..

The first Reverse challenge (crack_me) was quite easy, but this one was a little bit more difficult as we could not easily get the extracted file. By loading the program in r2, we saw that the extracted binary was immediately unlinked:

|     ||    0x00000a9f      e85cfdffff     call sym.imp.open          ; int open(const char *path, int oflag);
|     ||    0x00000aa4      8945dc         mov dword [rbp - local_24h], eax
|     ||    0x00000aa7      837ddc00       cmp dword [rbp - local_24h], 0
|     ||,=< 0x00000aab      790a           jns 0xab7
|     |||   0x00000aad      b800000000     mov eax, 0
|    ,====< 0x00000ab2      e9a1000000     jmp 0xb58
|    ||||   ; JMP XREF from 0x00000aab (main)
|    |||`-> 0x00000ab7      488d45e9       lea rax, qword [rbp - local_17h]
|    |||    0x00000abb      4889c7         mov rdi, rax
|    |||    0x00000abe      e8cdfcffff     call sym.imp.unlink        ; int unlink(const char *path);
|    |||    0x00000ac3      85c0           test eax, eax
|    |||,=< 0x00000ac5      740a           je 0xad1
|    ||||   0x00000ac7      b800000000     mov eax, 0
|   ,=====< 0x00000acc      e987000000     jmp 0xb58

For the previous challenge, we noticed that the extracted file came from the .data section:

objdump -s -j .data crack_me

crack_me:     file format elf64-x86-64

Contents of section .data:
 201000 00000000 00000000 08102000 00000000  .......... .....
 201010 00000000 00000000 00000000 00000000  ................
 201020 7f454c46 02010100 00000000 00000000  .ELF............
 201030 03003e00 01000000 30050000 00000000  ..>.....0.......
 201040 40000000 00000000 28110000 00000000  @.......(.......
 201050 00000000 40003800 09004000 1b001a00  ....@.8...@.....
 201060 06000000 04000000 40000000 00000000  ........@.......
 201070 40000000 00000000 40000000 00000000  @.......@.......
 201080 f8010000 00000000 f8010000 00000000  ................
 201090 08000000 00000000 03000000 04000000  ................
 2010a0 38020000 00000000 38020000 00000000  8.......8.......
 2010b0 38020000 00000000 1c000000 00000000  8...............
 2010c0 1c000000 00000000 01000000 00000000  ................

For this 2nd part, we tried first to exploit a race condition to get the extracted file but it was unsuccessful. We guessed that the file would be extracted in a similar way, hence we ran the same command:

 objdump -s -j .data crack_me_hard

crack_me_hard:     file format elf64-x86-64

Contents of section .data:
 201000 00000000 00000000 08102000 00000000  .......... .....
 201010 00000000 00000000 00000000 00000000  ................
 201020 7bc4817a 703e4043 00000000 00000000  {..zp>@C........
 201030 00000000 00000000 00000000 00000000  ................
 201040 b389808a cecdcdcc cccccccc cccccccc  ................
 201050 cfccf2cc cdcccccc 4cc9cccc cccccccc  ........L.......
 201060 8ccccccc cccccccc e4ddcccc cccccccc  ................
 201070 cccccccc 8cccf4cc c5cc8ccc d7ccd6cc  ................
 201080 cacccccc c8cccccc 8ccccccc cccccccc  ................
 201090 8ccccccc cccccccc 8ccccccc cccccccc  ................
 2010a0 34cdcccc cccccccc 34cdcccc cccccccc  4.......4.......

We guessed that the file had been XOR’ed with the byte 0xCC. We then extracted the content of the .data section:

 objcopy -O binary -j .data crack_me_hard data_Section

and applied the XOR using python

f = open("data_Section", "rb")
data = f.read()
f.close()
f = open("extracted_elf", "wb")
f.write("".join(chr(ord(x)^0xCC) for x in data))
f.close()

We knew that some garbage were put at the beginning of the extracted file (final extracted binary here):

binwalk extracted_elf

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
64            0x40            ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)

Let’s open it in r2:

[0x00000580]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[ ] [*] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan))
[0x00000580]> afl
0x00000528    3 23           sub.__cxa_finalize_232_528
0x00000550    2 16   -> 32   sym.imp.puts
0x00000560    2 16   -> 48   sym.imp.strlen
0x00000570    1 16           sub.__cxa_finalize_248_570
0x00000580    1 43           entry0
0x000005b0    4 50   -> 40   sub.__cxa_finalize_216_5b0
0x0000068a    9 138          sub.strlen_68a
0x00000714    7 96           main
[0x00000580]> sf main
[0x00000714]> pdf
/ (fcn) main 96
|   main ();
|           ; var int local_10h @ rbp-0x10
|           ; var int local_4h @ rbp-0x4
|           ; DATA XREF from 0x0000059d (entry0)
|           0x00000714      55             push rbp
|           0x00000715      4889e5         mov rbp, rsp
|           0x00000718      4883ec10       sub rsp, 0x10
|           0x0000071c      897dfc         mov dword [rbp - local_4h], edi
|           0x0000071f      488975f0       mov qword [rbp - local_10h], rsi
|           0x00000723      837dfc01       cmp dword [rbp - local_4h], 1 ; [0x1:4]=0x2464c45
|       ,=< 0x00000727      7f13           jg 0x73c
|       |   0x00000729      488d3d210100.  lea rdi, qword str.Usage:_crack_me_hard__flag_ ; 0x851 ; str.Usage:_crack_me_hard__flag_ ; "Usage: crack_me_hard <flag>" @ 0x851
|       |   0x00000730      e81bfeffff     call sym.imp.puts          ; int puts(const char *s);
|       |   0x00000735      b801000000     mov eax, 1
|      ,==< 0x0000073a      eb36           jmp 0x772
|      ||   ; JMP XREF from 0x00000727 (main)
|      |`-> 0x0000073c      488b45f0       mov rax, qword [rbp - local_10h]
|      |    0x00000740      4883c008       add rax, 8
|      |    0x00000744      488b00         mov rax, qword [rax]
|      |    0x00000747      4889c7         mov rdi, rax
|      |    0x0000074a      e83bffffff     call sub.strlen_68a        ; size_t strlen(const char *s);
|      |    0x0000074f      84c0           test al, al
|      |,=< 0x00000751      740e           je 0x761
|      ||   0x00000753      488d3d130100.  lea rdi, qword str.You_got_it_ ; 0x86d ; str.You_got_it_ ; "You got it!" @ 0x86d
|      ||   0x0000075a      e8f1fdffff     call sym.imp.puts          ; int puts(const char *s);
|     ,===< 0x0000075f      eb0c           jmp 0x76d
|     |||   ; JMP XREF from 0x00000751 (main)
|     ||`-> 0x00000761      488d3d110100.  lea rdi, qword str.Try_again_:_ ; 0x879 ; str.Try_again_:_ ; "Try again :(" @ 0x879
|     ||    0x00000768      e8e3fdffff     call sym.imp.puts          ; int puts(const char *s);
|     ||    ; JMP XREF from 0x0000075f (main)
|     `---> 0x0000076d      b800000000     mov eax, 0
|      |    ; JMP XREF from 0x0000073a (main)
|      `--> 0x00000772      c9             leave
\           0x00000773      c3             ret

The only interesting routine is sub.strlen_68a:

[0x00000714]> sf sub.strlen_68a
[0x0000068a]> pdf
/ (fcn) sub.strlen_68a 138
|   sub.strlen_68a ();
|           ; var int local_18h @ rbp-0x18
|           ; var int local_8h @ rbp-0x8
|           ; CALL XREF from 0x0000074a (main)
|           0x0000068a      55             push rbp
|           0x0000068b      4889e5         mov rbp, rsp
|           0x0000068e      4883ec20       sub rsp, 0x20
|           0x00000692      48897de8       mov qword [rbp - local_18h], rdi
|           0x00000696      488b45e8       mov rax, qword [rbp - local_18h]
|           0x0000069a      4889c7         mov rdi, rax
|           0x0000069d      e8befeffff     call sym.imp.strlen        ; size_t strlen(const char *s);
|           0x000006a2      4883f820       cmp rax, 0x20               ; "@" 0x00000020
|       ,=< 0x000006a6      7407           je 0x6af
|       |   0x000006a8      b800000000     mov eax, 0
|      ,==< 0x000006ad      eb63           jmp 0x712
|      ||   ; JMP XREF from 0x000006a6 (sub.strlen_68a)
|      |`-> 0x000006af      48c745f80000.  mov qword [rbp - local_8h], 0
|      |,=< 0x000006b7      eb42           jmp 0x6fb
|      ||   ; JMP XREF from 0x0000070b (sub.strlen_68a)
|     .---> 0x000006b9      488b55e8       mov rdx, qword [rbp - local_18h]
|     |||   0x000006bd      488b45f8       mov rax, qword [rbp - local_8h]
|     |||   0x000006c1      4801d0         add rax, rdx                ; '('
|     |||   0x000006c4      0fb608         movzx ecx, byte [rax]
|     |||   0x000006c7      488d153a0100.  lea rdx, qword str.000000000000400A00A4BB000A00A0B0 ; 0x808 ; str.000000000000400A00A4BB000A00A0B0 ; "000000000000400A00A4BB000A00A0B0" @ 0x808
|     |||   0x000006ce      488b45f8       mov rax, qword [rbp - local_8h]
|     |||   0x000006d2      4801d0         add rax, rdx                ; '('
|     |||   0x000006d5      0fb600         movzx eax, byte [rax]
|     |||   0x000006d8      31c1           xor ecx, eax
|     |||   0x000006da      488d154f0100.  lea rdx, qword str.scbKqqqqqqqqZTouWQpZxxoWByoZqRcM ; 0x830 ; str.scbKqqqqqqqqZTouWQpZxxoWByoZqRcM ; "scbKqqqqqqqqZTouWQpZxxoWByoZqRcM" @ 0x830
|     |||   0x000006e1      488b45f8       mov rax, qword [rbp - local_8h]
|     |||   0x000006e5      4801d0         add rax, rdx                ; '('
|     |||   0x000006e8      0fb600         movzx eax, byte [rax]
|     |||   0x000006eb      38c1           cmp cl, al
|    ,====< 0x000006ed      7407           je 0x6f6
|    ||||   0x000006ef      b800000000     mov eax, 0
|   ,=====< 0x000006f4      eb1c           jmp 0x712
|   |||||   ; JMP XREF from 0x000006ed (sub.strlen_68a)
|   |`----> 0x000006f6      488345f801     add qword [rbp - local_8h], 1
|   | |||   ; JMP XREF from 0x000006b7 (sub.strlen_68a)
|   | ||`-> 0x000006fb      488b55e8       mov rdx, qword [rbp - local_18h]
|   | ||    0x000006ff      488b45f8       mov rax, qword [rbp - local_8h]
|   | ||    0x00000703      4801d0         add rax, rdx                ; '('
|   | ||    0x00000706      0fb600         movzx eax, byte [rax]
|   | ||    0x00000709      84c0           test al, al
|   | `===< 0x0000070b      75ac           jne 0x6b9
|   |  |    0x0000070d      b801000000     mov eax, 1
|   |  |    ; JMP XREF from 0x000006ad (sub.strlen_68a)
|   |  |    ; JMP XREF from 0x000006f4 (sub.strlen_68a)
|   `--`--> 0x00000712      c9             leave
\           0x00000713      c3             ret

The code here is quite simple as it’s a simple loop applying a XOR between each character of 2 constant strings, str.000000000000400A00A4BB000A00A0B0 and str.scbKqqqqqqqqZTouWQpZxxoWByoZqRcM. We decocded it using python and got our flag:

str1 = int("000000000000400A00A4BB000A00A0B0".encode("hex"), 16)
str2 = int("scbKqqqqqqqqZTouWQpZxxoWByoZqRcM".encode("hex"), 16)
hex(str1^str2)[2:-1].decode("hex")
  'CSR{AAAAAAAAnd_4ga1n::_gr8_j0b!}'