Author Archives: Hal Pomeranz

Independent IT/InfoSec Consultant, SANS Institute Faculty Fellow

Fun with FIFOs (Part II): Output Splitting

0
Filed under Computer Forensics, Evidence Analysis

Hal Pomeranz, Deer Run Associates

Several months ago now, I wrote up a little article on using FIFOs to trick the script command into writing output over the network.  But there are other neat hacks you can do with FIFOs, and I want to show you one right now that can save you lots of time.

Suppose you had a disk image and you wanted to pull out both the ASCII and Unicode strings from a specific partition.  The classic approach is to read the partition twice– once to gather the ASCII strings and once to pull out the Unicode.  But on a large partition, reading the image even once can take a huge amount of time.  The good news is we can use some Unix FIFO magic along with the frequently overlooked tee command and only have to read the partition once.

Let me show you the magic incantation first, and then explain what’s happening:

$ mkfifo part-output
$ strings -a -t d -e l <part-output >strings.uni &
[1] 23281
$ dd if=drive-image.dd bs=512 skip=273168 count=160587 | \
          tee part-output | strings -a -t d >strings.ascii
160587+0 records in
160587+0 records out
82220544 bytes (82 MB) copied, 2.82945 s, 29.1 MB/s

My first command is simply creating  a FIFO object called “part-output”.  You can call this FIFO anything you want and put it in any directory you want– the naming convention is completely irrelevant.

Next I run the strings command which is going to dump out our Unicode strings (see the “-e l” on the command-line? that’s how you tell strings to look for Unicode).  I tell it to read it’s input from the part-output FIFO (”<part-output”) and write the strings to a file called strings.uni (”>strings.uni”).  The trailing ampersand (”&”) tells the command shell to run this process in the background so I get my command prompt back.  But nothing is going to start happening with this process until I start putting data into the FIFO.

Putting data into the FIFO is the magic on the next line.  First I’m using dd to carve a particular partition out of my disk image and send the data to the standard output (see my recent article on manipulating disk images for more information on where this dd command-line comes from).  I send that output to the tee command, which is a simple utility that reads data on the standard input and writes that data both to the standard output and to a file simultaneously.  Think of it like a “T-joint” (hence the name “tee”) in your plumbing or your ductwork: one input, two outputs.  The problem is that one of those outputs has to be a file, which is where our FIFO comes in handy.

In this case, I tell tee to write the data into our FIFO instead of a regular file.  All of this data is then read by the strings command we set up with the previous command to read the FIFO and output the Unicode strings.  As for the other output channel from tee– the standard output– I just pipe that into another strings command which dumps out the ASCII strings.  The tee command ensures both strings commands get the same input, and I get to extract both types of strings simultaneously.  This means I only have to read through the partition once to get all the data I need.  And that’s a huge time-saver.

Now I only needed to split the output into two streams for this example, but there’s nothing that says you couldn’t create multiple FIFOs and use multiple tee commands to accomplish further splitting.  As a silly example, let me simultaneously create the two strings files and compute an MD5 checksum over the partition data using three output streams:

$ mkfifo str-uni
$ strings -a -t d -e l <str-uni >strings.uni &
[1] 23724
$ mkfifo str-asc
$ strings -a -t d <str-asc >strings.asc &
[2] 23727
$ dd if=drive-image.dd bs=512 skip=273168 count=160587 | \
        tee str-uni | tee str-asc | md5sum
160587+0 records in
160587+0 records out
82220544 bytes (82 MB) copied, 2.71264 s, 30.3 MB/s
efafa128fa2f8ab0544b633c33f28559  -

First I create FIFOs named “str-uni” and “str-asc” and run a strings command against each FIFO to extract the different types of strings.  We then run the dd command as before and pipe the output into tee which writes to one of the FIFOs we created above.  But the standard output of the first tee goes into the input of a second tee command which writes to the other FIFO.  The output of the second tee command gets fed into md5sum so we can get our checksum value (you can see it on the last line of output after the output from dd).

Keep stacking up FIFOs and tee commands and you can split your output into an arbitrary number of streams.  Ultimately, of course, the CPU load of all the processing you’re doing will set a limit on this.  But if you’ve got a multi-core CPU, you’ve probably got more than enough processing power for typical tasks.

Anyway, the short summary is that FIFOs can save time and let you do lots of cool things you never thought you could do.  It’s a shame more people don’t know about them.  But the good news is that this lack of understanding in the general population makes you look like a big-time guru when you pull tricks like this out of your bag.

Hal Pomeranz, GCFA, is an Independent IT/Security Consultant and a SANS Institute Faculty Fellow.  He will also never be a rich man, since he has apparently failed to grasp the fact that saving time is not a virtue when one is charging clients by the hour.  Hal will be teaching Security 508: Computer Forensics, Investigation, and Response at SANS Virginia Beach, May 24-29.

Using Image Offsets

Comments Off
Filed under Computer Forensics, Evidence Analysis

Hal Pomeranz, Deer Run Associates

One of the basic techniques we teach in SANS Forensic classes is “carving” out partition images from complete raw disk images.  All it takes is a little facility with mmls and dd.  Here’s a quick example of carving an NTFS partition out of a disk image to show you what I mean:

$ mmls -t dos drive-image.dd
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

     Slot    Start        End          Length       Description
