After a request to add the capability to PowerSploit, I wanted to figure out how to do it (I do prefer avoiding writing anything to disk, but there are times when it is unavoidable). I always thought that TimeStomp was black magic, but then I noticed the capability in Cobalt Strike's Beacon. I asked Raphael and he pointed me to a well-documented part of the Windows API. So naturally I headed over to pinvoke.net to check out the C# sample. It didn't take long to have a working function, but I got curious and found a .Net class to simplify the code. Armed with two working functions, I boarded the plane after ShowMeCon and wondered if it were possible to accomplish the task in a more "PowerShelly" (technical term) way.
Lets explore with Get-Member:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PowerShell.exe -com {$file=(gi c:\demo\test.txt);$date='01/03/2006 12:12 pm';$file.LastWriteTime=$date;$file.LastAccessTime=$date;$file.CreationTime=$date} |
Nothing novel, but cool nonetheless. Some people would prefer a more "Touch" like capability, so I wrapped it all up in a function called Set-MacAttributes which will be added to PowerSploit soon:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Set-MacAttribute { | |
<# | |
.SYNOPSIS | |
Sets the modified, accessed and created (Mac) attributes for a file based on another file or input. | |
PowerSploit Function: Set-MacAttribute | |
Author: Chris Campbell (@obscuresec) | |
License: BSD 3-Clause | |
Required Dependencies: None | |
Optional Dependencies: None | |
Version: 1.0.0 | |
.DESCRIPTION | |
Set-MacAttribute sets one or more Mac attributes and returns the new attribute values of the file. | |
.EXAMPLE | |
PS C:\> Set-MacAttribute -FilePath c:\test\newfile -OldFilePath c:\test\oldfile | |
.EXAMPLE | |
PS C:\> Set-MacAttribute -FilePath c:\demo\test.xt -All "01/03/2006 12:12 pm" | |
.EXAMPLE | |
PS C:\> Set-MacAttribute -FilePath c:\demo\test.txt -Modified "01/03/2006 12:12 pm" -Accessed "01/03/2006 12:11 pm" -Created "01/03/2006 12:10 pm" | |
.LINK | |
http://www.obscuresec.com/2014/05/touch.html | |
#> | |
[CmdletBinding(DefaultParameterSetName = 'Touch')] | |
Param ( | |
[Parameter(Position = 1,Mandatory = $True)] | |
[ValidateNotNullOrEmpty()] | |
[String] | |
$FilePath, | |
[Parameter(ParameterSetName = 'Touch')] | |
[ValidateNotNullOrEmpty()] | |
[String] | |
$OldFilePath, | |
[Parameter(ParameterSetName = 'Individual')] | |
[DateTime] | |
$Modified, | |
[Parameter(ParameterSetName = 'Individual')] | |
[DateTime] | |
$Accessed, | |
[Parameter(ParameterSetName = 'Individual')] | |
[DateTime] | |
$Created, | |
[Parameter(ParameterSetName = 'All')] | |
[DateTime] | |
$AllMacAttributes | |
) | |
Set-StrictMode -Version 2.0 | |
#Helper function that returns an object with the MAC attributes of a file. | |
function Get-MacAttribute { | |
param($OldFileName) | |
if (!(Test-Path $OldFileName)){Throw "File Not Found"} | |
$FileInfoObject = (Get-Item $OldFileName) | |
$ObjectProperties = @{'Modified' = ($FileInfoObject.LastWriteTime); | |
'Accessed' = ($FileInfoObject.LastAccessTime); | |
'Created' = ($FileInfoObject.CreationTime)}; | |
$ResultObject = New-Object -TypeName PSObject -Property $ObjectProperties | |
Return $ResultObject | |
} | |
#test and set variables | |
if (!(Test-Path $FilePath)){Throw "$FilePath not found"} | |
$FileInfoObject = (Get-Item $FilePath) | |
if ($PSBoundParameters['AllMacAttributes']){ | |
$Modified = $AllMacAttributes | |
$Accessed = $AllMacAttributes | |
$Created = $AllMacAttributes | |
} | |
if ($PSBoundParameters['OldFilePath']){ | |
if (!(Test-Path $OldFilePath)){Write-Error "$OldFilePath not found."} | |
$CopyFileMac = (Get-MacAttribute $OldFilePath) | |
$Modified = $CopyFileMac.Modified | |
$Accessed = $CopyFileMac.Accessed | |
$Created = $CopyFileMac.Created | |
} | |
if ($Modified) {$FileInfoObject.LastWriteTime = $Modified} | |
if ($Accessed) {$FileInfoObject.LastAccessTime = $Accessed} | |
if ($Created) {$FileInfoObject.CreationTime = $Created} | |
Return (Get-MacAttribute $FilePath) | |
} |
I think its a prime example of why you should start by exploring cmdlets, then check out .Net and finally the API. It can save you a lot of time when you are building PowerShell tools. Obviously this won't stand up to forensic scrutiny like TimeStomp will, but it will definitely serve the purpose of hiding files in plain sight.
-Chris