New stuff, new stuff...
I've read a lot of interesting
articles recently about how Powershell can be used in a
variety of execution methods spanning various mediums. This lead me to grabbing hold of some malware and unwrapping the venom inside. Interestingly enough, there are some great features of PowerShell that can be used in a benign and even helpful way,
Good stuff, great stuff
Unwrapping the code was an interesting process in itself as the AV kept trying to bash the deobfuscated code as soon as it hit harddisk, but from the code, I found some really great functions for compression and obfuscation of scripts I thought were worthy of mention as I have used them myself:
String to Base64, Base64 to String Obfuscation
Function S-B64([parameter(ValueFromPipeline=$True, Mandatory=$True)]$i){[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($i))}
#Export-ModuleMember -Function S-B64
Function B64-S([parameter(ValueFromPipeline=$True, Mandatory=$True)]$i){[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($i))}
#Export-ModuleMember -Function B64-S
For example:
S-B64 'net' produces 'bmV0'
S-B64 'user' produces 'dXNlcg=='
S-B64 'Administrator' produces 'QWRtaW5pc3RyYXRvcg=='
S-B64 'secretPass' produces 'c2VjcmV0UGFzcw=='
In your script:
Function B64-S([parameter(ValueFromPipeline=$True, Mandatory=$True)]$i){[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($i))}
& (B64-S 'bmV0') (B64-S 'dXNlcg==') (B64-S 'QWRtaW5pc3RyYXRvcg==') (B64-S 'c2VjcmV0UGFzcw==')
This is written as two functions, but if used just once in a script, you wrap can the second function around that base string to present the results to a variable or function.
Invoke-Expression "[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('V3JpdGUtSG9zdCAnV2Fzc3VwLCBidWQ/Jw=='))"
File to Base64? Yes we can.
function F-B64([string]$p=''){
if(!(Test-Path $p)){throw 'F-B64: File path invalid'}
try{$b=[IO.File]::ReadAllBytes($p)}catch{throw 'F-B64: File Read Fail'}
if($b){[Convert]::ToBase64String($b)}else{throw 'F-B64: No data received'}
}
#Export-ModuleMember -Function B64-S
function B64-F([parameter(ValueFromPipeline=$True, Mandatory=$True)]$d,[string]$p=''){
if($p){if(Test-Path $p){throw 'B64-F: File already exists'}}else{throw 'B64-F: File path empty'}
$a=[Convert]::FromBase64String($d)
try{[IO.File]::WriteAllBytes($p,$a)}catch{throw 'B64-F: Write Access Fail'}
}
#Export-ModuleMember -Function B64-F
Simple as, read the file as bytes, convert to base64. Read out in the same way. Now binaries can be implanted into script files as strings. Nice and easy way to carry tools without AVs sniping them off your USB sticks. The resultant Base64 string is huge... Actually much larger in size than the original executable, but this is heavily mitigated by the next set of functions.
Compressing it further...
function S-CB64([parameter(ValueFromPipeline=$True,Mandatory=$True)]$d){
$m=New-Object IO.MemoryStream
$g=New-Object IO.Compression.GZipStream($m,[IO.Compression.CompressionMode]::Compress)
$s=New-Object IO.StreamWriter($g)
$s.Write($d)
$s.Close()
[Convert]::ToBase64String($m.ToArray())
}
#Export-ModuleMember -Function S-CB64
function CB64-S([parameter(ValueFromPipeline=$True,Mandatory=$True)]$d){
$a=[Convert]::FromBase64String($d)
$m=New-Object IO.MemoryStream
$m.Write($a,0,$a.Length)
$null=$m.Seek(0,0)
$g=New-Object IO.Compression.GZipStream($m,[IO.Compression.CompressionMode]::Decompress)
$s=New-Object IO.StreamReader($g)
$s.readtoend()
}
#Export-ModuleMember -Function CB64-S
OK, so now, we push that one stage further and realise that, with Invoke-Expression we can run entire scripts (to unnaturally powerful effects), how can we reduce the size of the payload? The malware already had the answer. Use a Gzip compression stream. Push the script in one side and grab the Base64 of the compressed script, then spit it into IEX on the user side. This will turn large scripts into quite tiny strings and compressed B64 strings from files are a near match to the original executable size.
What I learned???
PowerShell is living up to its name. By leveraging COM, .Net, Win32API and whatever else it can get into with all their varying execution methods, PowerShell
can execute any data however it wants. There's good and bad to this, but this just amplifies the very name of it. It takes me much longer to produce a refined C# application that can be powerful than it does to slap out a quick script with the limited tools available, but Powershell brings me both at once, which is very powerful indeed.
Footnote
This dissemination of code and the understanding of it was made massively easier by using
ISESteroids for contextual help, window shuffling, code cleaning and generally a better overall Powershell experience. Still raving about this.