00:  -----   0000000000   0000000000   0000000001   Primary Table (#0)
01:  -----   0000000001   0000000062   0000000062   Unallocated
02:  00:00   0000000063   0000064259   0000064197   DOS FAT12 (0x01)
03:  00:01   0000064260   0000273104   0000208845   DOS Extended (0x05)
04:  -----   0000064260   0000064260   0000000001   Extended Table (#1)
05:  -----   0000064261   0000064322   0000000062   Unallocated
06:  01:00   0000064323   0000273104   0000208782   DOS FAT16 (0x06)
07:  01:01   0000273105   0000433754   0000160650   DOS Extended (0x05)
08:  -----   0000273105   0000273105   0000000001   Extended Table (#2)
09:  -----   0000273106   0000273167   0000000062   Unallocated
10:  02:00   0000273168   0000433754   0000160587   NTFS (0x07)
11:  02:01   0000433755   0000481949   0000048195   DOS Extended (0x05)
12:  -----   0000433755   0000433755   0000000001   Extended Table (#3)
13:  -----   0000433756   0000433817   0000000062   Unallocated
14:  03:00   0000433818   0000481949   0000048132   Linux (0x83)
15:  03:01   0000481950   0000626534   0000144585   DOS Extended (0x05)
16:  -----   0000481950   0000481950   0000000001   Extended Table (#4)
17:  -----   0000481951   0000482012   0000000062   Unallocated
18:  04:00   0000482013   0000626534   0000144522   Linux Swap / Solaris x86 (0x82)
19:  -----   0000626535   0000629143   0000002609   Unallocated
$ dd if=drive-image.dd of=ntfs.img bs=512 skip=273168 count=160587
160587+0 records in
160587+0 records out
82220544 bytes (82 MB) copied, 2.28871 s, 35.9 MB/s

The bs=, skip=, and count= values are taken directly from the mmls output.  The “skip=” value corresponds to the “Start” of the partition and “count=” should be the “Length”.  And near the top of the mmls output you see “Units are in 512-byte sectors”, so that’s our “bs=” value.

Mostly we teach partition carving to get students up to speed with reading partition tables and manipulating various options of the dd command.  The only real-world problem is that as disk drives get larger, the time it takes to simply image the drive is really slowing down forensic investigations.  If you then have to go back and carve out each individual partition– effectively re-reading the nearly the entire drive– you’re doubling the time it takes you just to get started with your forensicating, as well as burning all that additional disk space for the partition images.  Fortunately there’s a better approach.

Most common forensic tools have some sort of option for specifying a byte or sector offset in a disk image so that you don’t actually have to carve out each individual partition.  The trick is usually just having to remember which tools want byte offsets and which want sector offsets, but that’s what help texts and manual pages are for.  There are some tools that don’t have an offset option, but there are work-arounds here as well.  Let me give you a few practical examples.

The Sleuthkit Tools

All of the core Sleuthkit tools have a “-o” option for specifying a sector offset in a disk image file.  Since the offsets are specified in sectors, you can just use the “Start” values from the mmls output.  For example, let’s use fsstat to get some basic information about the Linux partition in our disk image:

$ fsstat -o 433818 drive-image.dd
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext2
Volume Name:
Volume ID: 8c05a8859c81c2978427d205e60531e

Last Written at: Sat Sep 23 14:09:29 2006
Last Checked at: Sat Sep 23 14:09:28 2006
[...]

Or perhaps you’d like to use foremost to carve files out of the free blocks in the NTFS partition.  Like fsstat, blkls has a “-o” option, and foremost accepts image data on the standard input, so you can easily set up a command like:

$ blkls -o 273168 | foremost -o ntfs-carved-files -q -v

I’m sure you get the idea at this point, so I won’t waste time going through the other Sleuthkit tools individually.  Let’s move on to some more interesting examples.

Mounting File Systems

As somebody who primarily works in the Linux environment, mounting read-only copies of partition images to loopback devices is one of my most heavily used forensic tools.  It turns out that the mount command also has an “offset” option so that you can operate on partitions within a full disk image.  The trick is that mount wants you to specify the offset in terms of bytes rather than sectors.  But this is no big deal, it just means we need to do a little math first.

Let me show you how I’d go about mounting the NTFS partition from our disk image:

$ expr 273168 \* 512
139862016
$ sudo mount -t ntfs-3g -o ro,loop,show_sys_files,offset=139862016 drive-image.dd /mnt/ntfs

First I’m multiplying the “Start” value from our mmls output by the sector size to get the byte offset of the start of the partition.  Then all I have to do is use the resulting value after “offset=” in the mount options and I’m golden.  All of the other options and mount arguments are exactly the same as if you were mounting a partition image that you’d carved out manually.  You have to be root to use the mount command, so here I’m using sudo to get temporary root privileges for myself.

Other Tools

Some other common forensic tools you might want to use may not support an option to specify a partition at a specific byte offset.  For example, you might want to use strings to extract the ASCII string data from the Linux swap partition in our disk image.  But strings (or srch_strings if you prefer) have no way of selecting a single partition from our disk image.

However, you can simply use dd to “read” the partition image and then just pipe the output into strings:

$ dd if=drive-image.dd bs=512 skip=482013 count=144522 | strings -a -t d >linux-swap.ascii.str
144522+0 records in
144522+0 records out
73995264 bytes (74 MB) copied, 2.27807 s, 32.5 MB/s

You could say this is “cheating” since I’m really using dd to carve the partition image.  But at least I don’t need to store the partition image on disk anywhere– just pipe it into the standard input of strings.  Since most Unix/Linux commands will happily operate on data coming in via the standard input, this technique is broadly applicable across a wide variety of tools.

Conclusion

Using byte offsets rather than carving file system partitions out of a disk image can save you enormous amounts of time and disk space, leaving you more time for forensicating.  I urge you to spend some time practicing the techniques covered in this article.  Once you drink the offset Kool Aid, you’ll never go back to carving.

Hal Pomeranz is an Independent IT/Security Consultant, a SANS Institute Faculty Fellow, and a GCFA.  He is also a hard-core nerd, an ISTJ, and a Taurus.  One or more of these facts is probably irrelevant.  Hal will be teaching Security 508: Computer Forensics, Investigation, and Response at SANS Virginia Beach, May 24-29.

Mounting Images Using Alternate Superblocks (Follow-Up)

0
Filed under Computer Forensics, Evidence Acquisition, Evidence Analysis

Hal Pomeranz, Deer Run Associates

Several months ago, I blogged about using alternate superblocks to fake out the ext3 drivers so you could mount file system images read-only, even if they were needing journal recovery.  However, due to recent changes in the ext file system driver the method I describe in my posting is no longer sufficient.  Happily, there’s a quick work-around.

Let’s try the solution from the end of my previous posting under a more recent Linux kernel:

# mount -o loop,ro,sb=131072 dev_sda2.dd /mnt
mount: wrong fs type, bad option, bad superblock on /dev/loop0,
 missing codepage or helper program, or other error
 In some cases useful info is found in syslog - try
 dmesg | tail  or so

This looks like the original error output we got when using the primary superblock.  Looking at the relevant dmesg output we see something different, however:

[163135.527484] JBD: Ignoring recovery information on journal
[163135.795917] Buffer I/O error on device loop0, logical block 0
[163135.795931] lost page write due to I/O error on loop0
[163135.795944] Buffer I/O error on device loop0, logical block 1
[163135.795949] lost page write due to I/O error on loop0
[163135.795958] Buffer I/O error on device loop0, logical block 2
[163135.795963] lost page write due to I/O error on loop0
[163135.795973] Buffer I/O error on device loop0, logical block 3
[163135.795977] lost page write due to I/O error on loop0
[163135.795986] Buffer I/O error on device loop0, logical block 18
[163135.795991] lost page write due to I/O error on loop0
[163135.795999] Buffer I/O error on device loop0, logical block 32
[163135.796034] lost page write due to I/O error on loop0
[163135.796232] Buffer I/O error on device loop0, logical block 73
[163135.796238] lost page write due to I/O error on loop0
[163135.796248] Buffer I/O error on device loop0, logical block 74
[163135.796253] lost page write due to I/O error on loop0
[163135.796261] Buffer I/O error on device loop0, logical block 94
[163135.796267] lost page write due to I/O error on loop0
[163135.796275] Buffer I/O error on device loop0, logical block 96
[163135.796280] lost page write due to I/O error on loop0
[163135.796516] JBD: recovery failed
[163135.796520] EXT3-fs: error loading journal.

It would appear that even though we’re using an alternate superblock that’s marked as not requiring journal recovery, the ext file system driver is still finding the uncompleted journal entries and trying to apply them.  This is arguably “more correct” behavior than the old driver used, but it doesn’t help us very much.

The simple work-around is to tell the ext file system driver to ignore the journal by forcing the file system to be mounted as ext2:

# mount -t ext2 -o loop,ro,sb=131072 dev_sda2.dd /mnt
# ls /mnt
bin   dev  home    lib         mnt  proc  sbin  usr
boot  etc  initrd  lost+found  opt  root  tmp   var

Excellent!  With this small modification our trick is working again.  Hurrah!

You might well wonder what happens if you just try to mount our image as ext2 without using the alternate superblock.  Unfortunately, simply mounting as ext2 is not sufficient because the primary superblock is still marked as needing journal recovery.  Though I wonder why this flag should be relevant to an ext2 file system, it’s enough to prevent the mount from happening.  So the result is that you need to both mount using an alternate superblock and (at least on modern Linux kernels) mount the file system as ext2 to stop the file system driver from looking at the journal.

Hal Pomeranz is an independent IT/Computer Security consultant and a SANS Faculty Fellow.  He actually discovered this problem when attempting to give a live demo in the middle of a class.  Unfortunately, the solution only occurred to him after class was concluded.  This is one of the reasons why being a SANS Instructor can be so… invigorating.

Tricking the “script” Command

0
Filed under Computer Forensics, Evidence Acquisition, Incident Response, Linux IR

Keeping a record of all of the commands you type as well as their output is obviously useful during a forensic investigation.  On Unix and Linux systems, we have the “script” command which does precisely this.  You run “script <filename>” and the script command spawns a new shell: everything you type and all output you receive in return is automatically captured to the specified file.

From a forensic perspective, however, the classic problem is that script insists on writing its output to a file in the local file system.  This is particularly a problem during the initial stages of incident response when you’re operating on a live system trying to verify whether or not it has been compromised.  If you capture your session with the script command, you may be trampling important data as your output file grows.  Of course you could attach a portable storage device and write your output there, but that could be problematic on many levels.

This topic came up recently when Ed Skoudis and I were working on an article for our Command Line Kung Fu blog (a useful resource for Incident Response professionals, since we provide helpful command line short-cuts using both the Windows and Unix command shells).  During our conversation, I realized that there might be a work-around that allows the script command to send its output over the network.  Sure enough, after a little bit of hacking I came up with a devious little method to accomplish exactly this.

Suppose we had another machine on the same network as the host we are investigating.  Let’s suppose this other machine has IP address 192.168.100.1 and there’s a netcat process listening on port 9999 and redirecting its output to some file (”nc -l 9999 >myoutput”).  Now, on the machine you’re investigating, run the following commands:

$ mkfifo /tmp/fifo
$ cat /tmp/fifo >/dev/tcp/192.168.100.1/9999 &
[1] 1523
$ script -f /tmp/fifo
Script started, file is /tmp/fifo
$

Some explanation is clearly in order here:

  • The mkfifo command creates a special type of object in the file system called a FIFO (short for “first in, first out”).  The FIFO allows one command to write data into this “file” and another command to read data out of it.  This is perfect for our purposes.
  • The next command uses the cat to read data out of the FIFO and redirect that output into /dev/tcp/192.168.100.1/9999.  This “file name” is a specially recognized syntax in the bash shell that means “write the data over the network to host 192.168.100.1 on port 9999/tcp” (for more information see Ed’s excellent “Netcat Without Netcat” presentation).  We use “&” to put this command in the background where it will sit and wait for us to start putting data into the FIFO.
  • Finally we fire up the script command and tell it to write its data into the FIFO.  We also add the “-f” (”flush”) argument so that the script command doesn’t buffer its output– the remote side will see the commands being typed and get the output instantly.  We’re now in the subshell spawned by the script command and anything that happens from here on out should start appearing in the output file on the remote system.

The “/dev/tcp/…” syntax is a useful little bit of bash shell trickery.  But even if you didn’t have this, you could do something similar if your incident response kit included netcat.  Just change the second command in the output above to “cat /tmp/fifo | nc 192.168.100.1 9999″.

The real trick here is obviously knowing how to create and manipulate FIFOs, and for whatever reason this doesn’t seem to be something that’s commonly covered in most Unix classes.  But you have to admit it’s an impressively useful thing to know for situations such as this when you have a command like script that insists only on writing to a local “file”.

Obviously, on principles of strict forensic soundness it must be admitted that creating the FIFO does alter the file system slightly.  The FIFO itself requires an inode, though no data blocks will be consumed.  Also the contents of the directory the FIFO is placed in will be modified.  However, I will point out that many Unix systems are configured by default to use memory-based file systems for directories such as /tmp or /var/run.  If this is the case on the system you’re investigating, I would recommend creating your FIFO in one of these memory-based file systems to minimize any impact to the file system on disk.

Hope you find this little trick useful in future investigations!

Hal Pomeranz, Deer Run Associates, is an independent IT/Computer Security consultant and a SANS Faculty Fellow.  He spends far too much time hanging out in the sketchy parts of the Unix operating system.

Perl Fu: Email Discovery

1
Filed under Email Investigations, eDiscovery

Hal Pomeranz, Deer Run Associates

I hope Mike Worman doesn’t hate on me for stealing his “Perl Fu” idea, but I recently have been dealing with a task that is perfect for Perl.  One of my customers is having to do a laborious discovery process through a huge email archive that is in “Unix mailbox format”– meaning large text files with the email messages all concatentated togther.  They need to find any one of a list of relevant keywords in messages stored in these hundreds of gigabytes of large text files and output the entire text of the matching email messages.

Unix mailbox format is a file format that I’ve dealt with a lot, and I’ve written many scripts to parse these kinds of files.  So it probably took me less time to write the script to do this than it’s going to take me to write this blog post.  But I figured this is a task that other readers of the blog might encounter from time to time, so here’s the code:

#!/usr/bin/perl
# mgrep -- match patterns and output messages from Unix mailbox files
# Usage: mgrep [-i] [-f file] [pattern] file1 ...

use strict;
use Getopt::Std;

my %opts = ();
getopts('if:', \%opts);

my $pattern = undef;
if (length($opts{'f'})) {
    open(FILE, "< $opts{'f'}") ||
	die "Can't open pattern file $opts{'f'}: $!\n";
    my @lines = <FILE>;
    close(FILE);
    chomp(@lines);
    $pattern = '(' . join('|', @lines) . ')';
}
else {
    $pattern = shift(@ARGV);
}
$pattern = "(?i)$pattern" if ($opts{'i'});

my $message = undef;
while (<>) {
    if (/^From\s/) {
	print $message if ($message =~ /$pattern/s);
	$message = undef;
    }
    $message .= $_;
}
print $message if ($message =~ /$pattern/s);

The actual meat of the program is the “while (<>) …” loop down in the bottom third of the code.  We spend more code processing arguments and setting up the pattern match than on actually processing the input files.  But here are some notes to help you make sense of what’s happening in the program:

  1. First we “use strict” to have Perl help us enforce good programming practice in our script, like pre-declaring variables with “my” to help prevent typos and other errors.
  2. Then we incorporate the standard Perl command line argument processing library (”use Getopt::Std”) and call getops() to process the command line arguments.  Here we’re specifying that our program accepts both “-i” (case insensitive matching) and “-f” to specify a file name containing a list of patterns to match against.  The “:” after the “f” in the getops() string means that”-f” expects an argument, namely the file name.  Any options that getopts() finds will be stored in the “%opts” array.
  3. Next our “if” block checks to see if the “-f” option was set.  If so, then we attempt to open the specified file name and read in its contents (”die” causes the program to abort if the file can’t be opened).  We use chomp() to remove the newlines from the lines we read in and then we concatenate all of the patterns together to form a pattern string like “(pattern1|pattern2|…)” (”pattern1 or pattern2 or …”).  Note that if “-f” was not set, then we just read the pattern in from the command line like the normal Unix grep program (that’s the “else { … }” block).
  4. Next we check to see if the “-i” (case-insensitive match) option is set.  If so, then we add “(?i)” at the front of our pattern.  In a Perl pattern match, this is one way to express case-insensitive matching.
  5. Now we’re finally ready to start processing our input files.  The “while (<>) { … }” construct is a useful bit of Perl shorthand that emulates the standard Unix command-line processing.  Specifically it means that if there are any remaining command-line arguments, they should be treated as file names and opened sequentially and all lines processed one at a time from each file.  If there are no unused arguments on the command line after our argument processing, then the program should look for its input from the standard input.
  6. Within the body of the loop, we’re processing our input one line at a time.  At the end of the loop we’re simply concatenating the lines we read into the “$message” variable that holds our message text.  “$_” is the magic Perl variable that represents the text of the line we’re currently processing, and “$message .= $_” means “append $_ to the text already in $message”.
  7. Now for the uninitiated, Unix mailbox format is nothing but a large text file with messages concatenated one after the other.  You can recognize the start of each new mail message when you find a line that begins “From<whitespace>“.  Our “if { … }” block at the top of the loop matches this pattern as an indication that we’ve reached the end of one message and are starting in on another.  If the message we’ve collected so far matches the pattern specified by the user then we print the entire contents of the mail message.  Then we empty our “$message” variable and so we can start collecting the next mail message.
  8. After we’ve processed all of our input files, we still need to determine whether or not we should output the last message from the last file we processed.  That’s why there’s one more print statement after the end of the loop.

Whew!  That’s a lot of words for a simple script, but I hope it helps you wrap your head around some of the more obscure bits of Perl syntax and gives you some ideas for writing your own scripts.  By the way, because I chose to use Perl for this task, one of the happy accidents is that we can actually use the Perl regular expression syntax for the patterns we give as input to the program (whether we put them in a file or specify them on the command line).  This is good news because Perl’s pattern matching syntax is much more flexible and expressive than the one used by the regular Unix grep command.

Happy email hacking!

Hal Pomeranz is an independent IT/Computer Security Consultant and a SANS Faculty Fellow.  He is available as a strolling Perl programmer for weddings and bar mitzvahs.

Directory Link Counts and Hidden Directories

1
Filed under Computer Forensics, Evidence Analysis, Incident Response, Linux IR

by Hal Pomeranz, Deer Run Associates

One of the things I love about teaching at SANS is that the students are smart people and come up with great ideas.  Sometimes these ideas even lead to useful tools, as was the case a few years ago when we were talking about hidden directories in the Digital Forensics section of Sec506.

First, a little background information.  Unix file systems keep track of a “link count” to all objects in the file system.  This “link count” value is the number of different directory entries that all point to the inode associated with the object.  In the case of a regular file, the link count is the number of hard links to that file.

However, Unix file systems don’t let you create hard links to directories, yet the link count on a directory is always at least two, and even increases by one for each sub-directory in that directory.  Why is this so?

  • Any object in the file system must have a directory entry that connects it into the file system.  For example, if you have a directory like “/tmp”, there’s a pointer in the root directory (”/”) that points to the “tmp” directory entry.  So that gives you one link.
  • Every directory contains the “.” link that points back to itself.  So that gives us the minimum value of 2 links per directory.
  • Every subdirectory has a “..” link that points back to its parent, incrementing the link count on the parent directory by one for each subdirectory created.

For one thing, the above behavior is why it’s important to monitor the link count on critical directories in your file system using a file integrity assessment tool like Tripwire, Samhain, or AIDE.  You can detect people adding or deleting directories when the link counts change.

But consider the following output from a compromised system:

# ls -a /foo
.  ..
# ls -dl /foo
drwxr-xr-x    3 root     root         4096 Jun 12 18:46 /foo

Our “/foo” directory is empty except for the normal “.” and “..” links, meaning we’d expect the link count to be 2.  Yet we see from the “ls -l” output that the link count on this directory is listed as 3 (look for the link count in the second column after the permissions flags and before the file ownership).  What’s going on here?

What’s happening is that I’ve used a kernel-level rootkit to hide a subdirectory of “/foo”.  However the rootkit was not able to decrement the link count of the parent directory without causing a file system discrepancy that would show up the next time you fsck-ed the file system.  In fact, I’ve never encountered a kernel-level rootkit that has attempted to mask the parent directory link count in any fashion when it hides a directory.

As my students pointed out, this suggests an obvious heuristic for detecting the presence of hidden directories on a system.  Simply write a tool that traverses the entire file system searching for directories where the number of subdirectories in a given directory is not equal to the “link count minus two”.  While this technique will only tell you that a hidden directory exists and not necessarily give you the name of the hidden directory, it will pinpoint exactly where to start looking once you get a chance to analyze the file system image on a system that doesn’t have the kernel-level rootkit loaded.

In any event, the tool was extremely simple to write.  It’s called “chkdirs” and it’s now part of the chkrootkit distribution.  And it’s all thanks to some smart and interested SANS students.

Hal Pomeranz is an independent IT/Computer Security Consultant and a SANS Faculty Fellow.  He believes that when the student is ready the master will appear… even if that master is one of your students!

When “Redundant” Yields Different Results

0
Filed under Evidence Acquisition, Incident Response

by Hal Pomeranz, Deer Run Associates

One question that often comes up with I’m talking about Digital Forensics in SANS Sec506 is, “There are so many ways to get at the same data on a Linux/Unix system, which method should we choose?”  My response is, “All of them.”  And then I show them this little example to explain why.

Let’s take the case of active network connections on the system.  There are all sorts of ways to get at this data, including “lsof” and “netstat”:

# lsof -i :22
# netstat -anp | grep :22
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 172.1.1.136:22          172.1.1.1:39967         ESTABLISHED -

This is definitely a Whiskey-Tango-Foxtrot kind of situation.  First we’re asking “lsof” to show us all current network connections associated with port 22, and it says there’s nothing going on.  However when we run “netstat” to dump the same information and “grep” for the port 22 traffic, we see both a local server process listening on that port as well as an active network connection with another system.  If you look closer at the “netstat” output you’ll see that where the “-p” option should be providing process ID information about these processes in the last column of output, we’re only getting a “-”, indicating that “netstat” is unable to associate a process with these network connections.

What’s happening on this system is that I’ve used a kernel-level rootkit to hide the SSH daemon process in the kernel process table.  Since “lsof” comes at the problem by scanning through the process table, it misses our hidden processes and their open sockets.  On the other hand, “netstat” starts from the list of open sockets and (if requested with “-p”) tries to find related processes in the process table.  Even if it can’t find an associated process, however, it still can output the fact that the network sockets are in use.

This is why it’s so critical to capture data using multiple tools when you’re trying to verify an incident or capture volatile data about the current state of a compromised system.  If we had only relied on “lsof”, we would have missed important information.  In this case, the discrepancy in the output of these two tools tells us a lot about what’s happened on the system.  So make sure you use all the tools in your toolkit.

Hal Pomeranz is an independent Computer Security/IT consultant and SANS Institute Faculty Fellow.  He once developed the perfect kernel-level rootkit, but it was so good at hiding itself that it disappeared.

Missed It By That Much!

0
Filed under Computer Forensics, Evidence Analysis

Hal Pomeranz, Deer Run Associates

One primitive forensic technique I show my students in my SANS Sec506 class is the tried and true method of using grep to display byte offsets of “strings of interest” found in a disk image.  For example, I have my students go looking for “love” in the file system of the VMware image we use in class:

# grep -abi ' love ' /dev/sda6
452925733:# This is a comment. I love comments.
...

Once you have the byte offsets from grep, all you have to do is divide by the block size of the file system (hint: use fsstat) to get the number of the block that the string resides in.  In the example, /dev/sda6 is a small file system that only uses 1024 byte blocks, so the number of the block where love is hiding is: 452925733 / 1024 = 442310.

However, when we go to dump that block, something interesting occurs:

# dcat /dev/sda6 442310
###
### Begin Red Hat Mailcap
###

audio/mod; /usr/bin/mikmod %s
# play is apparently a security hole
#audio/*; /usr/bin/play %s

image/*; gthumb %s

application/msword; ooffice %s
application/pdf; evince %s
application/postscript ; evince %s

text/html; /usr/bin/htmlview %s ; copiousoutput

Apparently there’s something wrong with our technique, because the string we matched with grep doesn’t appear in the block whose number we calculated from the byte offset!  Let’s try the next block:

# dcat /dev/sda6 442311
# This is a comment. I love comments.

# This file controls what Internet media types are sent to the client for
...

OK, there’s our string– right at the beginning of the next block.  What the heck is going on here?

We’ve just encountered on of the curious side-effects of using a line-oriented tool like grep on binary file system image data.  It’s easier to understand what’s happening if you look at the hex dump output of the original block whose number we calculated from the byte offset:

# dcat -h /dev/sda6 442310
0       23232320 0a232323 20426567 696e2052     ###  .###  Beg in R
16      65642048 6174204d 61696c63 61700a23     ed H at M ailc ap.#
...
272     77202573 203b2063 6f70696f 75736f75     w %s  ; c opio usou
288     74707574 0a000000 00000000 00000000     tput .... .... ....
304     00000000 00000000 00000000 00000000     .... .... .... ....
320     00000000 00000000 00000000 00000000     .... .... .... ....
...

What we’ve got here is a very small file that ends at byte 292 with a final trailing newline (hex 0×0a).  The rest of the slack space in the block is filled with nulls.

However, grep is looking to display the byte offset of matching lines, so from it’s perspective the next “line” starts at byte 293 in our block, right after that trailing newline.  Since there are no newlines in the rest of the block, that “line” continues into the next block and includes our “string of interest”.  Remember that grep is just treating its input as a stream of data, it knows nothing about block boundaries because the lower-level system call interfaces hide those details from grep.

If what I’m telling you is the truth then the original byte offset that was displayed by grep (452925733) should equal 442310 blocks of 1024 bytes each, plus 293 bytes.  You can do the calculation for yourself, but here’s my result (presented in true Unix nerd fashion):

# expr 442310 \* 1024 + 293
452925733

Theory confirmed.

Now don’t get me wrong: the “grep for strings of interest” technique is a useful arrow in your forensics quiver.  You just need to be aware that little bumps in the road like this will occur whenever you’re using tools like grep in ways that they were not originally intended to be used.

Change Controls: Ur Doin It Rong

1
Filed under Incident Response

by Hal Pomeranz, Deer Run Associates

More details are emerging in the case of Rajendrasinh Makwana, a former consultant at Fannie Mae, who allegedly planted malicious code on Fannie Mae’s servers after he had been terminated.  If the code had not been detected, it apparently would have destroyed data on a large number of Fannie Mae’s servers on January 31st.

There’s been a great deal of hand-wringing over the fact that Makwana continued to have sufficient access after he was terminated to allow him to plant the malicious code.  Well, let’s review the facts as presented by FBI Agent Jessica Nye’s affidavit:

“On October 24, 2008 between 1:00 and 1:30pm, MAKWANA was terminated as an employee of [Fannie Mae]… At approximately 4:45pm, MAKWANA dropped of his badge and laptop to a [Fannie Mae] employee… Access to [Fannie Mae's] computers…[was not terminated] until late in the evening on October 24, 2008.”

Certainly it’s regrettable that Makwana had upwards of 12 hours of access to Fannie Mae’s network after he was notified of his termination.  But, while I’m not condoning this practice, it’s a fact that managing to terminate Makwana’s access the same day he left the building puts Fannie Mae in the upper 90th percentile of most IT organizations I’ve encountered.

The information in the FBI Agent’s affidavit that really made me sit up and take notice was the following:

“On October 29, 2008, SK, [a Fannie Mae] senior Unix engineer, discovered malicious script embedded within a pre-existing, legitimate script… It was only by chance that SK scrolled down to the bottom of the legitimate script to discover the malicious script.”

In other words, Fannie Mae got very, very lucky here.  What I want to know is why Fannie Mae had to trust to luck to detect an attack that (again according to the FBI affidavit), “would have caused millions of dollars of damage and reduced if not shut down operations at [Fannie Mae] for at least a week.”

Where the hell are the controls on Fannie Mae’s change management process?  How is it possible that Makwana was able to modify code that ran on Fannie Mae’s production systems without that modification being detected?  Having a front-end change control process is nearly useless if you don’t have back-end controls to verify that the process is being followed correctly.

Fellow SANS Instructor Randy Marchany is fond of saying, “The time it takes your organization to deal with an incident is equal to the time it takes you to notice the problem plus the time it takes you to react.”  Well in this case, it was only through sheer luck apparently that Fannie Mae’s “time to notice the problem” wasn’t infinite.  That’s unacceptable in a high-performing IT organization.  In fact, there’s research that shows that effective change management and lack of tolerance for unplanned changes may be the key benchmark for the highest-performing IT organizations.  And Fannie Mae clearly isn’t there.

And there’s such an easy fix for this problem: file integrity assessment tools like Tripwire, AIDE, and Samhain.  Yes, there is overhead to using these tools in any IT organization, but it’s easy to justify these tools if the alternative is potentially losing millions of dollars and having your operations offline or degraded for a week.  That’s a catastrophic event that would put many companies out of business.

Many of you reading this blog deal more with the aftermath of failures of IT processes than with establishing those processes themselves.  But I think we’d all agree that the best incident response scenario is one where we don’t have to respond to an incident at all because the incident wasn’t allowed to happen.  As the current economic climate leads to more layoffs and a greater potential for malice by disgruntled former employees, it’s important that IT organizations look to shoring up the controls that will help them defend their infrastructures against possible threats.

Hal Pomeranz is an independent IT/Computer Security Consultant and a SANS Faculty Fellow.  He’s extremely happy to report that he has no financial relationships with Fannie Mae.

Recovering Open But Unlinked File Data

0
Filed under Computer Forensics, Evidence Acquisition, Incident Response, Linux IR

By Hal Pomeranz, Deer Run Associates

If you’ve ever been a Unix system administrator, you may have encountered “open but unlinked” files in the course of your normal duties.  The typical scenario is a user who’s launched a process that creates an unexpectedly large output file which consumes all of the free space in the partition.  In a panic, the user deletes the output file but leaves the process running.  Unfortunately, the operating system is not allowed to reclaim the space until the last process that has the output file open actually exits.  So until the user kills their process, the space is still in use and the file system is full.  But when you as the system administrator logs in to free some space in the partition, you’re unable to find the massive file that’s consuming all of the space with your normal file system tools because the file has been unlinked (deleted) from the file system.  Finding the process that’s holding the file open and killing it would free the space, but that requires some specialized knowledge and trickery which we’ll see a little later.

In an incident, attackers have been known to use open but unlinked files to hide their data.  For example, suppose the attacker were running a packet sniffer that was capturing usernames and passwords off your network and storing it in a file.  Perhaps they have another process that’s reading the data as it’s placed in the file and using some covert channel to move it off system.  At this point the attacker could delete the data file: the packet sniffer would continue writing data to the file and their reader process could continue reading the data because they opened the file before it was removed from the file system, but the system administrator would have trouble locating the file because it’s now unlinked from the file system.  In fact, the attacker can even delete the executables for the packet sniffer and the reader process from the file system and the current processes will continue to run.

This kind of open but unlinked file data can be difficult to recover from a “cold” system image, because the minute the system is shut down and the attacker’s processes are terminated, the data in these files just becomes part of the free block collection and must be recovered like any other deleted file data.  However, if you have the luxury of analyzing the running system, it is extremely easy to spot and recover this kind of file data.

Creating Our Test Case

As a stand-in for our attacker’s hypothetical packet sniffer, I’m going to start a tcpdump process and have it dump its packet captures into a file.  Since I plan on removing the tcpdump binary as part of my demonstration, I’m first going to make a copy of the binary in /tmp:

# cp /usr/sbin/tcpdump /tmp/tcpdump
# /tmp/tcpdump -w /tmp/capture &
[1] 12437
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
# ls -l /tmp/tcpdump /tmp/capture
-rw-r--r-- 1 root root   4096 2009-01-21 18:08 /tmp/capture
-rwxr-xr-x 1 root root 639416 2009-01-21 18:07 /tmp/tcpdump

So far, so good.  Our tcpdump process is running and has captured a little bit of data.  Now I’m going to remove the binary and the output file and verify that the process is still running:

# rm /tmp/tcpdump /tmp/capture
# ls -l /tmp/tcpdump /tmp/capture
ls: cannot access /tmp/tcpdump: No such file or directory
ls: cannot access /tmp/capture: No such file or directory
# ps -ef | grep tcpdump
root     12437 12289  0 18:08 pts/1    00:00:00 /tmp/tcpdump -w /tmp/capture

Great!  The process is still active, but neither the binary nor its output file are visible to standard Unix tools like ls.  Now let’s have some fun.

The Power of lsof

It turns out that the highly indispensible lsof utility has an option for detecting exactly these open but unlinked files:

# lsof +L1
COMMAND     PID USER   FD   TYPE DEVICE     SIZE NLINK   NODE NAME
init          1 root    0u   CHR    5,1              0    623 /dev/console (deleted)
init          1 root    1u   CHR    5,1              0    623 /dev/console (deleted)
init          1 root    2u   CHR    5,1              0    623 /dev/console (deleted)
wineserve 10510  hal   31u   REG  254,1 16777216     0  42233 /tmp/.wine-1000/server-fe05-4ee00e/anonmap.WKvI4J (deleted)
firefox   10826  hal   60u   REG  254,4     8200     0 139466 /var/tmp/etilqs_wkK3U9h1sAcQpD3 (deleted)
tcpdump   12437 root  txt    REG  254,1   639416     0  25463 /tmp/tcpdump (deleted)
tcpdump   12437 root    4w   REG  254,1    65536     0  25500 /tmp/capture (deleted)

The “+L1″ option is translated as “show me all files with link count less than one”– in other words, “show me all files with link count zero” which is just another way of saying “files which have been unlinked from the file system”.  It’s almost anti-climactic how easy it is to spot these files with lsof.

However, the above output also demonstrates another important aspect of this discussion: not all open but unlinked files are necessarily cause for concern.  There are a few processes that are common to the Unix/Linux platform that sometimes make use of open but unlinked files as part of their normal operations.  This is clearly a situation where one must “know thy systems”– be familiar with how the operating systems you’ll be investigating appear during normal operations– so that you can spot discrepancies.  That being said, programs that I’ve seen regularly using open but unlinked files include the Linux init process, Firefox, the Wine Windows emulator (all of which you can see in the output above), and VMware Server.

OK, at this point we’ve spotted the open but unlinked files, but how can we recover the data that’s in them?  The lsof output above gives us the inode numbers for the files if you look in the “NODE” column (25463 for our deleted tcpdump binary and 25500 for the output file).  This means we could use a tool like icat from the Sleuthkit to dump the contents of these files.  But it turns out that there’s another approach that doesn’t require any tools that aren’t already present in most Unix-like operating systems.

/proc to the Rescue!

The lsof output also gives us the process ID of the processes with open but unlinked files.  In this case, our tcpdump process is PID 12437.  Let’s head over to the /proc/12437 directory and see what we can see:

# cd /proc/12437
# ls
attr		 cpuset   io	    mountinfo	oom_score  smaps
auxv		 cwd	  latency   mounts	pagemap    stat
cgroup		 environ  limits    mountstats	root	   statm
clear_refs	 exe	  loginuid  net		sched	   status
cmdline		 fd	  maps	    numa_maps	schedstat  task
coredump_filter  fdinfo   mem	    oom_adj	sessionid  wchan

There’s a lot of interesting data in /proc, but for our purposes the “exe” object is the first interesting thing:  “exe” is always a copy of the binary image of the running process.  So all we have to do to recover the deleted executable is make a copy of this “file” under /proc.  Obviously in a real incident you wouldn’t want to copy the file back into the file system of the compromised machine because you’d potentially be overwriting important evidence.  You’d either want to copy it to a portable drive you’ve connected to the system, or move the executable off the machine via the network with a command line like:

# cat /proc/12437/exe | nc 192.168.1.1 9999

This assumes you’ve got a machine acting as a “collector” at 192.168.1.1 with another netcat process listening on port 9999/tcp and writing the incoming data into a file.

Just to prove to you that this works, however, let me just copy the binary into my local file system and demonstrate that the result is a working executable:

# cp /proc/12437/exe /tmp/testing
# /tmp/testing --version
testing version 3.9.8
libpcap version 0.9.8
Usage: testing [-aAdDeflLnNOpqRStuUvxX] [-c count] [ -C file_size ]
        [ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]
        [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
        [ -W filecount ] [ -y datalinktype ] [ -Z user ]
        [ expression ]

Again, in a real incident you wouldn’t just blindly execute a suspicious program you’d recovered in this manner.  You’d only want to experiment with a copy of the executable in an isolated “sandbox” type system.

OK, so what about recovering the data file that the tcpdump process is writing?  If you look at the directory listing of /proc/12437, you’ll notice that there’s an object called /proc/12437/fd.  “fd” here stands for “file descriptor” and /proc/12437/fd is actually a directory that contains links to all files this process currently has open.  Let’s take a look at this directory in more detail:

# ls -l /proc/12437/fd
total 0
lrwx------ 1 root root 64 2009-01-21 18:14 0 -> /dev/pts/1
lrwx------ 1 root root 64 2009-01-21 18:14 1 -> /dev/pts/1
lrwx------ 1 root root 64 2009-01-21 18:12 2 -> /dev/pts/1
lrwx------ 1 root root 64 2009-01-21 18:14 3 -> socket:[4197672]
l-wx------ 1 root root 64 2009-01-21 18:14 4 -> /tmp/capture (deleted)

Notice that the link names are named for the internal file descriptor number used by the process, but the names of the files associated with these file descriptors can be clearly seen, along with the fact that the /tmp/capture file has been deleted.

The cool thing is that you can use these links as arguments to normal Unix file system commands.  For example, if you wanted to copy the data in the deleted file over the network to your capture workstation:

# cat < /proc/12437/fd/4 | nc 192.168.1.1 9999

There’s a little bit of subtlety to the command above.  Notice that I’m not just doing “cat /proc/12437/fd/4″, because that would only give me a snapshot of the contents of the file at a particular instant in time.  Instead I’m using input redirection (”<”) to dump the current state of the file and then continue reading data and dumping it into netcat as it’s being written into the file.  Our cat process will only terminate when the tcpdump file closes its output file.  This is one of the things that makes this approach superior to just using a tool like icat to dump the current state of the file.

Some Final Thoughts

It’s fairly uncommon to find attackers making use of open but unlinked files in this manner.  But if you’re accessing the compromised system anyway– for example to capture a memory dump before you shut the machine down– it doesn’t hurt to run a quick lsof command to check for any instances of these files.  In the cases where they do exist, the techniques described above can allow you to quickly recover some information that is typically critical to analyzing what the attacker is doing to your system.

Also, don’t forget about the /proc/<pid>/cwd link, which is a link to the current working directory of the process.  If the attacker was foolish enough to start the suspicious process from their rootkit installation directory, you may be able to zero-in on the compromise in record time!

Hal Pomeranz is an independent Computer Security/IT consultant and SANS Institute Faculty Fellow.  He wants to name his first child “Elesso’ef Slashproc”, which probably means it’s a good thing he’s not planning on having kids.