TCP Proxy Using Python - python

I am studying Black Hat Python and trying to understand the TCP proxy code.
I now almost understand it, but it doesn't quite work when I try to test it with
python proxy.py localhost 21 ftp.target.ca 21 True
in one terminal and
ftp ftp.target.ca 21
in another.
In the first terminal, I get only listen on localhost on port 21 and nothing else; and in the second terminal, it's happen connection between me and server and I wrote username and password.
The packages that transfer between me and server should appear in the first terminal.
What am I doing wrong?
Here is the code:
import sys
import socket
import threading
# this is a pretty hex dumping function directly taken from
# http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, unicode) else 2
for i in xrange(0, len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
print b'\n'.join(result)
def receive_from(connection):
buffer = ""
# We set a 2 second time out depending on your
# target this may need to be adjusted
connection.settimeout(2)
try:
# keep reading into the buffer until there's no more data
# or we time out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except:
pass
return buffer
# modify any requests destined for the remote host
def request_handler(buffer):
# perform packet modifications
return buffer
# modify any responses destined for the local host
def response_handler(buffer):
# perform packet modifications
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
# connect to the remote host
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))
# receive data from the remote end if necessary
if receive_first:
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
# send it to our response handler
remote_buffer = response_handler(remote_buffer)
# if we have data to send to our local client send it
if len(remote_buffer):
print "[<==] Sending %d bytes to localhost." % len(remote_buffer)
client_socket.send(remote_buffer)
# now let's loop and reading from local, send to remote, send to local
# rinse wash repeat
while True:
# read from local host
local_buffer = receive_from(client_socket)
if len(local_buffer):
print "[==>] Received %d bytes from localhost." % len(local_buffer)
hexdump(local_buffer)
# send it to our request handler
local_buffer = request_handler(local_buffer)
# send off the data to the remote host
remote_socket.send(local_buffer)
print "[==>] Sent to remote."
# receive back the response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print "[<==] Received %d bytes from remote." % len(remote_buffer)
hexdump(remote_buffer)
# send to our response handler
remote_buffer = response_handler(remote_buffer)
# send the response to the local socket
client_socket.send(remote_buffer)
print "[<==] Sent to localhost."
# if no more data on either side close the connections
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print "[*] No more data. Closing connections."
break
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host,local_port))
except:
print "[!!] Failed to listen on %s:%d" % (local_host,local_port)
print "[!!] Check for other listening sockets or correct permissions."
sys.exit(0)
print "[*] Listening on %s:%d" % (local_host,local_port)
server.listen(5)
while True:
client_socket, addr = server.accept()
# print out the local connection information
print "[==>] Received incoming connection from %s:%d" % (addr[0],addr[1])
# start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))
proxy_thread.start()
def main():
# no fancy command line parsing here
if len(sys.argv[1:]) != 5:
print "Usage: ./proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True"
sys.exit(0)
# setup local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
# setup remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
# this tells our proxy to connect and receive data
# before sending to the remote host
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
# now spin up our listening socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
main()

Simply running a proxy server on port 21 won't make the ftp client use it - so you shouldn't be trying to connect to the remote host. if the commandline is running the proxy on for example 9000, then ftp to that port i.e. localhost 9000 and the proxy will forward communication to/from that remote host.

Related

Python client hanging when sending empty message to server

