Report for Practical Binary Analysis CTF
The game now is given.
However, we have some problems at first. The virtual machine given on the website is really old. It even couldn’t support the newest visual studio code ssh-server. So there is a method to have a nice editing experience to use command:
1 | ssh -p 2222 binary@127.0.0.1 |
After finish ssh connection, I really recommend everyone who want to play this game to use hexedit but not vim. Vim really takes me big trouble in the game.
And now, we could begin the game.
Level 2
First of all, there is a key given 84b34c124b2ba5ca224af8e33b077e9e.
1 | binary@binary-VirtualBox:~/code/chapter5$ ./oracle 84b34c124b2ba5ca224af8e33b077e9e |
It gives us a hint, it’s important.
1
2binary@binary-VirtualBox:~/code/chapter5$ ./oracle 84b34c124b2ba5ca224af8e33b077e9e -h
Combine the parts
It seems we have no point to solve the problem. So we can first justify what it is.
1 | binary@binary-VirtualBox:~/code/chapter5$ file ./lvl2 |
OK, it’s a executable. We can run a few times to observe it.
1 | binary@binary-VirtualBox:~/code/chapter5$ ./lvl2 |
It puts some words repeatedly. We guess the key is an arrangement of these words.
1 | binary@binary-VirtualBox:~/code/chapter5$ ltrace ./lvl2 |
In ltrace, we can see that the program seems like to get a rand number and get a words to puts. And when we use objdump, it seems we are close to the answer.
1 | 0000000000400500 <.text>: |
We can see from 0x400517 to 0x400522, eax is expanded in edx. And then edx is shifted right by 28 bits. Then add edx and eax and only the last four digits are retained. The whole progress is to take the remainder of eax divided by 16. And in 0x400524, get a words from 0x601060 + 8 * rax to puts.
So we could just use gdb to get the key.
1 | (gdb) b *0x400524 |
Now we get the key 034fc4f6a536f2bf74f8d6d3816cdf88.
1 | binary@binary-VirtualBox:~/code/chapter5$ ./oracle 034fc4f6a536f2bf74f8d6d3816cdf88 |
Level 3
1 | ``` |
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 034fc4f6a536f2bf74f8d6d3816cdf88 -h
Fix four broken things
1 | The hint of level 3 is clear. Let's first see what lvl3 is. |
binary@binary-VirtualBox:~/code/chapter5$ file lvl3
lvl3: ERROR: ELF 64-bit LSB executable, Motorola Coldfire, version 1 (Novell Modesto) error reading (Invalid argument)
1 | It is obvious something wrong. First check its elf headers. |
binary@binary-VirtualBox:~/code/chapter5$ readelf -h lvl3
ELF Header:
Magic: 7f 45 4c 46 02 01 01 0b 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: Novell - Modesto
ABI Version: 0
Type: EXEC (Executable file)
Machine: Motorola Coldfire
Version: 0x1
Entry point address: 0x4005d0
Start of program headers: 4022250974 (bytes into file)
Start of section headers: 4480 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
readelf: Error: Reading 0x1f8 bytes extends past end of file for program headers
1 | First of all, the OS/ABI is obviously wrong, default linux should be Unix/System V. So "0b" should be corrected to "00". And also, the Machine is ridiculous. It should be X86-64, so we need to correct "34" to "3E". |
[14] .text NOBITS 0000000000400550 00000550
00000000000001f2 0000000000000000 AX 0 0 16
1 | The problem is showed. ``.text`` is NOBITS. It should be PROGBITS. So we correct "8d00 0000 0800 0000" to "8d00 0000 0100 0000". And the position is 4480 + 64 * 13 = 5312. The hex mode is 0x14c0, so find "8d00 0000 0800 0000" around it and correct it. Then we could get the key: |
binary@binary-VirtualBox:/code/chapter5$ ./lvl3/code/chapter5$ ./oracle 3a5c381e40d2fffd95ba4452a0fb4a40
3a5c381e40d2fffd95ba4452a0fb4a40 ./lvl3
binary@binary-VirtualBox:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 3 completed, unlocked lvl4 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint
1 | By the way, **Don't use vim when you want to change a binary file**. Otherwise, it will take you 3 hours to find what mistakes you have made, and finally you'll find that it's vim who change your code without your permission. |
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 3a5c381e40d2fffd95ba4452a0fb4a40 -h
Watch closely while I run
1 | It reminds us we should observe its running time. |
binary@binary-VirtualBox:/code/chapter5$ ./lvl4/code/chapter5$
binary@binary-VirtualBox:
1 | We found nothing in it. So maybe we could use ltrace to see what libc function it called. |
binary@binary-VirtualBox:~/code/chapter5$ ltrace ./lvl4
__libc_start_main(0x4004a0, 1, 0x7ffceec34fd8, 0x400650 <unfinished …>
setenv(“FLAG”, “656cf8aecb76113a4dece1688c61d0e7”…, 1) = 0
+++ exited (status 0) +++
1 | Lucky! The answer is just in it. |
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 656cf8aecb76113a4dece1688c61d0e7
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 4 completed, unlocked lvl5 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint
1 |
|
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 656cf8aecb76113a4dece1688c61d0e7 -h
Secrets hidden in code unused
The method of redirection is the key
Static rather than dynamically
1 | OK, the hint reminds us that we should find the code never used and do a redirection to get the key. So we can use objdump first. |
0000000000400500 <.text>:
400500: 48 83 ec 08 sub $0x8,%rsp
400504: bf 97 07 40 00 mov $0x400797,%edi
400509: e8 a2 ff ff ff callq 4004b0 <puts@plt>
40050e: b8 01 00 00 00 mov $0x1,%eax
400513: 48 83 c4 08 add $0x8,%rsp
400517: c3 retq
400518: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40051f: 00
400520: 31 ed xor %ebp,%ebp
400522: 49 89 d1 mov %rdx,%r9
400525: 5e pop %rsi
400526: 48 89 e2 mov %rsp,%rdx
400529: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40052d: 50 push %rax
40052e: 54 push %rsp
40052f: 49 c7 c0 60 07 40 00 mov $0x400760,%r8
400536: 48 c7 c1 f0 06 40 00 mov $0x4006f0,%rcx
40053d: 48 c7 c7 00 05 40 00 mov $0x400500,%rdi
400544: e8 87 ff ff ff callq 4004d0 <__libc_start_main@plt>
400549: f4 hlt
40054a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
400550: b8 4f 10 60 00 mov $0x60104f,%eax
400555: 55 push %rbp
400556: 48 2d 48 10 60 00 sub $0x601048,%rax
40055c: 48 83 f8 0e cmp $0xe,%rax
400560: 48 89 e5 mov %rsp,%rbp
400563: 76 1b jbe 400580 <__printf_chk@plt+0xa0>
400565: b8 00 00 00 00 mov $0x0,%eax
40056a: 48 85 c0 test %rax,%rax
40056d: 74 11 je 400580 <__printf_chk@plt+0xa0>
40056f: 5d pop %rbp
400570: bf 48 10 60 00 mov $0x601048,%edi
400575: ff e0 jmpq *%rax
400577: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40057e: 00 00
400580: 5d pop %rbp
400581: c3 retq
400582: 0f 1f 40 00 nopl 0x0(%rax)
400586: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40058d: 00 00 00
400590: be 48 10 60 00 mov $0x601048,%esi
400595: 55 push %rbp
400596: 48 81 ee 48 10 60 00 sub $0x601048,%rsi
40059d: 48 c1 fe 03 sar $0x3,%rsi
4005a1: 48 89 e5 mov %rsp,%rbp
4005a4: 48 89 f0 mov %rsi,%rax
4005a7: 48 c1 e8 3f shr $0x3f,%rax
4005ab: 48 01 c6 add %rax,%rsi
4005ae: 48 d1 fe sar %rsi
4005b1: 74 15 je 4005c8 <__printf_chk@plt+0xe8>
4005b3: b8 00 00 00 00 mov $0x0,%eax
4005b8: 48 85 c0 test %rax,%rax
4005bb: 74 0b je 4005c8 <__printf_chk@plt+0xe8>
4005bd: 5d pop %rbp
4005be: bf 48 10 60 00 mov $0x601048,%edi
4005c3: ff e0 jmpq *%rax
4005c5: 0f 1f 00 nopl (%rax)
4005c8: 5d pop %rbp
4005c9: c3 retq
4005ca: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
4005d0: 80 3d 71 0a 20 00 00 cmpb $0x0,0x200a71(%rip) # 601048 <__printf_chk@plt+0x200b68>
4005d7: 75 11 jne 4005ea <__printf_chk@plt+0x10a>
4005d9: 55 push %rbp
4005da: 48 89 e5 mov %rsp,%rbp
4005dd: e8 6e ff ff ff callq 400550 <__printf_chk@plt+0x70>
4005e2: 5d pop %rbp
4005e3: c6 05 5e 0a 20 00 01 movb $0x1,0x200a5e(%rip) # 601048 <__printf_chk@plt+0x200b68>
4005ea: f3 c3 repz retq
4005ec: 0f 1f 40 00 nopl 0x0(%rax)
4005f0: bf 20 0e 60 00 mov $0x600e20,%edi
4005f5: 48 83 3f 00 cmpq $0x0,(%rdi)
4005f9: 75 05 jne 400600 <__printf_chk@plt+0x120>
4005fb: eb 93 jmp 400590 <__printf_chk@plt+0xb0>
4005fd: 0f 1f 00 nopl (%rax)
400600: b8 00 00 00 00 mov $0x0,%eax
400605: 48 85 c0 test %rax,%rax
400608: 74 f1 je 4005fb <__printf_chk@plt+0x11b>
40060a: 55 push %rbp
40060b: 48 89 e5 mov %rsp,%rbp
40060e: ff d0 callq *%rax
400610: 5d pop %rbp
400611: e9 7a ff ff ff jmpq 400590 <__printf_chk@plt+0xb0>
400616: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40061d: 00 00 00
400620: 53 push %rbx
400621: be 74 07 40 00 mov $0x400774,%esi
400626: bf 01 00 00 00 mov $0x1,%edi
40062b: 48 83 ec 30 sub $0x30,%rsp
40062f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400636: 00 00
400638: 48 89 44 24 28 mov %rax,0x28(%rsp)
40063d: 31 c0 xor %eax,%eax
40063f: 48 b8 10 60 21 33 15 movabs $0x6223331533216010,%rax
400646: 33 23 62
400649: c6 44 24 20 00 movb $0x0,0x20(%rsp)
40064e: 48 89 04 24 mov %rax,(%rsp)
400652: 48 b8 45 65 76 34 41 movabs $0x6675364134766545,%rax
400659: 36 75 66
40065c: 48 89 44 24 08 mov %rax,0x8(%rsp)
400661: 48 b8 17 67 75 64 10 movabs $0x6570331064756717,%rax
400668: 33 70 65
40066b: 48 89 44 24 10 mov %rax,0x10(%rsp)
400670: 48 b8 18 35 76 62 11 movabs $0x6671671162763518,%rax
400677: 67 71 66
40067a: 48 89 44 24 18 mov %rax,0x18(%rsp)
40067f: 8b 1c 25 40 05 40 00 mov 0x400540,%ebx
400686: 31 c0 xor %eax,%eax
400688: 89 da mov %ebx,%edx
40068a: e8 51 fe ff ff callq 4004e0 <__printf_chk@plt>
40068f: 48 8d 54 24 20 lea 0x20(%rsp),%rdx
400694: 48 89 e0 mov %rsp,%rax
400697: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40069e: 00 00
4006a0: 31 18 xor %ebx,(%rax)
4006a2: 48 83 c0 04 add $0x4,%rax
4006a6: 48 39 d0 cmp %rdx,%rax
4006a9: 75 f5 jne 4006a0 <__printf_chk@plt+0x1c0>
4006ab: 31 c0 xor %eax,%eax
4006ad: 48 89 e2 mov %rsp,%rdx
4006b0: be 82 07 40 00 mov $0x400782,%esi
4006b5: bf 01 00 00 00 mov $0x1,%edi
4006ba: e8 21 fe ff ff callq 4004e0 <__printf_chk@plt>
4006bf: 31 c0 xor %eax,%eax
4006c1: 48 8b 4c 24 28 mov 0x28(%rsp),%rcx
4006c6: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx
4006cd: 00 00
4006cf: 75 06 jne 4006d7 <__printf_chk@plt+0x1f7>
4006d1: 48 83 c4 30 add $0x30,%rsp
4006d5: 5b pop %rbx
4006d6: c3 retq
4006d7: e8 e4 fd ff ff callq 4004c0 <__stack_chk_fail@plt>
4006dc: 0f 1f 40 00 nopl 0x0(%rax)
4006e0: bf 97 07 40 00 mov $0x400797,%edi
4006e5: e9 c6 fd ff ff jmpq 4004b0 <puts@plt>
4006ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
4006f0: 41 57 push %r15
4006f2: 41 56 push %r14
4006f4: 41 89 ff mov %edi,%r15d
4006f7: 41 55 push %r13
4006f9: 41 54 push %r12
4006fb: 4c 8d 25 0e 07 20 00 lea 0x20070e(%rip),%r12 # 600e10 <__printf_chk@plt+0x200930>
400702: 55 push %rbp
400703: 48 8d 2d 0e 07 20 00 lea 0x20070e(%rip),%rbp # 600e18 <__printf_chk@plt+0x200938>
40070a: 53 push %rbx
40070b: 49 89 f6 mov %rsi,%r14
40070e: 49 89 d5 mov %rdx,%r13
400711: 4c 29 e5 sub %r12,%rbp
400714: 48 83 ec 08 sub $0x8,%rsp
400718: 48 c1 fd 03 sar $0x3,%rbp
40071c: e8 5f fd ff ff callq 400480 <puts@plt-0x30>
400721: 48 85 ed test %rbp,%rbp
400724: 74 20 je 400746 <__printf_chk@plt+0x266>
400726: 31 db xor %ebx,%ebx
400728: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40072f: 00
400730: 4c 89 ea mov %r13,%rdx
400733: 4c 89 f6 mov %r14,%rsi
400736: 44 89 ff mov %r15d,%edi
400739: 41 ff 14 dc callq *(%r12,%rbx,8)
40073d: 48 83 c3 01 add $0x1,%rbx
400741: 48 39 eb cmp %rbp,%rbx
400744: 75 ea jne 400730 <__printf_chk@plt+0x250>
400746: 48 83 c4 08 add $0x8,%rsp
40074a: 5b pop %rbx
40074b: 5d pop %rbp
40074c: 41 5c pop %r12
40074e: 41 5d pop %r13
400750: 41 5e pop %r14
400752: 41 5f pop %r15
400754: c3 retq
400755: 90 nop
400756: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40075d: 00 00 00
400760: f3 c3 repz retq
1 | OK, it's a very long text, and obviously it's difficult for human to understand it. So maybe we can use something smartly. We can add breakpoint at everywhere it seems like a return or finish for a function, and we could run it in gdb. The place it would not be run is the thing we are finding. |
(gdb) b *0x400520
Breakpoint 1 at 0x400520
(gdb) b *0x4005c9
Breakpoint 2 at 0x4005c9
(gdb) b *0x40061d
Breakpoint 3 at 0x40061d
(gdb) b *0x4006c6
Breakpoint 4 at 0x4006c6
(gdb) b *0x400728
Breakpoint 5 at 0x400728
(gdb) run
Starting program: /home/binary/code/chapter5/lvl5
Breakpoint 1, 0x0000000000400520 in ?? ()
(gdb) c
Continuing.
Breakpoint 5, 0x0000000000400728 in ?? ()
(gdb) c
Continuing.
Breakpoint 2, 0x00000000004005c9 in ?? ()
(gdb) c
Continuing.
nothing to see here
[Inferior 1 (process 1936) exited with code 01]
(gdb)
1 | As we predicted, there are some codes never used. Let's focus on it. |
400620: 53 push %rbx
400621: be 74 07 40 00 mov $0x400774,%esi
400626: bf 01 00 00 00 mov $0x1,%edi
40062b: 48 83 ec 30 sub $0x30,%rsp
40062f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400636: 00 00
400638: 48 89 44 24 28 mov %rax,0x28(%rsp)
40063d: 31 c0 xor %eax,%eax
40063f: 48 b8 10 60 21 33 15 movabs $0x6223331533216010,%rax
400646: 33 23 62
400649: c6 44 24 20 00 movb $0x0,0x20(%rsp)
40064e: 48 89 04 24 mov %rax,(%rsp)
400652: 48 b8 45 65 76 34 41 movabs $0x6675364134766545,%rax
400659: 36 75 66
40065c: 48 89 44 24 08 mov %rax,0x8(%rsp)
400661: 48 b8 17 67 75 64 10 movabs $0x6570331064756717,%rax
400668: 33 70 65
40066b: 48 89 44 24 10 mov %rax,0x10(%rsp)
400670: 48 b8 18 35 76 62 11 movabs $0x6671671162763518,%rax
400677: 67 71 66
40067a: 48 89 44 24 18 mov %rax,0x18(%rsp)
40067f: 8b 1c 25 40 05 40 00 mov 0x400540,%ebx
400686: 31 c0 xor %eax,%eax
400688: 89 da mov %ebx,%edx
40068a: e8 51 fe ff ff callq 4004e0 <__printf_chk@plt>
40068f: 48 8d 54 24 20 lea 0x20(%rsp),%rdx
400694: 48 89 e0 mov %rsp,%rax
400697: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40069e: 00 00
4006a0: 31 18 xor %ebx,(%rax)
4006a2: 48 83 c0 04 add $0x4,%rax
4006a6: 48 39 d0 cmp %rdx,%rax
4006a9: 75 f5 jne 4006a0 <__printf_chk@plt+0x1c0>
4006ab: 31 c0 xor %eax,%eax
4006ad: 48 89 e2 mov %rsp,%rdx
4006b0: be 82 07 40 00 mov $0x400782,%esi
4006b5: bf 01 00 00 00 mov $0x1,%edi
4006ba: e8 21 fe ff ff callq 4004e0 <__printf_chk@plt>
4006bf: 31 c0 xor %eax,%eax
4006c1: 48 8b 4c 24 28 mov 0x28(%rsp),%rcx
4006c6: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx
1 | As the hint says, we could do a redirection to here to get something. |
400500: 48 83 ec 08 sub $0x8,%rsp
400504: bf 97 07 40 00 mov $0x400797,%edi
400509: e8 a2 ff ff ff callq 4004b0 <puts@plt>
40050e: b8 01 00 00 00 mov $0x1,%eax
400513: 48 83 c4 08 add $0x8,%rsp
400517: c3 retq
400518: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40051f: 00
400520: 31 ed xor %ebp,%ebp
400522: 49 89 d1 mov %rdx,%r9
400525: 5e pop %rsi
400526: 48 89 e2 mov %rsp,%rdx
400529: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40052d: 50 push %rax
40052e: 54 push %rsp
40052f: 49 c7 c0 60 07 40 00 mov $0x400760,%r8
400536: 48 c7 c1 f0 06 40 00 mov $0x4006f0,%rcx
40053d: 48 c7 c7 00 05 40 00 mov $0x400500,%rdi -> 40053d 48 c7 c7 20 06 40 00 mov $0x400520, %rdi
400544: e8 87 ff ff ff callq 4004d0 <__libc_start_main@plt>
1 | Now we can get the key. |
binary@binary-VirtualBox:/code/chapter5$ ./lvl5/code/chapter5$ ./oracle 0fa355cbec64a05f7a5d050e836b1a1f
key = 0x00400620
decrypted flag = 0fa355cbec64a05f7a5d050e836b1a1f
binary@binary-VirtualBox:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 5 completed, unlocked lvl6 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint
1 |
|
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 0fa355cbec64a05f7a5d050e836b1a1f -h
Find out what I expect, then trace me for a hint
1 | So let's just run it. |
binary@binary-VirtualBox:/code/chapter5$ ./lvl6/code/chapter5$ ./lvl6 101
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
binary@binary-VirtualBox:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
binary@binary-VirtualBox:/code/chapter5$ ./lvl6 2/code/chapter5$ ./lvl6 97
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
binary@binary-VirtualBox:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
binary@binary-VirtualBox:~/code/chapter5$ ltrace ./lvl6
__libc_start_main(0x4005f0, 1, 0x7fff758d71b8, 0x400890 <unfinished …>
__printf_chk(1, 0x400947, 2, 100) = 2
__printf_chk(1, 0x400947, 3, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 5, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 7, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 11, 0x7ffffffe) = 3
__printf_chk(1, 0x400947, 13, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 17, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 19, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 23, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 29, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 31, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 37, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 41, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 43, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 47, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 53, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 59, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 61, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 67, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 71, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 73, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 79, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 83, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 89, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 97, 0x7ffffffd) = 3
putchar(10, 3, 0, 0x7ffffffd2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
) = 10
+++ exited (status 0) +++
1 | We get nothing, and it seems we need to find something it expected. So we maybe could use strings to try if we can get anything interesting. |
binary@binary-VirtualBox:~/code/chapter5$ strings ./lvl6
/lib64/ld-linux-x86-64.so.2
libc.so.6
__printf_chk
__stack_chk_fail
putchar
__sprintf_chk
strcmp
_libc_start_main
setenv
gmon_start
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.2.5
UH-`
AWAVA
AUATL
[]A\A]A^A
DEBUG: argv[1] = %s
get_data_addr
0x%jx
DATA_ADDR
;*3$”
1 | GOOD! There are really obvious hint for us. ``argv[1] = %s get_data_addr'' |
binary@binary-VirtualBox:/code/chapter5$ ./lvl6 get_data_addr/code/chapter5$ ltrace ./lvl6 get_data_addr
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
binary@binary-VirtualBox:
__libc_start_main(0x4005f0, 2, 0x7ffd05739688, 0x400890 <unfinished …>
strcmp(“get_data_addr”, “get_data_addr”) = 0
__sprintf_chk(0x7ffd05739180, 1, 1024, 0x400937) = 8
setenv(“DATA_ADDR”, “0x4006c1”, 1) = 0
__printf_chk(1, 0x400947, 2, 100) = 2
__printf_chk(1, 0x400947, 3, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 5, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 7, 0x7ffffffe) = 2
__printf_chk(1, 0x400947, 11, 0x7ffffffe) = 3
__printf_chk(1, 0x400947, 13, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 17, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 19, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 23, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 29, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 31, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 37, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 41, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 43, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 47, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 53, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 59, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 61, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 67, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 71, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 73, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 79, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 83, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 89, 0x7ffffffd) = 3
__printf_chk(1, 0x400947, 97, 0x7ffffffd) = 3
putchar(10, 3, 0, 0x7ffffffd2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
) = 10
+++ exited (status 0) +++
1 | There is nothing special in directly running, but something interesting in ltrace. If input get_data_addr, set DATA_ADDR as 0x4006c1. Let's have a look what it is. |
(gdb) x/16x 0x4006c1
0x4006c1: 0x2e 0x29 0xc6 0x4a 0x0f 0x03 0xa6 0xee
0x4006c9: 0x2a 0x30 0x7f 0xec 0xc8 0xc3 0xff 0x42
1 | We get the key ``2e29c64a0f03a6ee2a307fecc8c3ff42``. |
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 2e29c64a0f03a6ee2a307fecc8c3ff42
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 6 completed, unlocked lvl7 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint
1 |
|
binary@binary-VirtualBox:~/code/chapter5$ ./oracle 2e29c64a0f03a6ee2a307fecc8c3ff42 -h
First observe my runtime state,
then watch closely while I replicate
1 | Let's first see runtime state. |
binary@binary-VirtualBox:~/code/chapter5$ ./lvl7
-bash: ./lvl7: cannot execute binary file: Exec format error
1 | Strange! Let's have a look what lvl7 is. |
binary@binary-VirtualBox:~/code/chapter5$ file ./lvl7
./lvl7: gzip compressed data, last modified: Sat Dec 1 17:30:15 2018, from Unix
1 | OK, it's a gzip. First unzip it. |
binary@binary-VirtualBox:~/code/chapter5$ tar -xvzf ./lvl7
stage1
stage2.zip
1 | OK, two file is here. |
binary@binary-VirtualBox:/code/chapter5$ file stage1/code/chapter5$ unzip stage2.zip
stage1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ac71081a0951af729a4064c1dafbc5713b1537e3, stripped
binary@binary-VirtualBox:
Archive: stage2.zip
[stage2.zip] tmp password:
1 | As we can see, stage1 is a elf file, and stage2.zip need a password. It seems that we need to get the password through stage1. |
binary@binary-VirtualBox:/code/chapter5$ ./stage1/code/chapter5$ ltrace ./stage1
binary@binary-VirtualBox:
__libc_start_main(0x4003e0, 1, 0x7fff690515d8, 0x400520 <no return …>
+++ exited (status 0) +++
1 | There is nothing interesting in runtime state. So maybe the password would stay in strings. |
binary@binary-VirtualBox:~/code/chapter5$ strings stage1
/lib64/ld-linux-x86-64.so.2
libc.so.6
_libc_start_main
gmon_start
GLIBC_2.2.5
dump ecx
UH-0
AWAVA
AUATL
[]A\A]A^A
S)TA
E2 KE
;*3$”
1 | We in fact find something interesting inthe last 3 lines. There are something be like STAE2 KE. Now it's time to use GDB! |
00000000004003e0 <.text>:
4003e0: ba a4 05 40 00 mov $0x4005a4,%edx
4003e5: 0f 1f 00 nopl (%rax)
4003e8: 0f be 02 movsbl (%rdx),%eax
4003eb: 83 f8 30 cmp $0x30,%eax
4003ee: 7c 12 jl 400402 <__libc_start_main@plt+0x42>
4003f0: 83 f8 5a cmp $0x5a,%eax
4003f3: 7f 0d jg 400402 <__libc_start_main@plt+0x42>
4003f5: eb 09 jmp 400400 <__libc_start_main@plt+0x40>
4003f7: 64 75 6d fs jne 400467 <__libc_start_main@plt+0xa7>
4003fa: 70 20 jo 40041c <__libc_start_main@plt+0x5c>
4003fc: 65 63 78 00 movslq %gs:0x0(%rax),%edi
400400: 89 c1 mov %eax,%ecx
400402: 48 83 c2 01 add $0x1,%rdx
400406: 48 81 fa b5 05 40 00 cmp $0x4005b5,%rdx
40040d: 75 d9 jne 4003e8 <__libc_start_main@plt+0x28>
40040f: 31 c0 xor %eax,%eax
400411: c3 retq
(gdb) b *0x4003e0
Breakpoint 1 at 0x4003e0
(gdb) run
Starting program: /home/binary/code/chapter5/stage1
Breakpoint 1, 0x00000000004003e0 in ?? ()
(gdb) display/i $pc
1: x/i $pc
=> 0x4003e0: mov $0x4005a4,%edx
(gdb) x/16s 0x4005a4
0x4005a4: “ S)TA\021G\372\336\377E2 KE\212Y”
1 | Lucky! We meet it at the first line. We guess the password is ``STAGE2KEY``. |
binary@binary-VirtualBox:~/code/chapter5/lv7$ ./stage2
#include <stdio.h>
#include <string.h>
#include
#include
int main()
{
std::vector
char q[] = “#include <stdio.h>\n#include <string.h>\n#include
int i, _0F;
char c, qc[4096];
for(i = 0; i < 32; i++) for(c = ‘0’; c <= ‘9’; c++) hex.push_back(c);
for(i = 0; i < 32; i++) for(c = ‘A’; c <= ‘F’; c++) hex.push_back(c);
std::srand(55);
std::random_shuffle(hex.begin(), hex.end());
_0F = 0;
for(i = 0; i < strlen(q); i++)
{
if(q[i] == 0xa)
{
qc[_0F++] = 0x5c;
qc[_0F] = ‘n’;
}
else if(q[i] == 0x22)
{
qc[_0F++] = 0x5c;
qc[0F] = 0x22;
}
else if(!strncmp(&q[i], “0F”, 2) && (q[i-1] == ‘‘ || i == 545))
{
char buf[3];
buf[0] = q[i];
buf[1] = q[i+1];
buf[2] = 0;
unsigned j = strtoul(buf, NULL, 16);
qc[_0F++] = q[i++] = hex[j];
qc[_0F] = q[i] = hex[j+1];
}
else qc[_0F] = q[i];
_0F++;
}
qc[_0F] = 0;
printf(q, qc);
return 0;
}
1 | Run stage2. We discover it puts a cpp file, and generate 2 Bytes keys. So we could iterated this process 16 times to get the entire key. |
OK, now we get the full key.
1 | binary@binary-VirtualBox:~/code/chapter5/lv7$ ./sol.sh |
Level 8
We finally come in level 8. The hint is very strange.
1 | binary@binary-VirtualBox:~/code/chapter5$ ./oracle 0F25E512A7763EEFB7696B3AEDA1F964 -h |
OK, we take it aside and see what lvl8 is first.
1 | binary@binary-VirtualBox:~/code/chapter5$ file ./lvl8 |
Strange! ASCII text, and very long. Open it.
Obviously, it’s not any language we could understand, but we could still find something really interesting in it.
If you observe it carefully, you’ll find there are many repeated words, and also, the capacity is very strange. So it’s easy to think about that maybe the words is meaningless, but the uppercase and lowercase of the letters are very important. Let’s make a program to translate uppercase letters into 1 and lowercase letters into 0.
1 |
|
And we could get such a file level8.bin
1 | binary@binary-VirtualBox:~/code/chapter5/lv8$ file level8.bin |
Now we have a bit map which is 300 * 300 * 24. And open the picture, it’s like this:
I’m stuck here for a bit while. Because I don’t know what the picture is. So I decided to open it with hexedit first.
Strange! Do you remember what the picture is? 300 * 300 * 24. However, that means, white should be FF and black should be 00. But as you see in picture, there are many 01 and FE, that means there are some information in the lowest bit. Let’s extract it.
1 |
|
Now we get another elf file, which seems to have ability to help us get the key.
1 | binary@binary-VirtualBox:~/code/chapter5/lv8$ gcc ./deal.c -o deal |
Let’s first run it.
1 | binary@binary-VirtualBox:~/code/chapter5/lv8$ ./lvl8_elf |
Really disgusting. It don’t want give us the key directly. OK, as we usually do, have a look at ltrace. There are something interesting need we focus. First it unlock a memory, and then write something on it, and lock it. Maybe we can find something it. GDB!
1 | 00000000004005d6 <main>: |
We can see that, after operating the memory block, it gets in a circle. And obviously, we don’t want to see what it exactly do. So we just use gdb and try to see what happen to the block.
1 | (gdb) b *0x400606 |
We can see that, the circle do one thing: change 0x603000 into 50 51 52 56 57. So we have enough reason to think that maybe there are something interesting in 0x53-0x55.
1 | (gdb) dump binary memory dump.bin 0x603000 0x603055 |

Got it!
1 | binary@binary-VirtualBox:~/code/chapter5$ ./oracle 2235a6b2123404469f4abce71b1dd29f |
And there is a rewards for us!
This game is really meaningful and interesting. I think everyone who wants to expose joy of binary analysis should finish this game.
The whole file directory could be found on https://github.com/BoringZheng/binary-analysis.git