Kernel Pool Overflows

June 22, 2008

Hi,

Device Drivers Security is not a really spreaded and known, not many researchers are involved into this field, one of my scope, in this blog is to summarize all material related to Windows Kernel Mode Security..

Here two intersing new papers about Kernel Pool Overflows and Driver Impersonation Attack:

http://immunityinc.com/downloads/KernelPool.odp

http://immunityinc.com/downloads/DriverImpersonationAttack_i2omgmt.pdf

See you to the next post.. 🙂


On USB Driver Coding #7

November 30, 2007

Hi,

In the previous post we have seen how to completely Dump an URB but as you should remember exists a particular structure _URB_CONTROL_TRANSFER, that USB client drivers sets up to transfer data to or from a control pipe. So we need to implement two external Dump Functions, DumpPipeHandle and DumpTransferBuffer.

void DumpPipeHandle(
in struct Buffer *b,const char *s,
in USBD_PIPE_HANDLE inPipeHandle
)
{
unsigned char ep;

if (GetEndpointInfo(inPipeHandle,&ep))
KPrintf(b,”%s = %p [endpoint 0x%x]\n”,s,inPipeHandle,ep);
else
KPrintf(b,”%s = %p\n”,s,inPipeHandle);
}

As you should remember it’s necessary for any PipeHandle to know the Endpoint. This can be accomplished by tracing the USBD_PIPE_HANDLE for each Endpoint (the number of Endpoints is declared at our choise (use for example MAXEP = 50).

Now is time to rip the TransferBuffer with DumpTransferBuffer:

void DumpTransferBuffer(
struct Buffer *b,
PUCHAR pBuffer,
PMDL pMdl,
ULONG uBufferSize,
in BOOLEAN bPrintHeader,
ULONG uBufferOffset = 0
)

if(pMdl)
{
DumpBuffer(b,pBuffer+uBufferOffset,uBufferSize);

else if(pMdl)
{
PUCHAR pMDLBuf = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl,NormalPagePriority);
if(pMDLBuf)
DumpBuffer(b,pMDLBuf+uBufferOffset,uBufferSize);
}
}

Here ends the USB Coding Series (source code I’ve used is taken from SniffUSB 2.0), but surely i’ll come back with other arguments related to USB..

See you to the next post.. 🙂


On USB Coding #5

November 17, 2007

Hi,

In the previous post We talked about the general foundamentals of USB Coding, many other thing should be said, for example about Power Management, but this will became a commentary upon USB_WDF.doc provided by Microsoft, our scope is a general overview of USB Coding and related USB Security/Forensics.

USB Security can be divided into two parts:

1) Intrusion Risk Security of USB Device Drivers
2) Forensics of USB Secure Devices

As you have seen USB Data Transactions does not have any kind of Encryption or Anti-Sniff protection by Default. Actually USB devices are extremely diffused,
these devs are applied in every kind of periferials, also in Secure Devices such as Fingerprint, Hardware Protectors, Sensitive Data Auth Devices and many many i
mportant as you know Usb is spreaded also for Mass Storage Devices. And where there are large collection of data born the problem of Sensitive Information Protection
and consequently we have to consider the Forensics Attacks that could be performed.

Around here you can download many USB-Tracers / UsbSniffers, such as Usbtrace and SnoopyPro, which sets an UsbFilter Driver and are make you able dump the entire code transaction. Let’s take a look at the general architecture..

Every Device Sniffer is based upon Data Filtering, because we need obviously to have a Dynamic Capture System, so he only way is to dispose a Filter Driver, this is the case of our USB Sniffer.

So we need to provide a Filter PNP Filter Driver, this kind of driver can be coded in two different ways, the Classical one without using any Framework, or by using KMDF, which is more easy and fast to code (just you have to provide WdfFdoInitSetFilter during EvtDeviceAdd Event)

We will follow the first “old school” way.

As every Filter Driver we the skeleton is based on a DeviceEntry, Device Adding, Dispatching and Unloading, so let’s view in detail each one of them.

NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)

in this nothing special, but inside the Method we have to provide, an IRP stack filtering context, that can be stored into an lookaside list

ExInitializeNPagedLookasideList(
&g_ContextLookasideList, NULL, NULL, 0, sizeof(IRP_STACK_CONTEXT),
IRP_STACK_CONTEXT_TAG, 0 );

