Skip to content

NcN 2013 CTF australia bin write up

In this post I will cover the first binary challenge of the No Con Name 2013 CTF driven by the Facebook security team. The binary is available here

This binary challenge is based on a i386 elf file which prompts for a flag:

$ file ./derp 
./derp: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=b77361bfdab4b30a5ed258ee173fe306184a4438, not stripped
$ ./derp 
Facebook CTF
Enter flag: asdasdasdasd
Sorry, that is not correct.
$ 

The first look at the binary:

$ gdb -q ./derp 
Reading symbols from /home/libcrack/Desktop/NcN2013-CTF/derp...(no debugging symbols found)...done.
gdb-peda$ pdisass main
Dump of assembler code for function main:
   0x080482d4 <+0>:	push   ebp
   0x080482d5 <+1>:	mov    ebp,esp
   0x080482d7 <+3>:	and    esp,0xfffffff0
   0x080482da <+6>:	sub    esp,0x20
   0x080482dd <+9>:	call   0x80483fa 
   0x080482e2 <+14>:	mov    eax,ds:0x80d1088
   0x080482e7 <+19>:	mov    DWORD PTR [esp],eax
   0x080482ea <+22>:	call   0x804ffa0 
   0x080482ef <+27>:	mov    DWORD PTR [esp+0x1c],eax
   0x080482f3 <+31>:	cmp    DWORD PTR [esp+0x1c],0x0
   0x080482f8 <+36>:	jne    0x8048329 
   0x080482fa <+38>:	mov    eax,ds:0x80d14c4
   0x080482ff <+43>:	mov    DWORD PTR [esp+0xc],eax
   0x08048303 <+47>:	mov    DWORD PTR [esp+0x8],0x1b
   0x0804830b <+55>:	mov    DWORD PTR [esp+0x4],0x1
   0x08048313 <+63>:	mov    DWORD PTR [esp],0x80b2265
   0x0804831a <+70>:	call   0x8049130 
   0x0804831f <+75>:	mov    eax,0x1
   0x08048324 <+80>:	jmp    0x80483f8 
   0x08048329 <+85>:	mov    eax,ds:0x80d1088
   0x0804832e <+90>:	mov    DWORD PTR [esp+0x8],eax
   0x08048332 <+94>:	mov    DWORD PTR [esp+0x4],0x0
   0x0804833a <+102>:	mov    eax,DWORD PTR [esp+0x1c]
   0x0804833e <+106>:	mov    DWORD PTR [esp],eax
   0x08048341 <+109>:	call   0x80481a0
   0x08048346 <+114>:	mov    edx,DWORD PTR ds:0x80d14bc
   0x0804834c <+120>:	mov    eax,ds:0x80d1088
   0x08048351 <+125>:	sub    eax,0x1
   0x08048354 <+128>:	mov    DWORD PTR [esp+0x8],edx
   0x08048358 <+132>:	mov    DWORD PTR [esp+0x4],eax
   0x0804835c <+136>:	mov    eax,DWORD PTR [esp+0x1c]
   0x08048360 <+140>:	mov    DWORD PTR [esp],eax
   0x08048363 <+143>:	call   0x8048fc0 
   0x08048368 <+148>:	test   eax,eax
   0x0804836a <+150>:	jne    0x80483a4 
   0x0804836c <+152>:	mov    eax,ds:0x80d14c4
   0x08048371 <+157>:	mov    DWORD PTR [esp+0xc],eax
   0x08048375 <+161>:	mov    DWORD PTR [esp+0x8],0x1b
   0x0804837d <+169>:	mov    DWORD PTR [esp+0x4],0x1
   0x08048385 <+177>:	mov    DWORD PTR [esp],0x80b2281
   0x0804838c <+184>:	call   0x8049130 
   0x08048391 <+189>:	mov    eax,DWORD PTR [esp+0x1c]
   0x08048395 <+193>:	mov    DWORD PTR [esp],eax
   0x08048398 <+196>:	call   0x804fee0 
   0x0804839d <+201>:	mov    eax,0x2
   0x080483a2 <+206>:	jmp    0x80483f8 
   0x080483a4 <+208>:	mov    eax,ds:0x80d1088
   0x080483a9 <+213>:	sub    eax,0x2
   0x080483ac <+216>:	mov    DWORD PTR [esp+0x4],eax
   0x080483b0 <+220>:	mov    eax,DWORD PTR [esp+0x1c]
   0x080483b4 <+224>:	mov    DWORD PTR [esp],eax
   0x080483b7 <+227>:	call   0x804841a 
   0x080483bc <+232>:	test   eax,eax
   0x080483be <+234>:	jne    0x80483e7 
   0x080483c0 <+236>:	mov    eax,ds:0x80d14c4
   0x080483c5 <+241>:	mov    DWORD PTR [esp+0xc],eax
   0x080483c9 <+245>:	mov    DWORD PTR [esp+0x8],0x1c
   0x080483d1 <+253>:	mov    DWORD PTR [esp+0x4],0x1
   0x080483d9 <+261>:	mov    DWORD PTR [esp],0x80b229d
   0x080483e0 <+268>:	call   0x8049130 
   0x080483e5 <+273>:	jmp    0x80483f3 
   0x080483e7 <+275>:	mov    DWORD PTR [esp],0x80b22ba
   0x080483ee <+282>:	call   0x8049430 
   0x080483f3 <+287>:	mov    eax,0x0
   0x080483f8 <+292>:	leave  
   0x080483f9 <+293>:	ret    