I have a python reverse shell that I am working on that utilizes a client-server connection using TCP. I am testing them both right now on my localhost windows machine and I am utilizing the subprocess library to handle commands. The client is supposed to send a command to the server and the server will reply back with the output.
Server:
import socket
import subprocess
import os
# Server
# creates TCP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# port and server ip(localhost)
LOCAL_HOST = '127.0.0.1'
PORT = 5565
BUFFER_SIZE = 5000 # size of message
no_char_message = "-1: Please enter a command"
# test connection
print("Server starting up on %s with port number %s" % (LOCAL_HOST, PORT))
# bind socket to ip and port
sock.bind((LOCAL_HOST, PORT))
# listen to socket
sock.listen(1)
# socket will accept connection and client address
print("Waiting for connection") # waiting for connection
connection, address = sock.accept() # accept connection with client address
print("Connected to", address) # connected by address
while True:
command = connection.recv(BUFFER_SIZE) # receive message from client
if not command:
break
if len(command) == 0:
connection.send(str.encode(no_char_message))
if len(command) > 0:
terminal = subprocess.Popen(command[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = terminal.stdout.read() + terminal.stderr.read()
output_as_string = str(output, "utf-8")
connection.send(str.encode(output_as_string))
print(output_as_string)
print("Closing Server")
sock.close()
connection.close()
Client
import socket
# Client
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # creates TCP Socket
# local host and port
LOCAL_HOST = '127.0.0.1'
PORT = 5565
BUFFER_SIZE = 5000 # size of message
# connect socket to ip and port
sock.connect((LOCAL_HOST, PORT))
print("Connected to server\n")
while True:
message = input("Please enter a command:\n") # ask user to input message
if message == 'quit':
break
print("Sending %s" % message)
sock.send(str.encode(message)) # send message
command = str(sock.recv(BUFFER_SIZE), "utf-8") # receive message
print("received %s" % command)
print("closing connection with server")
sock.close()
The issue is when I send an empty message to the server it hangs and just says sending in the terminal and the server never receives anything. I am not sure what is causing this but I am assuming the pipes are being blocked or that I am not handling this correctly.
I want the server to return an error message to the client rather than handle the message error in the client itself.
I tried checking the condition if the length of the command is 0 and handling it with an error message but it did not work and still hangs.
The program also seems to hang when I try for example the date command.
In general, how do I handle the condition if a command is not recognized, empty or doesn't execute successfully?
TCP has no concept of an empty message. TCP has no concept of a message at all, it knows only bytes. Thus, if you call send with an empty string it will simply send nothing (not an empty packet but no packet at all) to the server which means that there is nothing for the server to receive - it will still block while waiting for data. In other words: there is no empty command, there is simply no comment at all.
if len(command) == 0:
This will not check for an empty message (which again does not exist) but will trigger if the client closes the connection. Any check for an empty command had to be done at the client already.

Multithreaded socket gets closed before remote script execution over

Using Python 2.6.6, I am not able to get complete data from client script as suspecting the socket gets closed before the client script execution is over, while the client script working fine if I manually trigger the script on the remote server.
What script does -
Trigger SCRIPT
Only to transfer the client script [agent.py] and trigger remotely using multithread.
Client SCRIPT
agent.py would be transferred to target servers [1000+]
running on (1000+) remote servers [linux] to collect data and return
a list of dictionary from each remote machine back to Server
Server SCRIPT
Receives the data and convert to CSV
Client Script - agent.py
s = socket.socket() # Create a socket object
host = "<SERVER_HOST>" # server ip
port = 12345 # Reserve a port for your service.
try:
s.connect((host, port))
instlist = []
infoCollect = processInfo() #get the info in dictionary object
instlist.append(infoCollect)
data_string = str(instlist)
s.sendall(data_string)
s.send(",")
s.shutdown(socket.SHUT_WR)
print('Sent ',(instlist))
s.close()
Server Script [DataCollector]:
class ThreadedServer(object):
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(5)
print 'Started Listening....'
while True:
client, address = self.sock.accept()
print 'Got connection from', address
client.settimeout(60)
threading.Thread(target = self.listenToClient,args = (client,address)).start()
def listenToClient(self, client, address):
size = 1024
while True:
try:
l = client.recv(size)
while (l):
print ("Receiving...%s" % l)
f.write(l)
l = client.recv(size)
print "Instance Details Recieved"
client.send('Thank you for connecting')
except:
client.close()
return False
if __name__ == "__main__":
while True:
port_num = input("Port? ")
try:
port_num = int(port_num)
break
except ValueError:
pass
f = open(array_data,'wb')
ThreadedServer('',port_num).listen()
Trigger Script - This script's purpose is to initiate this all process and place the Client Script [agentScript] on 1000+ servers and execute remotely
cmd = "python agent.py"
takeLock = threading.Lock()
def worker(host):
ssh = paramiko.SSHClient() # Initiate SSH Object
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(host, username='user', password='pass' )
sftp = ssh.open_sftp() #sedning files to parellaly to all listed servers
sftp.put(__file__, 'excludelist')
sftp.close()
stdin, stdout, stderr = ssh.exec_command(cmd)
while not stdout.channel.exit_status_ready():
# Print Only data when available
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print alldata
return (str(alldata))
ssh.close()
except socket.error, v:
print "Connection Refused"
def main():
with open('IPlist.txt') as ip:
hosts = ip.read().splitlines()
threads = []
for h in hosts:
t = threading.Thread(target=worker, args=(h,))
t.start()
threads.append(t)
for t in threads:
t.join()
if __name__ == "__main__":
main()
NOTE: Client Script [agent.py] takes 1-5 sec depends on the server's
configuration to generate output and return value
PROBLEM - Incomplete Data populating at server side like -
When I trigger script manually on remote machine to test it send complete dictionary object like [{commonServerData},{a,b,c,d},{Engine02Data},{tempData,tempData02}] and so server recives the same data
When agent.py is invoked using trigger script it sends incomplete data like-
[{commonServerData},{a,b,c,d}] for all 1000+ srervers.
I am suspecting something wrong with my Trigger Script which does close the socket session of the remote server even before the agent.py gets completed.
Removed extra comma s.send(',') and added it to s.sendall(data_string + ',') from the client script does the expected work -
s = socket.socket() # Create a socket object
host = "<SERVER_HOST>" # server ip
port = 12345 # Reserve a port for your service.
try:
s.connect((host, port))
instlist = []
infoCollect = processInfo() #get the info in dictionary object
instlist.append(infoCollect)
data_string = str(instlist)
s.sendall(data_string + ',')
s.shutdown(socket.SHUT_WR)
print('Sent ',(instlist))
s.close()

How to call a function after some interval in python server?

I've a python socket server which listens to HTTP requests. It returns ip address and it's port after randomly choosing from a list of ip adresses. This result is generated by another file which fetches it from a database. The database is continuously updated. I want the list to be updated after every 10 requests or after 100 seconds any one of them will work. The below code doesn't work for me. The connection gets reset after every five requests. I printed the count and it increased to 10 after every 5 requests. Can anyone tell me what I'm missing here ?
result=get_ip() # Get a list of dictionary by calling get_ip() function
HOST, PORT = '127.0.0.1', 8890
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(10)
print 'Serving HTTP on port %s ...' % PORT
count = 0
while True:
if count % 10 == 0:
result=get_ip()
count +=1
client_connection, client_address = listen_socket.accept()
rand_ip = random.choice(result)
ip = rand_ip["ip"]
port = rand_ip["port"]
client_connection.sendall(ip+":"+port)
client_connection.close()
The problem comes from the close. It is dangerous to close a socket immediately after writing something into it. You should first shutdown the socket to make the peer to have a 0 read indicating a proper and of stream
So you script should end with:
client_connection.sendall(ip+":"+port)
try:
client_connection.shutdown(socket.SHUT_WR) # signal end of strem
while True: # wait for the client to close or shutdown his side
q = client_connection.recv(1024)
if len(q) == 0:
break
finally:
client_connection.close() # close the socket only after the client has close its side

how do i get socket to accept more than one connection?

Currently I have a socket server that can only accept ONE connection. Any second connection, it just hangs and not do anything.
The server can get the message send from one client. I have the server to send back confirmation only for now.
server.py:
import socket, sys
# some vars
HOST = "localhost";
PORT = 4242;
# create the socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
# bind the socket to port
server_addr = (HOST, PORT);
print >>sys.stderr, "starting server %s on port %s" % (HOST, PORT);
soc.bind(server_addr);
# check for connections
soc.listen(1);
while True:
# wait for a connection
connection, client_address = soc.accept();
try:
# since just test
# just send back whatever server receives
while True:
data = connection.recv(16);
if data:
connection.sendall(str(client_address[1]) + " said " + data);
finally:
connection.close();
client.py:
import socket, sys, thread
# some vars
HOST = "localhost";
PORT = 4242;
# create the socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
# connect to server/port
server_addr = (HOST, PORT);
print >>sys.stderr, "connecting to %s on port %s" % (HOST, PORT);
soc.connect(server_addr);
# try to send data over
while True:
try:
# send the message
msg = raw_input("Message: ");
soc.sendall(msg);
# check if there is response
amt_recd = 0;
amt_expd = len(msg);
while amt_recd < amt_expd:
data = soc.recv(16);
amt_recd += len(data);
print >>sys.stderr, data, "\n";
finally:
msg = '';
There is no exit condition from this infinite loop in the server:
while True:
data = connection.recv(16)
if data:
connection.sendall(str(client_address[1]) + " said " + data)
If the client closes the connection data will be empty, but it will still continue looping. To fix:
while True:
data = connection.recv(16)
if not data:
break
connection.sendall(str(client_address[1]) + " said " + data)
Also, even after fixing this the server can only handle one connection at a time. If you desire to service multiple clients at once, you'll need to use select.select or spin off threads for each client connection.
As an aside, Python does not require semicolons at the end of statements.

Socket Programming Issue - Python

Alright, I've spent about three hours fiddling with socket programming in Python trying to make a simple chat program. I've gotten the client to send text to the server and then, from then client, it repeats the message to it's self. However, I want the message to be sent to the server and then the server, not the client, re-send it to all client's connected. I'm having issues doing this. This is my code so far:
Server Side Code:
import SocketServer
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print "%s wrote:" % self.client_address[0]
print data
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 25555
server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
Client Side Code:
import socket
import sys
global HOST
global PORT
HOST, PORT = "localhost", 25555
while 1 > 0:
data = raw_input(">".join(sys.argv[1:]))
# SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# As you can see, there is no connect() call; UDP has no connections.
# Instead, data is directly sent to the recipient via sendto().
sock.sendto(data + "\n", (HOST, PORT))
received = sock.recv(1024)
print "Sent: %s" % data
print "Received: %s" % received
Right now your app is instantiating the MyUDPHandler class for each client connection. When the connection is opened you need to store that instance to a static array or queue. Then when the handle() call is made it can loop through all those sockets and send a copy of the data to each of them.
I'd checkout the python documentation; it basically does what your looking to: http://docs.python.org/library/socketserver.html#asynchronous-mixins
And what I'd change from that example (Don't just drop this in; it probably has glaring bugs!):
handlerList = []
class ...
def handle(self):
handlerList.append(self)
while (1):
data = self.request.recv(1024)
if (not data):
break
cur_thread = threading.currentThread()
response = "%s: %s" % (cur_thread.getName(), data)
for x in handlerList:
x.request.send(response)
psudo_code_remove_self_from_handlerList()
Would you like to play with a server that echos packets to all sockets but the original source of the data?
import socket, select
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 8989))
server.listen(5)
sockets = [server]
while True:
for sender in select.select(sockets, [], [])[0]:
if sender is server:
sockets.append(server.accept()[0])
else:
try:
message = sender.recv(4096)
except socket.error:
message = None
if message:
for receiver in sockets:
if receiver not in (server, sender):
receiver.sendall(message)
else:
sender.shutdown(socket.SHUT_RDWR)
sender.close()
sockets.remove(sender)
if __name__ == '__main__':
main()

Categories