After defining our context, as usual there is the Dispatch Procedure creation, in the particular case of a PNP Filter are used:

DriverObject->MajorFunction[IRP_MJ_PNP] = FilterDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = FilterDispatchPower;
DriverObject->DriverExtension->AddDevice = FilterAddDevice;

Cause the presence of multiple DeviceObject, is also necessary a Mutex, to synchronize all threads:

ExInitializeFastMutex(&ControlMutex);

Now is time to Add our Filter, so let’s study FilterAddDevice:

NTSTATUS
FilterAddDevice(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT PhysicalDeviceObject
)
At this point we are dealing directly with the PnP system, we need to determine if we need to be in the driver stack for the device, and next we have to initialize this device object.

{

PDEVICE_EXTENSION deviceExtension;
ULONG deviceType = FILE_DEVICE_UNKNOWN;

deviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject);
deviceType = deviceObject->DeviceType;
ObDereferenceObject(deviceObject);

This because windows check if the filter attached to a storage device doesn’t specify the same DeviceType as the device that’s attempts to attach to it.

Now we can attach our Filter

IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
NULL, // No Name
deviceType,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);

Jump in the stack:

deviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack (deviceObject, PhysicalDeviceObject);

this is to define the supported I/O of our driver

deviceObject->Flags |= deviceExtension->LowerDeviceObject->Flags &
(DO_BUFFERED_IO | DO_DIRECT_IO |
DO_POWER_PAGABLE );

Device properties can be retrieved by calling

IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyPhysicalDeviceObjectName, 0,
NULL, &nameLength);

Essentially we need a copy (slighty modified) of Next Lower Device’s Driver Object (FDO) so all transactions will pass also on our device. These are the modifications

deviceExtension->ModifiedLowerDriverObject.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FdoHookDispatchInternalIoctl;
deviceExtension->ModifiedLowerDriverObject.MajorFunction[IRP_MJ_PNP] = FdoHookDispatchPnp;

and next we save our copy

InterlockedExchangePointer(
(PVOID * )&( (deviceExtension->LowerDeviceObject)->DriverObject ),
&deviceExtension->ModifiedLowerDriverObject
);

Now we can grab all IRPs with FilterDispatchAny

NTSTATUS
FilterDispatchAny (
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)

PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

