November 12, 2003

DevCon:Common Driver Security Bugs

Well, we are currently into the session I came to see.

The presentor is a software engineer with the Kernel platform group, and he really knows his stuff. Unfortunately, his presentation skills seems kinda boring/dry, and he is second guessing himself. I think he would be more interesting if he used some good examples/stories to go along with the presentation. And it doesn't help when he has glaring errors in the slides. Poor guy. Atleast he caught it himself before we said anything.

Besides the normal arithmetic over/under flows, buffer overflows, and the like, he is showing some interesting things you don't normally think about, including neat ways to watch for alignment issues(which can bugcheck).

Some notes:

  • Any kernel copy (RtlCopyMemory etc) of untrusted data must be fully verified
  • Length check all buffers
  • Handle arithmetic over/underflow, negate (2s compliment), Zero size, divide by zero
  • Avoid race conditions.
  • Do not use try/except blocks when you don't need to. This should only be around access of user-mode address space
  • Verify alignment. x86 in't a big problem, but on 64-bit CPU it will crash!
  • Lock/guard data to ensure state doesn't change
  • Don't double fetch data. Malicious intent may take advantage of this data change
  • Usermode address space is the MOST untrusted area of data
  • Do not touch user memory at elevated IRQL
  • If you need to create a HANDLE, make sure you use OBJ_KERNEL_HANDLE flag in HandleAttributes (ie: ObOpenObjectPointer() ) so the user can not modify/manipulate the handle
  • Watch for information disclosure issues in which user mode can read a handle of a kernel mode driver
  • Use actual AccessMode in IRP->RequestorMode when calling ObReferenceObjectByHandle(), not explicit KernelMode. You may circumvent access checks
  • Do not confuse handles with objects. The Object you have won't go away, but the handle could!
  • Kernel handles are trusted, where user mode are not. Make sure you pass OBJ_KERNEL_HANDLE to InitalizeObjectAttributes()
  • Never pass a user mode handle to ObRef with KernelMode
  • Handles can be duplicated across processes!
  • Wrapping a possible NULL pointer exception in a try/except block HIDES a potential security bug from being found. It is safer to fail and BSOD then to simply let it pass in the except block.
  • Don't rely/trust on name or process ID. Do proper access checks.
  • Watch for zero length or MaximumLength of UNICODE_STRING
  • Watch for buffer underrun when trying to null terminate a UNICODE_STRING (str.Buffer[str.MaximumLength/2) -1] = L'\0'; // WRONG)
  • Watch for odd length UNICODE_STRING (ie: if( str.MaximumLength & 0x1 ) { bail } )

When its all summed up, basically the most dangerous habits are:

  • Untrusted pointers
  • Usermode address space
  • Shared view with usermode address space
  • Complex buffer structures, even if buffered. K.I.S.S.
  • Usermode handles
  • Zw API's (Their previous mode was KernelMode, so it will pass access checks unless you force it with the right flag)
  • Opening objects by "name"
  • Error paths. Make sure all error paths clean up properly.
  • Don't assume that a null pointer derefence causes an access violation and can be caught in a try/except block. A hacker will just map to the 0 based address
  • Returning a kernel address as a context could be dangerous
  • Use the driver verifier and associated tools, but don't trust them to find all your bugs

Posted by SilverStr at November 12, 2003 03:36 PM | TrackBack