process Standard input writeline problem

by adamliq at 2013-03-02 03:51:47

Hi there,
I am currently having a problem with the following;
I am attempting to start a new cmd.exe process with redirection of input and output. The problem occurs when I send standardinput.writeline() nothing appears in the standardoutput.read().
Can anyone help.
Thank you.

Code example below.


##Start application
$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()

##Redirect input and output streams
$inputstream = $process.StandardInput
$outputstream = $process.StandardOutput

##Start encoder
$encoding = new-object System.Text.AsciiEncoding

##Read output stream
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$out

##Write input to stream
$command=read-host
#Example command I have used is ‘dir’
$inputstream.writeline($command)

##Verify Read output stream
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$out
##Problem lies here nothing is returned##
by MattG at 2013-03-03 14:18:08
From the looks of things, I’d say you’re trying to write yourself a reverse or bind shell. :stuck_out_tongue: In fact, that looks nearly identical to Dave Kennedy’s and Josh Kelley’s bind shell found here.

The reason you’re not getting output is because after you call writeline, you need to read one byte. After you do that, you’ll be able to read the next output buffer. I modified your script slightly to reflect this change and I put everything in a loop which will constantly accept new commands. As I’m sure you’re already aware, this is a raw shell and as such, its output will be ugly. Also note that you need to hit enter twice to get a command’s output to display. The following script should get you going for whatever (potentially evil) tasks you plan on carrying out:
##Start application
$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()

##Redirect input and output streams
$inputstream = $process.StandardInput
$outputstream = $process.StandardOutput

##Start encoder
$encoding = new-object System.Text.AsciiEncoding

$out = ''
##Read output stream
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$out
$out = ''

while ($true)
{
# Read next command
$command = Read-Host -Prompt 'Enter the next command'
$inputstream.writeline($command)

$out = $encoding.GetString($outputstream.Read())

##Verify Read output stream
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$out.TrimEnd($inputstream.NewLine)

$out = ''
}
by adamliq at 2013-03-05 03:26:07
You would be correct. It was from Dave Kennedy. I was attempting to use parts of it. I figure why reinvent the wheel.
Is there a reason why it needs to read one byte.
Thanking you.
by MattG at 2013-03-06 03:55:52
You need to read that extra byte in order to flush the buffer. You wouldn’t have to read the extra byte if you called Read and compared the resulting byte to -1.