if (irpStack->MajorFunction == IRP_MJ_PNP)
{
const char * MinorFunctionName = PnPMinorFunctionString(irpStack->MinorFunction);
if (MinorFunctionName != NULL)
LogTheCapturedIrp();

it’s important to remember that this is only a filter, so we don’t need to know ALL about data transactions, so unknown IRPs are delivered untouched.

NTSTATUS
FilterDispatchPnp (
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)

if( irpStack->MinorFunction == IRP_MN_QUERY_INTERFACE )
{
if( IsEqualGUIDAligned(
*irpStack->Parameters.QueryInterface.InterfaceType,
USB_BUS_INTERFACE_HUB_GUID
)
)
LogTheCapturedIrp();

with USB_BUS_INTERFACE_HUB_GUID we obtain the interface for USB Hub drivers

In the next post we will see the final part of the Filter Driver.

See you to the next post.. 🙂


On USB Driver #4

November 3, 2007

Hi,

As you’ve seen, there are a series of Configuration to accomplish in order to have a fully transactional USB Driver, now is the time on I/O Configuration which sounds also as IO Implementation. Essentially we have to implement a Device IO Control Handler, in other words a mechanism that for each IO Request provides a different procedure.

This is the procedure to send an IO Request (directly taken from Microsoft USB_WDF Documentation):

  • Create the request or use a request that the framework delivered.
  • Set up the memory objects and buffers for the request.
  • Format the request.
  • Set an I/O completion callback for the request, if appropriate.
  • Send the request.

Let’s consider an InGoing requests are processed troughout In/Out Endpoints, so everything you put into In-Endpoint are pulled out the Out-Endpoint, we have the called Double Buffered Mechanism.

VOID
EvtDeviceIoWrite(
IN WDFQUEUE  Queue,
IN WDFREQUEST  Request,
IN size_t  Length
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT devCtx = NULL;
WDFMEMORY requestMem;

devCtx = GetDeviceContext(WdfIoQueueGetDevice(Queue));

status = WdfRequestRetrieveInputMemory(Request, &requestMem);

status = WdfUsbTargetPipeFormatRequestForWrite(
devCtx->UsbBulkOutPipe,
Request,
requestMem,
NULL);

WdfRequestSetCompletionRoutine(Request,
EvtIoWriteComplete,
devCtx->UsbBulkOutPipe);

status = WdfRequestGetStatus(Request);
WdfRequestComplete(Request, status);

The EvtIoWriteComplete associated with our EvtDeviceIoWrite to fix unreferenced parameters as Context and Target.

Let’s se now an Asynchronous Read Request:

VOID EvtIoReadRequest(IN WDFQUEUE         Queue,
IN WDFREQUEST       Request,
IN size_t           Length
)
{
WDFUSBPIPE          pipe;
NTSTATUS            status;
WDFMEMORY           reqMemory;
PDEVICE_CONTEXT     pDeviceContext;

pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue));
pipe = pDeviceContext->BulkReadPipe;
status = WdfRequestRetrieveOutputMemory(Request, &reqMemory);
status = WdfUsbTargetPipeFormatRequestForRead(pipe,
Request,
reqMemory,
NULL // Offsets
);
WdfRequestSetCompletionRoutine( Request,
EvtRequestReadCompletionRoutine,
pipe
);
if (WdfRequestSend(Request,
WdfUsbTargetPipeGetIoTarget(pipe),
WDF_NO_SEND_OPTIONS) == FALSE) {
status = WdfRequestGetStatus(Request);
goto Exit;
}
Exit:
if (!NT_SUCCESS(status)) {
WdfRequestCompleteWithInformation(Request, status, 0);
}
return;
}

[Code is taken from USB_WDF.doc]

As you’ve seen from the code, the involved Functions are WdfRequestRetrieveOutputMemory, WdfUsbTargetPipeFormatRequestForRead and WdfUsbTargetPipeGetIoTarget, for the Reading Process.

For write request we have WdfUsbTargetPipeFormatRequestForWrite and WdfUsbTargetPipeWriteSynchronously.

Here some coding reference:

http://www.microsoft.com/whdc/driver/wdf/default.mspx
http://www.microsoft.com/whdc/driver/wdf/kmdf-arch.mspx
http://go.microsoft.com/fwlink/?LinkId=80613

http://go.microsoft.com/fwlink/?LinkId=80619

With this post, ends the pure theoretical part, next post will contains 1 or 2 downloadable source code drivers, and observations about USB Security.

See you to the next post.. 🙂

http://go.microsoft.com/fwlink/?LinkId=83355


On USB Driver #3

November 1, 2007

Hi,

As you can see from the previous posts, Usb Architecture is more complex that other Serial Interfaces, due to layerization and complex packet architecture, so is necessary to have a well organized Coding Framework, to avoid and mitiagate the coding difficulties.
To implement a basical USB Device Driver, you need The latest version of the WDF DDK, Version 1.1 of the KMDF, and for professionally intersted subject in USB Coding OSR USB-FX2 learning kit.

Common WDM functions are great for USB Coding, but is any case coder needs to implements complex mechanisms, that can lead to heavy performances/working problems of the driver you coded, so Microsoft provided with KMDF an Encapsulation mechanism, that make more easy the code implementation.

The Device Descriptor

As previously said, the first operation to access an USB Device is to fill the Device Descriptor, that contains between the other settings the Number of Configurations, this field in our case is 1, because WDF supports only one onfiguration. Each Configuration has a Descriptor, that mantains trace of all Active Interfaces, these interfaces can have alternate settings, in other words various Endpoints, but at least you need for each interface Endpoint0. Pay attention to the USB Device Specifications, because many devices does not supports Multiple Alternate Settings, and your driver will deadly BSOD.

Now let’s see how to Configure our USB Device:

NTSTATUS ConfigOurUsb(WDFDEVICE Device, PDEVICE_CONTEXT DeviceContext)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT pDeviceContext;
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS usbConfig;

status = WdfUsbTargetDeviceCreate(Device,
WDF_NO_OBJECT_ATTRIBUTES,
&DeviceContext->UsbDevice);

WdfUsbTargetDeviceCreate, takes as input parameters a handle to the device object and a pointer to a WDF_OBJECT_ATTRIBUTES structure and returns a handle to a WDFUSBDEVICE object, if Configuration goes ok, we can Select the Choised Configuration, we will use:

WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE

WdfUsbTargetDeviceSelectConfig, creates WDF USB interface and pipe objects, and returns information about the specified configuration. Is importanto to say that the configuration process is done by filling WDF_USB_DEVICE_SELECT_CONFIG_PARAMS structs (which have In and Out params). As you have seen we uses INIT_SINGLE_INTERFACE, but KMDF have various INIT_XXX pre setted configs, so you’ve only to choise the one you need. There are also other functions to get informations about Configuration:

WdfUsbTargetDeviceRetrieveConfigDescriptor
WdfUsbTargetDeviceGetDeviceDescriptor
WdfUsbTargetDeviceGetInterface

After Usb Configuration, we can proceed with Pipe Configuration:

The framework creates a pipe object for each pipe in the setting, and gets access for each pipe with WdfUsbInterfaceGetConfiguredPipe.

As said for each alternate setting there are one or more associated Endpoints, so our driver needs an Enumeration Procedure to identify and use these pipes:

NTSTATUS ConfigUsbPipe(PDEVICE_CONTEXT DeviceContext)
{

NTSTATUS status = STATUS_SUCCESS;
WDF_USB_PIPE_INFORMATION pipeInfo;
WDFUSBPIPE pipe = NULL;
UCHAR index;

for(index=0; index < numberConfiguredPipes; index++) {
WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
pipe = WdfUsbInterfaceGetConfiguredPipe( pDeviceContext->UsbInterface,
index, //PipeIndex,
&pipeInfo
);

if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) {
pDeviceContext->InterruptPipe = pipe;
}
if(WdfUsbPipeTypeBulk == pipeInfo.PipeType
&& WdfUsbTargetPipeIsInEndpoint(pipe)) {
pDeviceContext->BulkReadPipe = pipe;
}
if(WdfUsbPipeTypeBulk == pipeInfo.PipeType
&& WdfUsbTargetPipeIsOutEndpoint(pipe)) {
pDeviceContext->BulkWritePipe = pipe;
}
}

Obviously, the most important function in our case is, WdfUsbInterfaceGetConfiguredPipe(), the out Struct WDF_USB_PIPE_INFORMATION mantains trace of each Pipe Configuration.

Here finishes the third part of Usb Coding, in the next days I’ll complete the coding part (probably with a full working USB Driver, and finally a we will talk about Usb Forensics.

See you to the next post.. 🙂


On USB Driver #2

October 31, 2007

Hi,

In the previous post, we talked about the General USB Architecture, that as you have seen is not easy and Highly Hierarchical, you can read that as highly Layerized.

Before talking about the foundamentals of USB Coding, is important to spent some words about Usb Protocols (not deeply handled in the previous post).

USB protocols are different from the other common interfaces, are highly layerized, but we will work only with High Level Layers, Low Level are controlled by USB Controller.

Each USB Transaction consists of a:

  • Token Packet (Header defining what it expects to follow)
  • Optional Data Packet, (Containing the payload)
  • Status Packet (Used to acknowledge transactions and to provide a means of error correction)

The first packet ( Token Packet ) is generated by the Host Controller and will cointain vital informations about the data transaction such as Device Address, Endpoints. Second packet strictly linked to the first, cointains the Payload and is called Data Packet, and finally a Status Packet is sent, works as an Handshaking Packet.

.:: Anatomy of an USB Packet ::.

USB’s data is formatted in LSB, and foundamentally USB packet is consist of various fields:

  • SYNC (All packets must start with a sync field. The sync field is 8 bits long at low and full speed or 32 bits long for igh speed and is used to synchronise the clock of the receiver with that of the transmitter. The last two bits indicatehere the PID fields starts.)
  • PID (his field is used to identify the type of packet that is being sent), Values of PID can identify 4 kind of packets: Token, Data, Handshake, Special.
  • ADDR (The address field specifies which device the packet is designated for. Being 7 bits in length allows for 127 devices to be supported. Address 0 is not valid, as any device which is not yet assigned an address must respond to packets sent to address zero.)
  • ENDP ( The Endpoint, already defined in the previous post)
  • CRC ( A classical Anti Corruption Check)
  • EOP (End Of Packet)

This is the basical composition of an USB Packet, and as said 4 types of packets, each packet have more kind of Sub-Packets:

  • Token Packets
    • In
    • Out
    • Setup
  • Data Packets
    • Data0
    • Data1
  • Handshake Packets
    • ACK
    • NAK
    • STALL
  • Start of Frame Packets (often called SOF Packet)

As you have seen, USB protocol is complicated to code directly, but fortunately we have a series of Functions that manages from low level to transation level, and only things we need to know are the error codes. Each function will have a series of buffers, typically 8 bytes long, each buffer will belong to an endpoint – EPx In, EPx

Out (we have the following numeration EP0 In/Out, EP1 In/Out, etc) , these Endpoints can be described as sources or

sinks of data, so if we send a packet to our EP1 device we will deal with EP1 In and EP1 Out. In all cases we have to ensure the support for EP0, because it receives all foundamental data about Device Control/Status.

Effective data transfer is done by Pipes, that are Logical Connections between Host and Endpoints and have some Control Parameters as Bandwidth Allocation, Transfer Type.

We can have two kind of pipes:

  • Stream Pipes: Can be sent any type of data down a stream pipe and can retrieve the data out the other end, and can support Bulk, Isochronous and Interrupt Transfer Types.
  • Message Pipes: Data is transferred in the desired direction, and is a Bidirectional Channel.

Here finishes the Architectural part, in the next part we will talk about USB Coding, and finally about Usb Forensics..

Many thanks goes to BeyondLogic Corp. for the great USB’s Arch Summary.

See you to the next post.. 🙂


On USB Driver #1

October 21, 2007

Hi,

USB Driver Coding is considered out of here something of really mystic, and too many speculations to help developers has been done, someone implemented also his own USB Development Kit, causing a lot of confusion, I’ll try to explain how to move in the USB field 😉
Here a rapid explaination of USB Architecture:

Starting out new with USB can be quite daunting, USB 2.0 documentation is 650 pages long, full of ssociated

standards as USB Class Standards such as HID Class Specifications (Human Interface Devices), and unlike RS-232 USB protocol is made up of several layers of protocols.

USB specification defines four transfer/endpoint types:

  • Control Transfers (typically used for command and status operations)
  • Interrupt Transfers (as each microcontroller, Interrupt transfers are typically non-periodic, small device initiated” communication requiring bounded latency)
  • Isochronous Transfers (sochronous transfers occur continuously and periodically. They typically contain time sensitive information, such as an audio or video stream. If there were a delay or retry of data in an audio stream)
  • Bulk Transfers (Bulk transfers can be used for large bursty data, as for printers, scanners)

All USB devices have a hierarchy of descriptors which describe to the host information such as what the device is, who makes it, what version of USB it supports, most common USB Descriptors, are:

  • Device Descriptors (The device descriptor, specifies some basic, important informations such as the supported USB version, maximum packet size, vendor and product IDs)
  • Configuration Descriptors (USB Supports different configurations although the majority of devices are simple and only have one, this descriptor specifies how the device is powered, what the maximum power consumption is, thenumber of interfaces it has)
  • Interface Descriptors (The interface descriptor could be seen as a header or grouping of the endpoints into a functional group performing a single feature of the device)
  • Endpoint Descriptors (Endpoint descriptors are used to describe endpoints other than endpoint zero)
  • String Descriptors (String descriptors provide human readable information and are optional)

Every USB device must respond to Setup Packets on the default pipe. The setup packets are used for detection and configuration of the device and carry out common functions such as setting the USB device’s address, requesting a device descriptor or checking the status of a endpoint.

Enumeration is the process of determining what device has just been connected to the bus and what parameters it requires such as power consumption, number and type of endpoint(s), class of product etc. The host will then assign the device an address and enable a configuration allowing the device to transfer data on the bus.

As you can see, USB driver coding is not so easy, is necessary to know:

  • General USB driver issues
  • USB Interrupt handling
  • Read, write, and IO control operations
  • General power management issues
  • Device suspend and wakeup

Obviously the only best way to write a good usb driver is to use WDF and KMDF, here some good link:

USB

BeyondLogic

UsbDeveloper

UsbCentral

UsbInformation

See you to the next post.. 🙂