Wednesday, April 29, 2009

Episode #29: Finding the Time

Hal Says:

When analyzing a file system after an incident, it's often useful to search for recently modified files. Yes, an attacker who's broken root could have reset the timestamps on the files they modified, but I've found that in many cases they don't bother. That means you can do something like this:

# find / -mtime -2 -ls

That will give you a detailed listing of all files that have been modified within the last two days.

This example points up a shortcoming of find, however-- the finest granularity you have for time-based searches is in terms of some number of days. But what if your IDS or firewall logs can tell you exactly when the attack occurred down to the second? Wouldn't it be nice if you could have your find command show you only the files that have been modified since that exact point in time?

Turns out there's a clever little idiom for doing precisely this:

# touch -t 200904291446.53 /tmp/timestamp
# find -newer /tmp/timestamp -ls

The touch command allows the root user to explicitly set the timestamp on a file. The format is (the seconds are optional), so in the example above we're setting the timestamp to 2:46:53pm on Apr 29, 2009. Once you've set the timestamp appropriately, it's a simple matter of using "-newer" with find to locate all files that have been modified more recently than that date.

Ed responds:
I really hate it when Hal pulls something out of his... uh... ear that is trivially easy to do in Linux with bash but is a real pain in the... uh... neck in Windows cmd.exe. But, saddled with this shell, we must make do.

One option we have for getting files' last modification dates and times in Windows cmd.exe is to use the dir command as follows:
C:\> dir /a /tw /o-d
That'll display the contents of the current directory, with all files regardless of their attributes (/a), showing the timestamp (/t) of the last written time (w), ordered (/o) in reverse (-) by date (d). OK... it's a start. The most recently written-to files (i.e., "modified") are at the top of the list.

But, Hal's find command is doing recursion through the Linux file system. What happens when we add a happy little /s to dir to make it recurse through all of c:\?
C:\> dir /a /s /tw /o-d c:\
In the words of Steve Jobs, it's a bag of hurt. It just sucks. It sucks horrifically bad. You see, the contents of each directory are displayed, and those files in each directory are sorted by modified date, as we'd like... but it's done on a directory-by-directory basis, without regard to when each directory was altered. Doh! Adding a /b (for bare form of output) doesn't help us, because it that'll leave off the timestamp information that we crave.

Often in cmd.exe, if we can't get the file information we'd like from the dir command because of all of its baked-in limitations, we can get far closer to what we want with a FOR loop.

So, let's try this again, this time with a FOR loop. We'll use a FOR /R loop, because it recurses through the file system for us, finding files. How about this:
C:\> for /r %i in (*) do @echo %~ti, %~fi
This loop will recurse (/r) through all subdirectories (*) of our current directory (cd into c:\ if you want to go from the top), with an iterator variable of %i taking on the name of each file that we find. In our do clause, we turn off display of commands (@), and echo to standard output %~ti. That reference will display the timestamp associated with %i (that is, our file). As it turns out, the timestamp displayed here is the last modified time. We then display a comma (you'll see why shortly), followed by %~fi, which is a way to reference the full path of %i.

The output here will show modified_time, full_path_to_file, for all files in our given directory and its subdirectories.

(BTW, with the FOR /R, our iterator variable will only take on the value of file names... if you want files and directories, you could use FOR /D /R... yup... both /D and /R together in the same FOR loop).

You might think that we could sort them using the sort command. Unfortunately, Windows cmd.exe built-in sort is an alphanumeric sort, and cannot in anyway understand the dates we want to sort by. Ouch.

So, what can we do? Well, we could dump our output into a csv file thusly:
C:\> for /r %i in (*) do @echo %~ti, %~fi >> file_list.csv
Now you can see why I put that comma in between the timestamp and full file path. Now, we could open up that csv file in a spreadsheet, and sort it however we want. I know that's kinda cheating with respect to our rules of using only built-in features, but we simply lack a good sort program in cmd.exe. Thus, we often have to create csv's and use a spreadsheet.

But, wait... Hal threw us a bone with his follow-up command, which is looking for a file with a very particular date and timestamp during a forensics investigation. We can look for that easily in the output of our FOR /R loop, as follows:
C:\> for /r %i in (*) do @echo %~ti, %~fi | find "04/28/2009 02:06 PM"
Mr. Bucket mentioned to me that the forfiles command is worthy of a mention in this article. My first thought was... "That's a great tool, but it's only in the Resource Kits." I've used it before in investigations, and carry it around with me on a USB token along with a ton of other useful tools. But, Mr. Bucket's bringing it up did make me double check... and, lo and behold, forfiles is built-in to Vista and Windows 2008 Server! That's scrumptious! The best news I've had in the last 30 minutes, at the very least. Sorry, but it's not built into earlier versions of Windows, though, but is a separate download from the Resource Kits.

Using forfiles can really help us out here, and, on Vista and 2008, we've got it built in. Here's how we can satisfy Hal's original hankerin':
C:\> forfiles /p c:\ /s /d -2
This one will display files inside of c:\ (the /p means "path"), recursing subdirectories (/s), displaying those with a last modification date earlier than the current date minus two days. Note that the /d option can be used with a date as well, instead of a number of days, with the date expressed in MM/DD/YYYY format. Instead of a -, you can also use a + in front of the number or date to show all files modified after that given date.

So, we have many options... dir for really simple stuff, FOR /R and FOR /D /R for more complicated stuff, and forfiles if we're on Vista or 2008. It's nice to have options in life. :)