简体   繁体   中英

Execute CMD commands over socket in Python 3

I am trying to do something similar to this: Execute CMD commands using python but I don't think that gave a clear answer and it is three years ago, so I am asking again.

I have a TCP connection between a server and client. That means that I am able to make screenshots upload files and similar stuff. Pretty useful to have actually!

In my code I first establish a connection on the server and client side. Then they are connected and I can send commands with

conn.send("text".decode())

and receive it on the client side with

some_text = s.recv(1024) #bytes
print(some_text.decode)

I can send commands to the server from the client too with

s.send("text".decode())

and receive text on the server side with

some_text = conn.recv(1024)
print(some_text.decode())

The thing is that I currently have a

while True

loop where I ask the server: Please enter a command and it loops trough a couple of if statements asking:

if command == "screenshot":
    #Make screenshot
elif command == "upload_file":
    #Upload file

=>
I want this to look like a person has opened a command prompt

Microsoft Windows [Version 10.0.18363.1198]
(c) 2019 Microsoft Corporation. Alle rettigheder forbeholdes.

C:\Users\Lukas>

and when the user for instance types ipconfig everything that it outputs should be seen on the server side with a print statement. The person controlling the server can then type a new command and it will look as if it the actual command prompt opened inside of my server.py file


I currently have looked up the Turtle reverse shell built in Python.

This is the code that they use

server.py

data = s.recv(1024)
        if data[:2].decode("utf-8") == 'cd':
            os.chdir(data[3:].decode("utf-8"))
        if len(data) > 0:
            cmd_command = subprocess.Popen(data[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
            output_bytes = cmd_command.stdout.read() + cmd_command.stderr.read()
            output_str = str(output_bytes, "utf-8")
            s.send(str.encode(output_str + str(os.getcwd()) + '> '))
            print(output_str)

client.py

 data = s.recv(1024) if data[:2].decode("utf-8") == 'cd': os.chdir(data[3:].decode("utf-8")) if len(data) > 0: cmd_command = subprocess.Popen(data[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) output_bytes = cmd_command.stdout.read() + cmd_command.stderr.read() output_str = str(output_bytes, "utf-8") s.send(str.encode(output_str + str(os.getcwd()) + '> ')) print(output_str)

When I paste it into my code and modify a the cmd variable name (I have the exact same in my script) some commands work like: shutdown -s -t 100 -c "StackOverflow" but others don't like. When I for instance run dir it shows me nothing and keeps doing so forever. I can't type anything in.


Pictures:
Server.py CMD function
Client.py CMD function
When I run a cmd command: example "shutdown.." it shows a shutdown dialog on my computer. This is the only command that seems to work.

TCP sockets are stream-based, not message-based. You have no way of knowing whether a

data = s.recv(1024)

actually receives all of a message (since TCP itself doesn't have a concept of messages). That 1024 is just how much you're willing to receive at most . This means it's basically sheer luck that things may or may not work.

You will need to come up with some sort of encapsulation scheme within your stream in order to reliably send messages of various types and lengths; a simple one would be a basic TLV scheme, eg each message in your protocol is eg

  • message type (4 bytes)
  • message length (4 bytes)
  • message data ( length bytes)

This way your message-receiving end ends up looking like

# TODO: Will crash if there is less than 8 bytes available to read
type, length = struct.unpack("!II", s.recv(8))

data = b""
while len(data) < length:
    max_recv = max(0, length - len(data))
    data += s.recv(max_recv)
assert len(data) == length
# do stuff with data

and your sending end is

data = b"blahblahblah" * 60  # arbitrary data
type = 1234  # could be something else
header = struct.pack("!II", type, len(data))
sock.sendall(header)
sock.sendall(data)

As for message types, you could eg have a message type for "starting command output", "command line output", "ending command output", whatever.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM