Friday, May 1, 2015

On the Forensic Trail - Master Boot Record (MBR)

[This is the 2nd in a multi-part series titled "On the Forensic Trail".  My goal with this series is to introduce my PowerShell Forensics module called PowerForensics, and the forensic artifacts that it parses.  This post covers the Master Boot Record, a disk structure that describes the logical layout of the disk in the form of partitions, and how to use PowerForensics to inspect it.]

For help with downloading/installing PowerForensics please visit the Installing PowerForensics article.

Master Boot Record is the name given to the first sector (typically 512 bytes) of a physical disk. Technet states that the MBR is "the most important data structure on the disk".  The MBR itself contains boot code, a disk signature, the partition table, and an end of sector marker which is always 0x55AA.

For a detailed breakdown of the MBR please see the poster above.

Windows Boot Order
Before diving into the MBR's boot code, it is important to review the boot order for Windows Operating Systems.

1.  The BIOS and CPU initiate the Power-on self-test (POST)
2.  The BIOS searches for a boot device (HDD, Floppy, CD, etc.)
3.  The BIOS reads the first sector of the device (Master Boot Record) into memory, and transfers CPU execution to that memory address.

Now that we have covered the boot process, lets look at what happens once the CPU transfers execution to the MBR.

Boot Code
The goal of the Master Boot Record's boot code is to find the bootable partition and transfer execution to it.  To find the bootable partition the following checks must occur:

1.  Search for an active partition (where the partition status is 0x80 or "Bootable")
2.  Checks that no other partitions are marked as bootable
3.  If partition is the only bootable partition, then the boot code will read the partition's Volume Boot Record (first sector, 512 bytes, of the partition) and transfer CPU execution to that memory address.
4.  The VBR is checked for the proper end signature (0xAA55).

If steps 2 - 4 fail then an execution is halted and an error message is displayed.  Below are the error messages for each step.

Step 2: If another partition is marked as bootable, the message "Invalid partition table" is displayed.
Step 3: If there is a problem loading the VBR, the message "Error loading operating system" is displayed.
Step 4: If the end signature is not present, the message "Missing operating system" is displayed.

Now that the we have covered how the boot code interacts with the partition table, lets talk about the structure of the partition table and its entries.

Partition Table
The partition table is a 64 byte structure made up of 4 0x10 (16) byte partition entries. The fixed size of the partition table limits the OS to 4 partitions, but modern OS have built in the capability for many more partitions through a concept called extended partitions.

Below I will cover the important values contained within a partition entry.

Partition Status
The 1st byte in every partition entry represents the Partition Status (whether the partition is bootable or not).  The Partition Status field has two acceptable values, these values are 0x00 (Non-Bootable) and 0x80 (Bootable).

It is important to note that only one partition can be marked as bootable per disk.  If this condition is not met, the "Invalid partition table" error will be thrown by the boot code.

Partition Types

The 5th byte of the partition table represents the type of file system the partition is using.  A list of partition type ids can be found here.  This value helps the operating system determine which file system device driver to load on startup.

It is worth noting that NTFS partitions will have an id of 0x07.

Cylinder Head Sector (CHS) Addressing
The operating system uses Cylinder Head Sector (CHS) Addressing to determine the location of the volume.  Bytes 2 - 4 and 6 - 8 represent the volume start address and end address respectively. The three bytes representing the CHS address are broken up such that the cylinder value is 10 bits, the head value is 8 bits, and the sector value is 6 bits.  Since disks are formatted with 512 byte sectors this addressing scheme only allows for a maximum addressable size of 7.8 GB.  As hard drive sizes increased, Logical Block Addressing (LBA) was introduced allowing much larger address ranges.

Partition Location
Most modern disks use the "Relative Starting Sector" and "Total Sectors" values to determine the location of volumes.  Each of these values are 4 bytes in size, and this allows for a maximum addressable size of right around 2 TB.

This limit is only exceeded by the introduction of the Guid Partition Table (GPT), which I will write about at a future date.


MBR boot code executes before the Operating System is loaded, and thus executes in Ring 0 without the normal Operating System protections.  This fact makes the MBR a viable location for malicious code in the form of bootkits.  I have begun research to identify a hash value for the MBR code section for a number of Windows operating systems and popular unix boot loader LILO and GRUB.  These hash values/signatures should help identify when the code section of the MBR has been tampered with, which could lead to bootkit detection.

NOTE: I admit this is not a full featured solution as a bootkit could easily detect disk IO and return false data, but at this time there are only a few publicly release bootkits that have been found to do this. 

PowerForensics Cmdlets
PowerForensics currently has two cmdlets that deal specifically with the MBR.  This portion of the post will explain the cmdlets and go through a few example use cases.

Get-MBR is a cmdlet that parses the Master Boot Record data structure contained within the first sector of the device specified.  Get-MBR requires the use of the -Path parameter which takes the Win32 Device Namespace (ex. \\.\PHYSICALDRIVE0) for the device from which the MBR should be parsed.

InvokeIR.PowerForensics.MasterBootRecord Object
The output of Get-MBR is a InvokeIR.PowerForensics.MasterBootRecord object.  The MasterBootRecord object has four readonly properties:

1)  DiskSignature - the 4 byte hex value that identifies the disk to the operating system
2)  BootCode - a byte array of the MBR boot code
3)  MBRSignature - a string representing the signature associated with the BootCode byte array (The 4)  MBRCodeArea is hashed and compared to a list of known MBR code signatures, benign and malicious. The string identifies which, if any, signature the BootCode matches).
5)  PartitionTable - an array of InvokeIR.PowerForensics.PartitionEntry objects

Below is an example of Get-MBR being run against \\.\PHYSICALDRIVE0 and being asked to return all properties (by default Get-MBR only returns MBRSignature and DiskSignature to console).

InvokeIR.PowerForensics.PartitionEntry Object
The InvokeIR.PowerForensics.PartitionEntry object represents an entry in the MBR partition table.  Each PartitionEntry object has four readonly properties:

1)  Bootable - a bool indicating whether the partition is bootable
2)  StartSector - the offset from the beginning of the disk to the beginning of the volume counting by sectors
3)  EndSector - the offset from the beginning of the disk to the end of the volume counting by sectors
4)  SystemID - a string defining the volume type (NTFS, FAT, etc.)

Here I am using the Select-Object cmdlet to expand the PartitionTable property of the MasterBootRecord object.

Introducing the -AsBytes Switch Parameter
While developing PowerForensics I wanted to make each cmdlet as flexible as possible.  I realized that returning the raw bytes for a data structure may be just as appealing as returning an object representing the data structure.  With this in mind, I have added a switch parameter to each cmdlet that parses a data structure called -AsBytes.  When the -AsBytes parameter is used, the cmdlet returns the raw bytes representing the structure instead of the expected object.

Below is an example of Get-MBR being used with the -AsBytes switch parameter.  In this example, I passed the output to Lee Holmes' Format-Hex cmdlet.

This example shows the -AsBytes switch parameter to save the MBR data structure's raw bytes to a file.

The Get-PartitionTable cmdlet is functionally the same as Get-MBR, but instead of returning an MBR object it returns an array of non-empty PartitionEntry objects.

Future Work
Currently PowerForensics does not have support for extended partitions or the UEFI Guid Partition Table (GPT).  I plan on adding support for these structures in the very near future.

My next post will break down the GUID Partition Table (GPT), which is a newer alternative to the Master Boot Record.


- Invoke-IR - By Jared Atkinson -