Monday, November 21, 2011

F12 Temptations


BIOS one-time boot menus are tempting, especially if you are a frequent forensics boot disc user like me.  I use boot discs to conduct preview examinations, something many people know as "device triage," and for imaging.  In fact, boot discs can be essential tools in certain device imaging scenarios (see Difficult Disk Imaging).  One-time boot menus make it easy to select alternate boot devices, like CD-ROM or USB, without wading into the BIOS settings.


I'm in the habit of accessing the BIOS, however, and not using the boot menu.  First, it gives me the opportunity to record the BIOS time settings and evaluate detected hardware, but also because one-time boot menus are not always clearly defined in startup messages.  They also vary from BIOS to BIOS, computer model to computer model, even from the same manufacturer!


But Dell does a good job of letting you know how to access their menu: F12.  And, there are a lot of Dell computers in the world.  And, let's admit it, its a lot easier to access the one-time boot menu (meaning, boot from a different device than default this time) than to access the BIOS Settings.  But, there is a very good reason not to be tempted by this Boot Device Nirvana, and I encountered it this weekend.

On Friday afternoon, I booted a Dell server with a Linux-based forensics boot disc.  It was a hardware-based stripped array.  After determining that the server had evidence on board, I chose to image it with Guymager.  The process was to take 8 hours, and I went home in the bliss of knowing that when I returned to work on Monday, my image would be waiting for me, along with a hash verification of the source drive (array).

What I discovered upon my return--both from an email and the condition of my equipment--is there had been a power failure during the imaging process.  Well, shortly after, in actuality.  But, the server had been set to reboot on power failure, and I failed to note that.  What I didn't fail to do, was change to boot order to ensure my book disc booted before the internal drives.  Therefore, the system was sitting at the boot disc OS desktop and not running the server!  In other words, no data had changed.  Had I used a one-time boot menu, this would not have been the case.

You might be thinking, "Well, it didn't really matter in this case, because the imaging process had completed."  To that I say, "Yes, you're right."  But, I didn't have a verified image, because, for an unknown reason, the hash digest of the source device did not match the hash digest of the data in the image.  However, because the server booted from the boot disc, and not the internal drives, I was able to hash the source device again and verify the data was the same in the image as on the drive!

Why did the Guymager source hash differ from the image and from my post-power failure verification?  I don't know.  But I had the opportunity to check the discrepancy, which is the point of this post.

Monday, August 1, 2011

Windows Link Files / Using While Loops

A colleague asked today about a tool to decode Microsoft Windows link files.  Before I begin to discuss the tool I recommended, I'll briefly describe Windows link files.  A Windows link file, commonly known as "shortcuts", has the .lnk extension.  It is basically a file with information about another file.  It is interpreted by the windows shell, and the shell opens the file pointed to by the link file if all goes well.  Link files can be user or system generated.  You can learn much more about Windows link files in the white paper by Harry Parsonage.

My favorite tool for parsing Windows link files was created by Jake Cunningham who posts tools he creates at the "JAFAT: Archive of Forensic Analysis Tools" website.  Jake has created some very well know Safari browser tools, but the tool that has caught my eye is "lnk-parse-1.0.pl".  The lnk-parse tool is a perl script that provides the most detail I have ever seen in a link file parser.  Here is some sample output:


Link File:  /WINDOWS/system32/config/systemprofile/Start Menu/Programs/Windows Media Player.lnk
Link Flags:  HAS SHELLIDLIST | POINTS TO FILE/DIR | HAS DESCRIPTION | HAS RELATIVE PATH STRING | NO WORKING DIRECTORY | HAS CMD LINE ARGS | NO CUSTOM ICON |
File Attributes: ARCHIVE
Create Time: Wed Jan 30 2008 05:36:33
Last Accessed time: Wed Jan 30 2008 05:39:37
Last Modified Time: Mon Jul 07 2003 05:00:00
Target Length: 520192
Icon Index: 0
ShowWnd: 1 SW_NORMAL
HotKey: 0
Target is on local volume
Volume Type: Fixed (Hard Disk)
Volume Serial: b0a65d8e
Vol Label: 
Base Path: C:\Program Files\Windows Media Player\wmplayer.exe
(App Path:) Remaining Path: 
Description: @%SystemRoot%\inf\unregmp2.exe,-155
Relative Path: ..\..\..\..\Program Files\Windows Media Player\wmplayer.exe
Command Line: /prefetch:1

