Skip to content

Instantly share code, notes, and snippets.

@HarmJ0y
Last active August 31, 2022 17:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HarmJ0y/c4e7afc9048f1a124435 to your computer and use it in GitHub Desktop.
Save HarmJ0y/c4e7afc9048f1a124435 to your computer and use it in GitHub Desktop.
streams.ps1
# 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