November 17, 2011 by

srch_strings_wrap — history and examples

1 comment

Categories: Forensics, Tags: , ,

I recently took SANS FOR508 with Rob Lee in Las Vegas.  It was a great class and I highly recommend it to everyone interested in Digital Forensics.  I’m new to forensics and learned so much from the class.

One of the topics covered is using the srch_strings command from the Sleuth Kit on a filesystem image to obtain not just the strings within the file, but also the byte offset of each string.  This is done using the “-t d” option:

$ srch_strings -a -t d sda1.img
 7208 vmlinuz-2.2.14-5.0
 7336 System.map-2.2.14-5.0smp
 7464 module-info-2.2.14-5.0
 262176 lost+found
 262196 kernel.h
 262212 System.map-2.2.14-5.0
 262244 module-info-2.2.14-5.0

Then, after obtaining the block size of the filesystem using fsstat, we figure out which block each of these strings is in.  For example, this is an image of a filesystem with 1024 byte blocks, so divide each byte offset by 1024:

Block  String
 7     vmlinuz-2.2.14-5.0
 7     System.map-2.2.14-5.0smp
 7     module-info-2.2.14-5.0
 256   lost+found
 256   kernel.h
 256   System.map-2.2.14-5.0
 256   module-info-2.2.14-5.0

During class, I got tired of opening the calculator to figure out these blocks, so I came up with a little one liner to do everything at once:

$ strings -a -t d sda1.img | tee file | awk '{print $1"/1024"}' | bc | paste - file
7       7208 vmlinuz-2.2.14-5.0
7       7336 System.map-2.2.14-5.0smp
7       7464 module-info-2.2.14-5.0
256     262176 lost+found
256     262196 kernel.h
256     262212 System.map-2.2.14-5.0
256     262244 module-info-2.2.14-5.0

Eventually, I got tired of typing that out and turned it into a script after getting back home after class.  I emailed Rob Lee about it and he put me in touch with Hal Pomeranz, who had been working on a similar script.  Hal and I had some other ideas of where this could be taken, and that’s what eventually became srch_strings_wrap.

In a previous post, I gave an overview of the command line options and functionality, so now I’d just like to show some examples.

As I said in the overview, if you just supply the same command line options as you would to srch_strings, srch_strings_wrap will give the same output:

$ srch_strings_wrap -a -t d sda1.img
 7208 vmlinuz-2.2.14-5.0
 7336 System.map-2.2.14-5.0smp
 7464 module-info-2.2.14-5.0
 262176 lost+found
 262196 kernel.h
 262212 System.map-2.2.14-5.0
 262244 module-info-2.2.14-5.0

If you know the blocksize you can specify with the -b option or use -d and it will be determined from fsstat.

$ srch_strings_wrap -a -t d -d sda1.img
OR
$ srch_strings_wrap -a -t d -b 1024 sda1.img
FILENAME_NF	NF	Metadata	A	7	40	7208	vmlinuz-2.2.14-5.0
FILENAME_NF	NF	Metadata	A	7	168	7336	System.map-2.2.14-5.0smp
FILENAME_NF	NF	Metadata	A	7	296	7464	module-info-2.2.14-5.0
/	A	2	A	256	32	262176	lost+found
/	A	2	A	256	52	262196	kernel.h
/	A	2	A	256	68	262212	System.map-2.2.14-5.0
/	A	2	A	256	100	262244	module-info-2.2.14-5.0

There are a few different output options. To write STDOUT to a file, use “-w file”. To suppress STDOUT, use “-N”. To print a header line, use “-H”, which for the output above would be:

FILENAME	I_STATUS	INODE	B_STATUS	BLOCK	B_OFFSET	BYTE OFFSET	STRING

The default delimiter is the tab character, but it can be changed with “-F delim” where delim is 1 or more characters to use. Alternatively, “-C” can be used to print in CSV format, which will put quotes around the string and escape any quotes within the string.

"/","A","2","A","256","32","262176","lost+found"

The default output takes the srch_strings output and prepends the additional columns. Another option is to use “-O” which will group all the hits within a single file or inode, if it was found, or the block if not.

$ srch_strings_wrap -a -t d -d -O sda1.img

IMAGE: sda1.img, PARTITION: N/A, FILE: FILENAME_NF, INODE STATUS: NF, INODE: Metadata, BLOCK: 7
	BLOCK_OFFSET	STRING
	        40 vmlinuz-2.2.14-5.0
	       168 System.map-2.2.14-5.0smp
	       296 module-info-2.2.14-5.0

