Last active
August 31, 2022 17:34
-
-
Save HarmJ0y/c4e7afc9048f1a124435 to your computer and use it in GitHub Desktop.
streams.ps1
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
# these functions all you to enumerate, add, and remove alternate data streams | |
# it can function as a bootleg replacement for Sysinternals' streams.exe | |
function Find-Streams { | |
<# | |
.SYNOPSIS | |
Enumerates all alternate data streams for a specified path. | |
If no path is provided, the current path is used. | |
Author: @harmj0y | |
License: BSD 3-Clause | |
.PARAMETER Path | |
The path to resursively enumerate for streams. | |
.PARAMETER Delete | |
Delete all streams found. | |
.EXAMPLE | |
> Find-Streams -Path C:\ | |
Find all alternate data streams in the C:\ drive. | |
.EXAMPLE | |
> Find-Streams -Path C:\ -Delete | |
Find and delete all alternate data streams in the C:\ drive. | |
#> | |
[CmdletBinding()] | |
param( | |
[string] | |
$Path = ".\", | |
[switch] | |
$Delete | |
) | |
function Find-ADS { | |
$dir = ''; | |
$(cmd /c dir /a /r /S) | %{ | |
if ($_ -match ' Directory of'){ | |
$dir = $(($_ -split ' Directory of ')[1]); | |
}; | |
if ($_ -match '\$DATA' ){ | |
$parts = $($_.trim() -split " "); | |
$file = $($parts[1..$parts.Length]) -join " "; | |
if (-not $file.StartsWith(".")){ | |
"$dir\$file" | |
} | |
} | |
} | |
} | |
if($Delete){ | |
Find-ADS | Remove-Stream | |
} | |
else{ | |
Find-ADS | |
} | |
} | |
function Remove-Stream { | |
<# | |
.SYNOPSIS | |
Removes an alterate data stream from a specified location. | |
P/Invoke code adapted from PowerSploit's Mayhem.psm1 module. | |
Author: @harmj0y, @mattifestation | |
License: BSD 3-Clause | |
.LINK | |
https://github.com/mattifestation/PowerSploit/blob/master/Mayhem/Mayhem.psm1 | |
#> | |
[CmdletBinding()] Param( | |
[Parameter(Position=0,Mandatory=$True,ValueFromPipeline=$true)] | |
[string]$Path | |
) | |
process { | |
if ($($Path.split("\")[-1]).contains(":")){ | |
if($Path.EndsWith(":")){ $Path += '$DATA' } | |
#region define P/Invoke types dynamically | |
# stolen from PowerSploit https://github.com/mattifestation/PowerSploit/blob/master/Mayhem/Mayhem.psm1 | |
$DynAssembly = New-Object System.Reflection.AssemblyName('Win32') | |
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) | |
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32', $False) | |
$TypeBuilder = $ModuleBuilder.DefineType('Win32.Kernel32', 'Public, Class') | |
$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String])) | |
$SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError') | |
$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, | |
@('kernel32.dll'), | |
[Reflection.FieldInfo[]]@($SetLastError), | |
@($True)) | |
# Define [Win32.Kernel32]::DeleteFile | |
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('DeleteFile', | |
'kernel32.dll', | |
([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), | |
[Reflection.CallingConventions]::Standard, | |
[Bool], | |
[Type[]]@([String]), | |
[Runtime.InteropServices.CallingConvention]::Winapi, | |
[Runtime.InteropServices.CharSet]::Ansi) | |
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute) | |
$Kernel32 = $TypeBuilder.CreateType() | |
$Result = $Kernel32::DeleteFile($Path) | |
if ($Result){ | |
Write-Verbose "Alternate Data Stream at $Path successfully removed." | |
} | |
else{ | |
Write-Verbose "Alternate Data Stream at $Path removal failure!" | |
} | |
$Result | |
} | |
else{ | |
Write-Warning "[!] Path $Path is not an alternate data stream." | |
} | |
} | |
} | |
function Get-Stream { | |
<# | |
.SYNOPSIS | |
Returns the content of a specified alternate data stream. | |
.PARAMETER Path | |
The path of the stream to get the content for. | |
.EXAMPLE | |
> Find-Streams -Path C:\Users\lab\Appdata:stream.txt | |
Returns the content of the ADS at C:\Users\lab\Appdata:stream.txt | |
#> | |
[CmdletBinding()] Param( | |
[Parameter(Position=0,Mandatory=$True,ValueFromPipeline=$true)] | |
[string]$Path | |
) | |
process { | |
if ($($path.split("\")[-1]).contains(":")){ | |
if($Path.EndsWith(":")){ $Path += '$DATA' } | |
Invoke-Command -ScriptBlock {cmd /C "more < $Path"} | |
} | |
else{ | |
Write-Warning "[!] Path $Path is not an alternate data stream." | |
} | |
} | |
} | |
function Add-Stream { | |
<# | |
.SYNOPSIS | |
Adds content to a specified alternate data stream. | |
Adapted from @enigma0x3's Invoke-ADSBackdoor. | |
.PARAMETER Path | |
The path of the stream to get the content for. | |
.EXAMPLE | |
> Find-Streams -Path C:\Users\lab\Appdata:stream.txt | |
Returns the content of the ADS at C:\Users\lab\Appdata:stream.txt | |
.LINK | |
https://github.com/enigma0x3/Invoke-AltDSBackdoor/blob/master/Invoke-ADSBackdoor.ps1 | |
#> | |
[CmdletBinding()] Param( | |
[Parameter(Position=0,Mandatory=$True)] | |
[string]$Path, | |
[Parameter(Position=1,Mandatory=$True,ValueFromPipeline=$true)] | |
$Content | |
) | |
process { | |
if ($($path.split("\")[-1]).contains(":")){ | |
if($Path.EndsWith(":")){ $Path += '$DATA' } | |
Invoke-Command -ScriptBlock {cmd /C "echo $Content > $Path"} | |
} | |
else{ | |
Write-Warning "[!] Path $Path is not an alternate data stream." | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment