5

I an trying to use Paramiko with SOCKS proxy (SecureCRT or PuTTY configured as SOCKS proxy). I am using the below code

import paramiko,socks

host, port = '127.0.0.1', 1080

# Set up your proxy information for this socket
sock=socks.socksocket()
sock.set_proxy(
    proxy_type=socks.SOCKS4,
    addr=host,
    port=port,
)

# Connect the socket
sock.connect((host, port))

# Create your Paramiko Transport
transport = paramiko.Transport(sock)
transport.connect(
    username='username',     #<------not sure if it is needed, the socks proxy needs no username/password
    password='secret',
)
client = paramiko.client.SSHClient.connect('remotedevice', username='usernameonremotedevice',sock=sock)
stdin, stdout, stderr=client.exec_command("ls -la")
# Do stuff

# Clean up
client.close()
transport.close()

The above approach seems to confuse Paramiko since it is using 127.0.0.1 for both. My issue originated in the Paramiko libraries used by Exscript so I wanted to simplify to see if this would work ....

This is the log that SecureCRT shows with each attempt

[LOCAL] : Starting port forward from 127.0.0.1 on local 127.0.0.1:1080 to remote 127.0.0.1:1080.  
[LOCAL] : Could not start port forwarding from local service 127.0.0.1:3106 to 127.0.0.1:1080.  Reason: The channel could not be opened because the connection failed.  Server error details:     Connection refused  

The script fails like below:

Traceback (most recent call last):
  File "C:\Users\Username\Documents\Eclipse\ESNetworkDiscovery\ParamikoProxyTest.py", line 24, in <module>
    sock.connect((host, port))
  File "C:\Utils\WPy2.7-32\python-2.7.13\lib\site-packages\socks.py", line 96, in wrapper
    return function(*args, **kwargs)
  File "C:\Utils\WPy2.7-32\python-2.7.13\lib\site-packages\socks.py", line 813, in connect
    negotiate(self, dest_addr, dest_port)
  File "C:\Utils\WPy2.7-32\python-2.7.13\lib\site-packages\socks.py", line 667, in _negotiate_SOCKS4
    raise SOCKS4Error("{0:#04x}: {1}".format(status, error))
socks.SOCKS4Error: 0x5b: Request rejected or failed
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
MiniMe
  • 1,057
  • 4
  • 22
  • 47

2 Answers2

9

The answer by @pynexj is correct, but having a full working example is always nice:

import socks
import paramiko

sock=socks.socksocket()
sock.set_proxy(
    proxy_type=socks.SOCKS5,
    addr="proxy.host.name.example",
    port=1080,
    username="blubbs",
    password="blabbs"
)
sock.connect(('ssh.host.name.example', 22))

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('ignored without host key verification', username='caesar', sock=sock)
print((ssh.exec_command('ls')[1]).read().decode())
ssh.close()

(Would be nice to know if sock has to be closed separately…)

Side note: Make sure to not use password authentication together with AutoAddPolicy. Preferrably, don't use password authentication at all. (See comments.)

Caesar
  • 6,733
  • 4
  • 38
  • 44
  • Obligatory warning: Do not use `AutoAddPolicy` this way – You are losing a protection against [MITM attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) by doing so. For a correct solution, see [Paramiko "Unknown Server"](https://stackoverflow.com/q/10670217/850848#43093883). – Martin Prikryl Jun 22 '22 at 08:34
  • Ironically, the top voted answer on that question says to use `AutoAddPolicy`. Also somewhat OT, but aren't you protected from MITM when using public key authentication? (I was using this to connect to a short-lived cloud instance precisely once, so remembering host keys did me little good.) – Caesar Jun 22 '22 at 10:56
  • How would an MITM add their PK to the server's `authorized_keys`? They'd have to get/steal a shell/sftp, right? I was [under the impression](https://security.stackexchange.com/a/75753/221359) that precisely that is impossible. – Caesar Jun 22 '22 at 12:26
  • 1
    First, the top-voted answer is five years older than mine. Second, people prefer easy "solution" over correct one. *(you were right about the public key auth)* – Martin Prikryl Jun 22 '22 at 12:32
3

sock.connect((host, port)) should use the SSH server's hostname (the same host you use for SSHClient.connect()) and port (default 22).

pynexj
  • 19,215
  • 5
  • 38
  • 56