Skip to content

Latest commit

 

History

History

quackme

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

quackme

Points: 200

Category

Reversing

Question

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.

Hint

Objdump or something similar is probably a good place to start.

Solution

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.

Flag

picoCTF{qu4ckm3_5f8d9c17}