Lnk-parse takes a single link file as an argument. But anyone who knows Windows knows there are usually hundreds of link files on a system. So, how does one quickly find all the link files in a Windows operating system using Linux tools? I'm going to avoid all the caveats, such a deleted files, renamed files, etc., and make the following assumption: The examiner is interested in allocated link files that have not been obfuscated by renaming or other anti-forensics techniques.

The fastest way to find the link files is to mount the Windows file system and search for link files by name. The search tool to use is the 'find' command. I'll discuss mounting in another post (I recently wrote a tool to read disk/forensic image partition tables an automatically mount all allocated filesystems), but here I want to show a how a simple while loop can make using commands like lnk-parser on multiple files easy.

The following command assumes it is being executed from the root of the Windows file system. Windows file system is a misnomer; I mean a file system in which the Windows operating system is installed.

$ find . -iname "*.lnk" | while read line; do lnk-parse-1.0.pl "$line"; done

I'll break that down by moving the major parts to their own lines:

find . -iname "*.lnk" | \  
while read line  
do 
    lnk-parse-1.0.pl "$line"  
done

Line by line:

  1. find, recursively from the current dir, all files ending with .lnk, regardless of case, and pipe the output to the while loop
  2. "while" there is output from the find command, read each line of output and assign the output (a file name and path) to the variable "line"
  3. a required argument in a while loop, essentially: "do" the following to $line
  4. process $line with lnk-parse-1.0.pl
  5. Finished with this loop cycle, return to while and get another line from "find", if any.

In 1.23 seconds, I processed all 103 link files in a small Windows XP system. I could pipe the output to a text file for a report, if necessary.

$ find . -iname "*.lnk" | while read line; do lnk-parse-1.0.pl "$line"; done > some_path/link_files.txt

I use while loops like this all the time. One gotcha of which to be aware is that variables, assigned within the while loop, don't survive outside of the while loop. I'll explain that sometime in the future, and provide some strategies on how to handle this. But for now, if you mimic this usage, you won't run into that issue, you'll save yourself a lot of work, and you'll increase your productivity tremendously.

Tuesday, July 26, 2011

BlackBerry Messenger / Google Talk for BlackBerry Save-files

My last post, "BlackBerry Text Message Parsing, AKA, Why I use Linux for Forensics," had unintended but pleasant consequences: it introduced me to BlackBerry forensics expert Shafik Punja.  I really wrote the post to comment on the versatility of the Linux operating system, and fortunately I erred in calling the file that was the subject of my discussion a "BlackBerry Text Message" save file, rather than the BlackBerry Messenger (BBM) save file that it was.

Shafik corrected me and taught me a bit more about the file type that I'll share here in the event that you missed his comments.  BBM messenger does not save message content by default.  It is a user selected option, and only available in BBM v5 and higher.  The files can be saved to the device's internal memory or an installed memory card.  Google Talk has the same save options and defaults as BBM, and also saves in the same basic format.

Shafik asked if I could write a program to parse the files.  I agreed and quickly converted the basic Bash script in my last post to a more complete program.  However, when Shafik tried to run the program in OS X, it failed because OS X and Linux do not utilize the same 'date' command.  I was faced with writing a new program for use in OS X, which I wished to support, or make my current script intelligently determine the OS in which it was running and apply the correct date command syntax.

Nothing seems like a bigger waste to me than to write essentially the same thing twice.  Isn't there a way to write a program that doesn't have to be altered based on the operating system in which it is run, I asked?  Then a little Australian-accented voice of reason reached my conscious thought: why don't you learn python?  For the millionth time: Thank you Michael, good idea.