End of assembler dump.
gdb-peda$ 

The call to the function that will check the input buffer is located at 0x080483b7

0x080483b7 <+227>:	call   0x804841a 

Let’s what the function check_buffer does:

gdb-peda$ pdisass check_buffer
Dump of assembler code for function check_buffer:
   0x0804841a <+0>:	push   ebp
   0x0804841b <+1>:	mov    ebp,esp
   0x0804841d <+3>:	sub    esp,0x10
   0x08048420 <+6>:	mov    BYTE PTR [ebp-0x5],0x0
   0x08048424 <+10>:	mov    BYTE PTR [ebp-0x6],0x0
   0x08048428 <+14>:	mov    BYTE PTR [ebp-0x7],0x0
   0x0804842c <+18>:	mov    DWORD PTR [ebp-0x4],0x0
   0x08048433 <+25>:	mov    DWORD PTR [ebp-0xc],0xcd000000
   0x0804843a <+32>:	jmp    0x804849c 
   0x0804843c <+34>:	mov    eax,DWORD PTR [ebp-0xc]
   0x0804843f <+37>:	shr    eax,0x18
   0x08048442 <+40>:	mov    BYTE PTR [ebp-0x7],al
   0x08048445 <+43>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x08048449 <+47>:	and    eax,0xf
   0x0804844c <+50>:	mov    BYTE PTR [ebp-0x5],al
   0x0804844f <+53>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x08048453 <+57>:	and    eax,0xfffffff0
   0x08048456 <+60>:	mov    BYTE PTR [ebp-0x6],al
   0x08048459 <+63>:	movzx  eax,BYTE PTR [ebp-0x6]
   0x0804845d <+67>:	mov    edx,eax
   0x0804845f <+69>:	shr    dl,0x4
   0x08048462 <+72>:	movzx  eax,BYTE PTR [ebp-0x5]
   0x08048466 <+76>:	shl    eax,0x4
   0x08048469 <+79>:	add    eax,edx
   0x0804846b <+81>:	mov    BYTE PTR [ebp-0x7],al
   0x0804846e <+84>:	mov    edx,DWORD PTR ds:0x80d1090
   0x08048474 <+90>:	mov    eax,DWORD PTR [ebp-0x4]
   0x08048477 <+93>:	add    eax,edx
   0x08048479 <+95>:	movzx  edx,BYTE PTR [eax]
   0x0804847c <+98>:	mov    eax,DWORD PTR [ebp-0x4]
   0x0804847f <+101>:	mov    ecx,DWORD PTR [ebp+0x8]
   0x08048482 <+104>:	add    eax,ecx
   0x08048484 <+106>:	movzx  ecx,BYTE PTR [eax]
   0x08048487 <+109>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x0804848b <+113>:	xor    eax,ecx
   0x0804848d <+115>:	cmp    dl,al
   0x0804848f <+117>:	je     0x8048498 
   0x08048491 <+119>:	mov    eax,0x0
   0x08048496 <+124>:	jmp    0x80484a9 
   0x08048498 <+126>:	add    DWORD PTR [ebp-0x4],0x1
   0x0804849c <+130>:	mov    eax,DWORD PTR [ebp-0x4]
   0x0804849f <+133>:	cmp    eax,DWORD PTR [ebp+0xc]
   0x080484a2 <+136>:	jb     0x804843c 
   0x080484a4 <+138>:	mov    eax,0x1
   0x080484a9 <+143>:	leave  
   0x080484aa <+144>:	ret    
End of assembler dump.
gdb-peda$ 

