Reverse shell using Python

Jithesh Chandrasekharan
5 min readSep 18, 2020

--

A simple reverse shell application using python

What is a reverse shell?

In a regular client-server scenario, the client sends commands to the server but in case of reverse shell, the server sends commands to the client. Even though this term is very popular in hacking, let us think about how we can use it in a good way.

Let’s say you have a computer ignorant friend who wants your help to find an important document in his PC. You asked him to type some commands in his terminal, but he is struggling.
Unfortunately, the remote desktop connection to his PC is not working. After some attempts, you decided to write a program that he can run in his PC which will connect to a server running in your PC.
So what should that client program do? When your friend launch that application(at least your friend know how to double click), it would connect to a server listening in your PC and you can send commands to the client, which will execute those commands and sends the response to you.

Let us start with basic server and client and from there we will expand it.

Basic Server

Our server is listening on localhost port 9090 for a new connection. When a client joins, it will send its hostname and our server will print the hostname and address of the client joined.

Basic Client

Our client will connect to our server running in localhost and send its hostname.

Let’s run our server and client.

Now our basic server and client are working. Our next step is to expand our client so that it can execute any command server is sending to it. We will be using a python module called ‘subprocess’ to execute the command from the server.
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.

If the client receives a join command, it will return the current working directory to the server appended with a ‘>’. The server will print the response and it will give the feel that you are in the client’s working directory. Then the server will ask input from the user to enter the next command for the client to execute.

~/Git/blog/rev_shell (master) $ python3 server.py
starting...
Server: waiting for new connection
JMac2.lan ('127.0.0.1', 58277) connected
/Users/jit/z/client>

Given below, you can see the client joins the server and the server executed ‘ls’ and ‘touch’ command to create a new file in client pc. ‘quit’ command is to close the current connection.

Yay! Now we can easily send commands to our friend's PC without actually remoting into his desktop.

Multi-Client Support

Now let us expand our application so that our server can handle multiple clients. Shall we?

In order for our server to support multiple clients, we need to add threading support in the server. The server will be listening on one thread for new incoming connections and new clients will be added to a list. Another thread will be processing the clients from this list. (we are not much worried about thread synchronization, because our processing thread will be mostly reading the list)

Given below shows our listener and processing code.

Our server is now listening and adding new clients to the list.

Now let us run our server and see the output when two clients joined the server. It lists two clients and the server can choose which client to process.

Yay! Now our server can handle multiple incoming connections.

Running server on EC2 Instance

Now I have everything running locally, let's try run it external. So let us spawn an EC2 instance and launch our server there and make sure that things are working.

Choose the AMI image that comes with Python. If Python3 is missing, please install it. Ensure that port 9090 is open in your EC2 security settings. Now let us copy our server file to EC2.

[ec2-user ~]$yum check-update[ec2-user ~]$ yum list installed | grep -i python3scp -i ~/kp.pem server.py ec2-user@ec2-51-53-197-192.us-west-1.compute.amazonaws.com:~/.

Run the server:

Run the Client:

Now let us run some commands and ensure things are working fine.

So now basic reverse shell implementation is completed. I hope you enjoyed reading it. You can see the source code here.

--

--