Michael Cohen, a software engineer at Google and author/maintainer of pyFLAG, AFF4,  and other tools soon to be released, has suggest many times over that I learn python, but I only recently started to do so.  Python is an excellent solution for cross platform programs, and I decided it was time to start.

The BBM / GTalk file format

BBM and GTalk save files are CSV text files with the following basic structure:
Application Name, version[newline]
DateCode, "Sender_ID", "Receiver_ID", Message[newline]
...

The first line of the file is the source application and the application version, separated by a comma. The version is followed by a newline control code.

The remaining lines are formatted thus: the line starts with a DateCode consisting of a 21 digit number. The first 8 digits are the date of the sent message rendered as YYYYMMDD. The remaining 13 digits are Unix epoch time, rendered in milliseconds. In the case of BBM, the sender Hex_ID follows the DateCode, separated by a comma and encapsulated in parenthesis. Similarly, the receiver's Hex_ID follows. For GTalk, the sender and receiver are identified by Google Account ID. Finally, the message, in text, is stored followed by a newline control code.

One minor issue in rendering the file in a spreadsheet centers on the message field. Messages are not encapsulated in commas; therefore, messages with commas will not format well in spreadsheets without additional spreadsheet configuration. This might not be a problem for one file, but would be a major annoyance for many files (one of my colleagues found 23 BBM save files on an SD card). I determined to encapsulate the message field in quotes to overcome this issue.

The python3 code I settled on follows:
import sys
from time import strftime, localtime

def main(csv):
    line_no = 0
    with open(csv) as db_file:
        for line in db_file:
            if line_no == 0:
                print(line)
                print('Date,DateCode,Sender,Receiver,Message')
                line_no += 1
            else:
                datecode, sender, receiver, message = line.split(',', 3)
                date = int(datecode[8:18])
                date = strftime('%Y-%m-%d %H:%M:%S (%Z)', localtime(date))
                print('"{}",{},"{}","{}","{}"'.format(date, datecode, sender, receiver, message.strip()))

if __name__ == '__main__':
    for file in sys.argv[1:]:
        main(file)

I won't try to explain all the code here, because with my rudimentary knowledge of python, I'm likely to misspeak. I will highlight a couple parts of the script and a couple of nice python features, however. First, the "if" condition in line 8 is present to skip over date decoding in the first line of the file. Instead, it prints the line, and adds a line of column headers to help with interpreting the remaining message data.

Line 13 demonstrates a very nice python feature: multiple value assignment. Here, I assign data from line 2 and higher, one line at a time (note the 'for' loop) to the datecode, sender, receiver, and message objects. To work correctly, however, there needs to be four values to assign to the four objects. The split method divides a string object into a list of strings based on a delimiter. Here, I configure split to divide on commas a maximum of three times. This creates a list of four strings. Remaining commas are ignored and included in the last string, which here is assigned to 'message'.

Line 14 converts the 'datecode' string to an integer, and line 15 uses the 'strftime' and 'localtime' functions from the 'time' module to convert the Unix epoch time embedded in the datecode to a human-readable format. I use string slicing, that is, selecting a portion of the datecode string by its position in the string (also called indexing where the starting position is 0), to extract the 10 digits that represent the Unix epoch value. The last three digits of the datecode are ignored since they represent milliseconds.

The final line of which to take note is Line 16, where a few things of import are occurring. First, the interpreted datecode is printed. The original datecode follows for reference and validation purposes, and then the remainder of the line. A format method is applied that replaces the brackets place holders in the print string with the objects that are arguments of the format method. Here, the message object is encapsulated in quotes. Also, the message object has the strip method applied to remove the newline control code at the end of each message to improve formatting.

Though I won't comment on it, I'll include the bash script I wrote first for comparison:
line_no=0 #set counter