First, the function will set the local variables after the function prologue at 0x08048420. After that It jumps to 0x080484a2 to finally jump again to 0x804843c which is when the important part takes place:

   0x0804841a <+0>:	push   ebp
   0x0804841b <+1>:	mov    ebp,esp
   0x0804841d <+3>:	sub    esp,0x10
   0x08048420 <+6>:	mov    BYTE PTR [ebp-0x5],0x0
   0x08048424 <+10>:	mov    BYTE PTR [ebp-0x6],0x0
   0x08048428 <+14>:	mov    BYTE PTR [ebp-0x7],0x0
   0x0804842c <+18>:	mov    DWORD PTR [ebp-0x4],0x0
   0x08048433 <+25>:	mov    DWORD PTR [ebp-0xc],0xcd000000
   0x0804843a <+32>:	jmp    0x804849c 
   0x0804849c <+130>:	mov    eax,DWORD PTR [ebp-0x4]
   0x0804849f <+133>:	cmp    eax,DWORD PTR [ebp+0xc]
   0x080484a2 <+136>:	jb     0x804843c 

Here, we can se some calculations over the registers eax,ecx and edx

   0x0804843c <+34>:	mov    eax,DWORD PTR [ebp-0xc]
   0x0804843f <+37>:	shr    eax,0x18
   0x08048442 <+40>:	mov    BYTE PTR [ebp-0x7],al
   0x08048445 <+43>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x08048449 <+47>:	and    eax,0xf
   0x0804844c <+50>:	mov    BYTE PTR [ebp-0x5],al
   0x0804844f <+53>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x08048453 <+57>:	and    eax,0xfffffff0
   0x08048456 <+60>:	mov    BYTE PTR [ebp-0x6],al
   0x08048459 <+63>:	movzx  eax,BYTE PTR [ebp-0x6]
   0x0804845d <+67>:	mov    edx,eax
   0x0804845f <+69>:	shr    dl,0x4
   0x08048462 <+72>:	movzx  eax,BYTE PTR [ebp-0x5]
   0x08048466 <+76>:	shl    eax,0x4
   0x08048469 <+79>:	add    eax,edx
   0x0804846b <+81>:	mov    BYTE PTR [ebp-0x7],al
   0x0804846e <+84>:	mov    edx,DWORD PTR ds:0x80d1090
   0x08048474 <+90>:	mov    eax,DWORD PTR [ebp-0x4]
   0x08048477 <+93>:	add    eax,edx
   0x08048479 <+95>:	movzx  edx,BYTE PTR [eax]
   0x0804847c <+98>:	mov    eax,DWORD PTR [ebp-0x4]
   0x0804847f <+101>:	mov    ecx,DWORD PTR [ebp+0x8]
   0x08048482 <+104>:	add    eax,ecx
   0x08048484 <+106>:	movzx  ecx,BYTE PTR [eax]
   0x08048487 <+109>:	movzx  eax,BYTE PTR [ebp-0x7]
   0x0804848b <+113>:	xor    eax,ecx
   0x0804848d <+115>:	cmp    dl,al
   0x0804848f <+117>:	je     0x8048498 

Here follows the most important part of this dissasembled. The register ecx will contain the characters of the user’s input string. This value will get xored with eax and then compared to edx. If the input caracted contained in ecx equals to xor(eax,edx) the function will jump to the begining of the algorithm to repeat this check for every character of the string

   0x0804848b <+113>:	xor    eax,ecx
   0x0804848d <+115>:	cmp    dl,al
   0x0804848f <+117>:	je     0x8048498 

To calculate to correct value for the input string, It is needed to calculate the value of xor(eax,edx) every iteration. This can be easily achieved with the following gdb script:

# 0x804848b :    xor    eax,ecx
# 0x804848d :    cmp    dl,al
# 0x804848f :    je     0x8048498 

break *0x804848b
        commands
        printf "%c", $edx ^ $eax
        continue
end

break *0x804848d
        commands
        set $eax = $edx
        continue
end

run
quit

The execution will look like the followin excerpt:

$ echo | gdb -q -x au_derp.gdb ./au_derp
Reading symbols from /home/libcrack/Desktop/NcN2013-CTF/australia/au_derp...(no debugging symbols found)...done.
Breakpoint 1 at 0x804848b
Breakpoint 2 at 0x804848d
Facebook CTF
74c86bf89646425f647fcf7643af15f251b186bf58a6d5dc7eb8bf9cfc9d04cdEnter flag: Winner! Post your flag.
[Inferior 1 (process 19655) exited normally]
Warning: not running or target is remote

Challenge solved!

Published inctfdebugginghacking