Points: 200
Reversing
Can you deal with the Duck Web? Get us the flag from this program. You can also find the program in /problems/quackme_4_0e48834ea71b521b9f35d29dc7be974e.
Objdump or something similar is probably a good place to start.
Upon listing all the functions, there are multiple written functions. We can analyse and print the function do_magic()
[0x08048642]> pdf
/ (fcn) sym.do_magic 211
| sym.do_magic ();
| ; var int local_1dh @ ebp-0x1d
| ; var int local_1ch @ ebp-0x1c
| ; var int local_18h @ ebp-0x18
| ; var int local_14h @ ebp-0x14
| ; var int local_10h @ ebp-0x10
| ; var int local_ch @ ebp-0xc
| ; CALL XREF from sym.main (0x804874a)
| 0x08048642 55 push ebp
| 0x08048643 89e5 mov ebp, esp
| 0x08048645 83ec28 sub esp, 0x28 ; '('
| 0x08048648 e88effffff call sym.read_input
| 0x0804864d 8945ec mov dword [local_14h], eax
| 0x08048650 83ec0c sub esp, 0xc
| 0x08048653 ff75ec push dword [local_14h]
| 0x08048656 e835feffff call sym.imp.strlen ; size_t strlen(const char *s)
| 0x0804865b 83c410 add esp, 0x10
| 0x0804865e 8945f0 mov dword [local_10h], eax
| 0x08048661 8b45f0 mov eax, dword [local_10h]
| 0x08048664 83c001 add eax, 1
| 0x08048667 83ec0c sub esp, 0xc
| 0x0804866a 50 push eax
| 0x0804866b e8f0fdffff call sym.imp.malloc ; void *malloc(size_t size)
| 0x08048670 83c410 add esp, 0x10
| 0x08048673 8945f4 mov dword [local_ch], eax
| 0x08048676 837df400 cmp dword [local_ch], 0
| ,=< 0x0804867a 751a jne 0x8048696
| | 0x0804867c 83ec0c sub esp, 0xc
| | 0x0804867f 6884880408 push str.malloc___returned_NULL._Out_of_Memory ; 0x8048884 ; "malloc() returned NULL. Out of Memory\n"
| | 0x08048684 e8e7fdffff call sym.imp.puts ; int puts(const char *s)
| | 0x08048689 83c410 add esp, 0x10
| | 0x0804868c 83ec0c sub esp, 0xc
| | 0x0804868f 6aff push 0xffffffffffffffff
| | 0x08048691 e8eafdffff call sym.imp.exit ; void exit(int status)
| | ; CODE XREF from sym.do_magic (0x804867a)
| `-> 0x08048696 8b45f0 mov eax, dword [local_10h]
| 0x08048699 83c001 add eax, 1
| 0x0804869c 83ec04 sub esp, 4
| 0x0804869f 50 push eax
| 0x080486a0 6a00 push 0
| 0x080486a2 ff75f4 push dword [local_ch]
| 0x080486a5 e816feffff call sym.imp.memset ; void *memset(void *s, int c, size_t n)
| 0x080486aa 83c410 add esp, 0x10
| 0x080486ad c745e4000000. mov dword [local_1ch], 0
| 0x080486b4 c745e8000000. mov dword [local_18h], 0
| ,=< 0x080486bb eb4e jmp 0x804870b
| | ; CODE XREF from sym.do_magic (0x8048711)
| .--> 0x080486bd 8b45e8 mov eax, dword [local_18h]
| :| 0x080486c0 0558880408 add eax, obj.sekrutBuffer
| :| 0x080486c5 0fb608 movzx ecx, byte [eax]
| :| 0x080486c8 8b55e8 mov edx, dword [local_18h]
| :| 0x080486cb 8b45ec mov eax, dword [local_14h]
| :| 0x080486ce 01d0 add eax, edx
| :| 0x080486d0 0fb600 movzx eax, byte [eax]
| :| 0x080486d3 31c8 xor eax, ecx
| :| 0x080486d5 8845e3 mov byte [local_1dh], al
| :| 0x080486d8 8b1538a00408 mov edx, dword obj.greetingMessage ; [0x804a038:4]=0x80487f0 str.You_have_now_entered_the_Duck_Web__and_you_re_in_for_a_honkin__good_time.__Can_you_figure_out_my_trick
| :| 0x080486de 8b45e8 mov eax, dword [local_18h]
| :| 0x080486e1 01d0 add eax, edx
| :| 0x080486e3 0fb600 movzx eax, byte [eax]
| :| 0x080486e6 3a45e3 cmp al, byte [local_1dh]
| ,===< 0x080486e9 7504 jne 0x80486ef
| |:| 0x080486eb 8345e401 add dword [local_1ch], 1
| |:| ; CODE XREF from sym.do_magic (0x80486e9)
| `---> 0x080486ef 837de419 cmp dword [local_1ch], 0x19 ; [0x19:4]=-1 ; 25
| ,===< 0x080486f3 7512 jne 0x8048707
| |:| 0x080486f5 83ec0c sub esp, 0xc
| |:| 0x080486f8 68ab880408 push str.You_are_winner ; 0x80488ab ; "You are winner!"
| |:| 0x080486fd e86efdffff call sym.imp.puts ; int puts(const char *s)
| |:| 0x08048702 83c410 add esp, 0x10
| ,====< 0x08048705 eb0c jmp 0x8048713
| ||:| ; CODE XREF from sym.do_magic (0x80486f3)
| |`---> 0x08048707 8345e801 add dword [local_18h], 1
| | :| ; CODE XREF from sym.do_magic (0x80486bb)
| | :`-> 0x0804870b 8b45e8 mov eax, dword [local_18h]
| | : 0x0804870e 3b45f0 cmp eax, dword [local_10h]
| | `==< 0x08048711 7caa jl 0x80486bd
| `----> 0x08048713 c9 leave
\ 0x08048714 c3 ret
Let's take a look what is necessary to get to puts("You are winner!");
address. We see that we need to pass this test where ebp + 0x1c must be equals to 0x19.
0x080486ef 837de419 cmp dword [local_1ch], 0x19 ; [0x19:4]=-1 ; 25
...
0x080486f8 68ab880408 push str.You_are_winner ; 0x80488ab ; "You are winner!"
0x080486fd e86efdffff call sym.imp.puts ; int puts(const char *s)
Looking around the assembly, we can see that there is an instruction that adds 1 to ebp + 0x1c.
0x080486eb 8345e401 add dword [local_1ch], 1
We also notice that there is a loop at the bottom of the assembly.
; CODE XREF from sym.do_magic (0x80486f3)
0x08048707 8345e801 add dword [local_18h], 1
; CODE XREF from sym.do_magic (0x80486bb)
0x0804870b 8b45e8 mov eax, dword [local_18h]
0x0804870e 3b45f0 cmp eax, dword [local_10h]
0x08048711 7caa jl 0x80486bd
Debugging the program, we can see that the number of loops it does corresponds to the number of characters inputted.
We also see that there's an XOR function, where eax is the characters you put in and ecx are the characters provided by the binary.
0x080486d3 31c8 xor eax, ecx
Putting everything together, it is trying to loop through every character in the input, xor it with the characters in the binary make sure it equates to the initial message. The initial message is: You have now entered the Duck Web, and you're in for a honkin' good time.
Writing some pseudo code, it will look something like this
count = 0
for (i = 0; i < length_of_user_input; i++) {
data = user_input[i] xor binary_data[i]
if (data == initial_message[i]) {
count += 1
}
if (count == 25) {
print "You are winner!"
}
}
Let's leak the values of the binary string. We see that the string is located in here
0x080486c0 0558880408 add eax, obj.sekrutBuffer
Get the value from the address
[0x08048642]> px @ obj.sekrutBuffer
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x08048858 2906 164f 2b35 301e 511b 5b14 4b08 5d2b )..O+50.Q.[.K.]+
0x08048868 5014 5d00 1917 5952 5d00 4e6f 206c 696e P.]...YR].No lin
We only need the first 25 bytes. We can then use a Python program to XOR the data ourselves and get the flag.
initialMsg = "You have now entered the Duck Web, and you're in for a honkin' good time."
xorData = '2906164f2b35301e511b5b144b085d2b50145d00191759525d'.decode('hex')
flag = ''
for i in range(len(xorData)):
flag += chr(ord(xorData[i]) ^ ord(initialMsg[i]))
print flag
And we get the flag! Just to confirm, we can pass the flag into the binary
$ ./main
You have now entered the Duck Web, and you're in for a honkin' good time.
Can you figure out my trick?
picoCTF{qu4ckm3_5f8d9c17}
You are winner!
That's all folks.
And there we go. This took me 1 whole day to solve. I hate reversing.
picoCTF{qu4ckm3_5f8d9c17}