cat $1 | while read line
do
    if [ $line_no -eq 0 ]
    then
        echo ${i}  #print first line unaltered
        echo "Date,DateCode,Sender,Receiver,Message"
        line_no=1
    else
        for var in date sent rcvd message
        do
            eval $var="\${line%%,*}"
            [[ "$var" = "message" ]] && message=$line #ignore commas in message
            line="${line#*,}"
        done
        date=$(date +"%Y-%m-%d %H:%M:%S (%Z)" -d @${date:8:10}) #convert date code and store
        len=$((${#message}-1)) #subtract 1 from remainder length for stripping newline control code
        echo "\"$date\",\"$sent\",\"$rcvd\",\"${message:0:$len}\""
    fi
done

Thursday, July 21, 2011

BlackBerry Text Message Parsing, AKA, Why I use Linux for Forensics

A little detour from my usual posts to explain why I use Linux for forensics, though my upbringing was in Windows-based tools like EnCase.  A colleague contacted me today with a little issue: He had found a BlackBerry text messaging backup file in CSV format (EDIT: This was actually a BlackBerry Messenger save file) on an external memory card, but the date code for each message was perplexing.  He asked me if I could help in interpret the code.  It looked like the following:
201010181287467321760
The full format of the CSV was "date, from(hexID), to(hexID), message."  It was obvious to my colleague and me that the first 8 digits of the date code was the date of the message in plain text, i.e., "20101018" or "2010-10-18."  My Unix roots made the remaining digits of the numeric string easy to identify: unixepoch in milliseconds, i.e., 1287467321760 milliseconds since 1-1-1970 00:00:00.

A quick verification with the date command, but truncating the date at seconds (i.e., dividing by 1000):
$ date -d @1287467321
Mon Oct 18 22:48:41 PDT 2010

The converted unixepoch date matches the plain text date. We seem to have interpreted the code correctly, and now we know the local time of the message as well.

But of course, using the date command is not why I find Linux so valuable.  It because of the ease with which I was able to convert the whole file, having discovered the meaning of the date code.  Remember the format of the file?  It was "date, from(hexID), to(hexID), message."

Consider three lines from the file as an example:
201010181287467321760,"6C31FB2C","0F315216",Hey
201010191287534544913, Oct 19 17:29:04 PDT 2010,"6C31FB2C","0F315216",Hey, you there?
201010191287534602157,"0F315216","6C31FB2C",Yeah, let's meet.

A quick, simple while loop to read each line of the Messenger save file,
$ cat backup.csv | while read line; do date=${line%%,*}; remainder=${line#*,}; echo "$(date -d @${date:8:10}),$remainder"; done
Mon Oct 18 22:48:41 PDT 2010,"6C31FB2C","0F315216",Hey
Tue Oct 19 17:29:04 PDT 2010,"6C31FB2C","0F315216",Hey, you there?
Tue Oct 19 17:30:02 PDT 2010,"0F315216","6C31FB2C",Yeah, let's meet.
...

Let me break that down:
cat backup.csv | while read line  #read a line of the file, assign to variable 'line'
do
  date=${line%%,*}  #read everything up to the first comma, assign to variable 'date'
  remainder=${line#*,}  #read everything beyond the first comma, assign to variable 'remainder'
  echo "$(date -d @${date:8:10}),$remainder" #convert digits 9-18 to local time, print localtime and the remainder of the line to stdout
done

The key to this solution is something I didn't learn in my initial studies of Bash, but I make extensive use of it now: variable expansion. I use the various expansions available in Bash 4 to assign portions each line to variables that I could then operate on and print the result. I won't discuss all available expansions here, but I will explain those I used:

Removing the longest match from the end:

Consider: Each line contained comma separated values. I really only needed to operated on the first value -- the date code. I prefer, as much as possible, to not call external tools, such as cut or awk, so as to not unnecessarily start external processes. Bash variable expansion makes this possible. The syntax ${var%%PATTERN} will remove the longest match to PATTERN from the variable 'var'.

So, in line 3, date=${line%%,*} assigns to the 'date' variable all of the contents of the 'line' variable up to the first comma. Thus, in the case of the first line, date="201010181287467321760".

Removing the shortest match from the beginning:

With the date code isolated in the 'date' variable, we still need to print the rest of the line once we convert the date. The syntax ${var#PATTERN} will remove the shortest match to PATTERN from the variable 'var'.

So, in line 4, remainder=${line#*,} assigns to the 'remainder' variable all of the contents of the 'line' variable after the first comma. Thus, in the case of the first line, remainder=""6C31FB2C","0F315216",Hey"

Returning a substring of a variable:

Finally, we need to isolate the unix epoch time from the plain text date in the date code now stored in the variable 'date'. We do this by indexing. The syntax ${var:OFFSET:LENGTH} will return a substring of the variable 'var' starting at OFFSET for the specified LENGTH. The first character in a variable is indexed at offset 0.

So, in line 5, ${date:8:10} returns 10 characters of the variable 'date' starting at the 9th character (remember, indexing starts at 0). Thus, we have now fed the unix epoch date string incorporated in the Messenger date code to the unix date command to be converted to local time in a human readable format.

Line five is a complex command, that indexes the 'date' variable, converts it in a sub-process with the date command, and then echo the result with the contents of the 'remainder' variable appended.

Where to go from here:

If you have some Bash skills, but want to advance them, I recommend the book "Pro Bash Programming: Scripting the GNU/Linux Shell" by Chris F.A. Johnson from Apress.

Tuesday, July 19, 2011

Mounting Split Raw Images

A raw image, made with dd or a variant, is still a common image format, and will not go away soon even as many argue the benefits of forensic images such as the Expert Witness Format (supplied through libewf) and the Advanced Forensic Format (supplied through afflib).  But raw images can be difficult to tote around because they are bit for bit copies which makes the copy as large as the original.  As such, the images are often split to fit on external media such as DVD.

But splitting, while solving storage problems, creates a new problem.  What if you want to mount the image for examination?  True, Sleuthkit can handle the examination of split raw images, but sometimes there is no equal to simply mounting an image during an examination.

Let me illustrate using a situation I encountered yesterday.  A colleague had a split raw image of over 200 segments that he wished to mount and then boot in a virtual machine.  He tried to follow my tutorial  but was unsuccessful, uncertain as to why.  When I looked into the situation with him, the issue became clear: xmount, the tool used to create a virtual disk from a disk image, was only mounting the first segment of the split raw image, despite being given all the segments as arguments as is required with Expert Witness Format images.  More simply put, xmount does not handle split raw images.  It will handle a single raw image file just fine, however.

What to do?  One could simply cat the files together, but that means doubling storage requirements, at least until the concatenation operation is concluded.  That might not be feasible or desirable, and it can be very time consuming.  In this case, we were talking 300 GB of data.  It would be great to be able to treat the segments as one file, and pass that file to xmount to accomplish the purpose.

Affuse to the rescue!  Affuse is part of the afflib tool suite.  It creates a virtual file system using fuse and mounts it to a location you specify.  You only pass the first segment of the split image as an argument.  The command takes the form:

# affuse image mount_point

Affuse creates an image.raw file (that is, the name of the segment with '.raw' appended)  in the mount point along with a log file.  Yes, its that easy.

To finish the scenario, xmount can then take the image.raw file as an argument to create the virtual disk, thusly:

# xmount --in dd --out vdi --cache image.cache mount_point/image.raw new_mount_point/

This command tells xmount that the input file, image.raw, is raw data, the output desired is a VirtualBox vdi format, that a cache file called "image.cache" is desired to store system changes when the virtual machine is running.  The .vdi file will be mounted in the "new_mount_point" directory.  If xmount is unfamiliar to you, I recommend you read my previous post.

Like affuse, xmount utilizes the fuse file system.  Both utilities accept fuse file system arguments as well as tool specific arguments, so read only mounting and permissions options exist (type "man fuse" at the command line for more details).  As always, practice on non-case data to become familiar with the tools.

Time Perspective

Telling time in forensic computing can be complicated. User interfaces hide the complexity, usually displaying time stamps in a human reada...