IMAGE: sda1.img, PARTITION: N/A, FILE: /, INODE STATUS: A, INODE: 2
	FILE_OFFSET	STRING
	        32 lost+found
	        52 kernel.h
	        68 System.map-2.2.14-5.0

All these commands are using the default “level” of 3 which tries to go all the way from the byte offset (level 0) to the block (level 1) to the inode (level 2) to the filename (level 3). The “-l #” option can be used to specify a custom level if going all the way to the filename layer is not needed. The output will be adjusted accordingly and the command should run faster at lower levels. Note that “level 0” is essentially the same as the basic srch_strings output. Here’s an example of only going to level 1:

srch_strings_wrap -a -t d -d -l 1 -H sda1.img
B_STATUS	BLOCK	B_OFFSET	BYTE OFFSET	STRING
A	7	40	7208	vmlinuz-2.2.14-5.0
A	7	168	7336	System.map-2.2.14-5.0smp
A	7	296	7464	module-info-2.2.14-5.0
A	256	32	262176	lost+found
A	256	52	262196	kernel.h

The -A option can be used to automatically carve any matches into a folder. The default folder is in the current directory and is called ssw_output, but it can be changed with the “-D path” option.

$ srch_strings_wrap -a -t d -d -A -N sda1.img
$ ls ssw_output/sda1.img/00/\[root\]/module-info-2.2.14-5.0     
module-info-2.2.14-5.0smp  vmlinux-2.2.14-5.0
ROOTDIR                    vmlinux-2.2.14-5.0smp
System.map-2.2.14-5.0      vmlinuz-2.2.14-5.0

The file named ROOTDIR is the root directory on the filesystem. The directory structure within ssw_output is “image_name/partition_number/” followed by [root] for allocated files, [unallocated] for unallocated files, and [filename unknown] when the filename couldn’t be found.

All of these examples so far have assumed that the image is a partition or filesystem image. This is the default, but a full disk image can be given as well. The mmls command is used to pick the partitions and their offsets. The partition number will be prepended in the output and “00” will be used if it’s just a filesystem image.

$ srch_strings_wrap -a -t d -d -A sda.img
00	FILENAME_NF	NF	Metadata	A	7	40	7208	vmlinuz-2.2.14-5.0
00	FILENAME_NF	NF	Metadata	A	7	168	7336	System.map-2.2.14-5.0smp
00	FILENAME_NF	NF	Metadata	A	7	296	7464	module-info-2.2.14-5.0
00	/	A	2	A	256	32	262176	lost+found
00	/	A	2	A	256	52	262196	kernel.h

Autocarving the whole image may match on many files, so srch_strings_wrap accepts “-g string” or “-G file” where string is a grep regex or file contains a list of strings to pass to “grep -f”. Case insensitivity can be specified with “-i”. The grep commands can be used with or without the “-A” option.

$ /srch_strings_wrap -a -t d -d -g f.*le sda1.img | head
/System.map-2.2.14-5.0	A	13	A	269	1003	276459	c0106e91 t mtrr_file_add
/System.map-2.2.14-5.0	A	13	A	270	4	276484	c0106f03 t mtrr_file_del
/System.map-2.2.14-5.0	A	13	A	279	123	285819	c0112e72 t copy_files
/System.map-2.2.14-5.0	A	13	A	280	896	287616	c0116ff0 T exit_files

The last option is “-P” which, rather than an image, accepts the output of a previously run srch_strings command. This would be useful if you wanted to run srch_strings on an entire image just once, then wanted to run multiple different “grep” searches on those results. The precomputed file is cat’d in via the pipeline. The “-I image” is also required where image is the image file that srch_strings was run against:

$ srch_strings_wrap -a -t d sda1.img > sda1.asc
$ cat sda1.asc | srch_strings_wrap -P -I sda1.img
FILENAME_NF	NF	Metadata	A	7	40	7208	vmlinuz-2.2.14-5.0
FILENAME_NF	NF	Metadata	A	7	168	7336	System.map-2.2.14-5.0smp
FILENAME_NF	NF	Metadata	A	7	296	7464	module-info-2.2.14-5.0
/	A	2	A	256	32	262176	lost+found
/	A	2	A	256	52	262196	kernel.h
$ cat sda1.asc | srch_strings_wrap -P -I sda1.img -g f.*le > sda1.asc.f_le
$ cat sda1.asc | srch_strings_wrap -P -I sda1.img -g kernel > sda1.asc.kernel

That covers all of the current functionality. I hope people find it useful. If anyone has any suggestions for improvement or finds any bugs, let me know at dave at this domain.

One Response to srch_strings_wrap — history and examples

Leave a Reply

Your email address will not be published. Required fields are marked *