Накратко: Ако PHP-FPM, Apache или друг процес на уеб сървър стартира shell като sh или bash, това е един от най-силните предупредителни сигнали за проникване през уебсайта. Проверете дървото на процесите, командния ред и работната директория на shell-а, преди да прекратите нещо. Отделни кратки shell-ове могат да са легитимни; дълго работещи shell-ове с мрежови инструменти почти никога не са.
Защо този модел казва толкова много
Уеб сървърът отговаря на заявки. PHP-FPM, тоест диспечерът на процеси, който изпълнява PHP скриптове за уеб сървъра, обикновено не стартира за това други програми. Shell под уеб сървъра означава, че PHP код е извикал програма умишлено. Или приложението го прави нарочно, или някой друг е вмъкнал код.
За PHP2Shell няма публикувани, потвърдени Indicators of Compromise, тоест няма списък с твърди признаци за разпознаване. Разпознаването се основава на поведението. Според наличните ни съобщения процесите на уеб сървъра или на PHP-FPM, които стартират shell, спадат към най-силните общи предупредителни сигнали. Това важи за всяка уязвимост, през която нападатели изпълняват код на сървъра. Преглед на други признаци дава Компрометиран ли съм вече?.
Защо shell-ът е толкова важен за нападателя? С една уязвимост той първоначално може да подава само отделни команди през PHP процеса. Shell превръща това в удобно работно място: може да се огледа, да зареди инструменти, да прочете данни за достъп от конфигурационни файлове и да се установи трайно. Който разпознае shell-а, често разпознава нападателя в момента, в който той преминава от първия достъп към същинското си намерение.
PHP-FPM стартира bash: четене на дървото на процесите
Всеки процес под Linux има родителски процес. Въпросът е дали shell работи като дете на процес на уеб сървър. Следните команди само четат:
# Дърво на процесите с потребител, PID на родителя и време на стартиране
ps -eo user,pid,ppid,lstart,cmd --forest | grep -B2 -A4 -E "[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp"
# Shell-ове, които работят под типични потребители на уеб сървъра
ps -eo user,pid,ppid,lstart,cmd | grep -E "^(www-data|apache|nginx) " | grep -E "[ /](ba|da)?sh( |$)"
# Дърво, започващо от най-стария процес на PHP-FPM
pstree -alp "$(pgrep -o php-fpm)"
Ако сте намерили подозрителен shell, записите под /proc дават допълнителни указания, също само за четене:
PID=12345 # PID на подозрителния shell
tr '\0' ' ' < /proc/$PID/cmdline; echo # пълен команден ред
ls -l /proc/$PID/cwd /proc/$PID/exe # работна директория и файл на програмата
ls -l /proc/$PID/fd 2>/dev/null | grep socket # отворени мрежови връзки
Имената на процесите при Debian и Ubuntu често са php8.3-fpm или подобни; пригодете шаблоните за търсене. Работни директории в /tmp, /dev/shm или в директории за качване са ясен знак.
Легитимни изключения и истински предупредителни знаци
Някои приложения извикват програми през PHP. При това за кратко може да възникне shell, например когато PHP предава поща през sendmail_path или приложение обработва изображения с външен инструмент. Такива shell-ове живеят само секунди и винаги извикват една и съща програма. Документирайте тези очаквани случаи веднъж чисто; тогава всяко отклонение от тях бие на очи веднага, вместо да се изгуби в поток от познати съобщения.
| Наблюдение | По-скоро безобидно, когато | Подозрително, когато |
|---|---|---|
| Кратък shell под PHP-FPM | стартира позната програма на приложението | целта и смисълът са неясни |
| По-дълго работещ shell | никога | работи минути или часове |
| Мрежови инструменти като дъщерен процес | позната заявка за актуализация или API на приложението | следват изтегляния във временни директории |
| Работна директория | папка на проекта на приложението | /tmp, /dev/shm, директория за качване |
| Момент във времето | съвпада с позната дейност, например изпращане на поща | нощем, без активност на потребители, на групи |
Ако не знаете дали Вашето приложение извиква програми, попитайте разработчика или потърсете в кода функции като exec, shell_exec, system, passthru, proc_open и popen. Попаденията в собствения код са нормални, попаденията в непознати файлове - не.
Наблюдавайте трайно вместо да погледнете веднъж
Моментна снимка с ps улавя само shell-ове, които работят в момента. Краткотрайните процеси се изплъзват. По-надеждно е стартирането на програми от потребителя на уеб сървъра да се протоколира трайно. Под Linux това постига услугата за одит auditd с правило за стартиране на програми от потребителя на уеб сървъра. Оценката се прави само за четене:
# Показване на протоколирани стартирания на програми по ключ на правило (ключът е пример)
sudo ausearch -k web_exec --start today -i | grep -E "exe=|proctitle="
Как изглежда правилото, зависи от дистрибуцията и от ID на потребителя; тествайте го първо, защото на силно натоварени сървъри възникват много записи.
Две допълнения правят наблюдението издръжливо. Първо, протоколите трябва допълнително да отиват към централна система, защото нападател с права на root може да изтрие локалните логове. Второ, нужно е алармиране: стартиране на програма от потребителя на уеб сървъра, която не е в кратък списък на очаквани програми, трябва да задейства съобщение, не само запис в лога. Който вече ползва решение за разпознаване на крайни устройства или сървъри, може да пренесе същото правило и там. Превантивно с disable_functions може да се блокира онова, от което приложението не се нуждае. Това не затваря уязвимост в интерпретатора, но затруднява следващата стъпка на нападателя. Подробности има в Правилно използване на disable_functions.
Какво да направите, ако намерите shell под уеб сървъра
- Документирайте: Запазете изхода на
ps, командния ред, работната директория и отворените връзки във файл извън уеб директорията. - Не почиствайте: Не изтривайте файлове и не прекратявайте процеси, преди следите да са запазени.
- Изолирайте: Изключете сървъра от мрежата или ограничете силно достъпа.
- Потърсете причината: Проверете логовете, новите файлове и постоянството, например cron задачи, вижте Намиране на подозрителни процеси на Linux сървъри.
- Сменете достъпите: Всички пароли и ключове, които са стояли на сървъра, се считат за известни.
Ако приложението работи в контейнери, важи същият принцип в малък мащаб. Shell в PHP контейнера е също толкова подозрителен, колкото и на класически сървър, а контейнерните образи често го съдържат само защото базовият образ го носи. Запазете състоянието на контейнера преди рестарта му, защото с контейнера изчезват и следите във временната файлова система.
Проверете освен това съседството. Нападател с shell на уеб сървър често се опитва оттам да достигне други системи, например базата данни, хранилището за резервни копия или вътрешни интерфейси за управление. Данните за достъп в конфигурационните файлове на приложението му го улесняват.
Дълго работещ shell под PHP-FPM на сървър с клиентски данни е инцидент със сигурността. Третирайте го така: запазете, изолирайте, обработете структурирано, поискайте проверка на задълженията за уведомяване.
Как помага PHP SOS конкретно?
- Оценка на находката: Проверяваме дървото на процесите, командните редове и връзките и отделяме поведението на приложението от следите от проникване.
- Запазване на следите: Запазваме състоянието на системата проследимо, преди нещо да бъде променено.
- Обработване на инцидента: С Incident Response водим от ограничаването до документираното приключване.
- Трайна защита: Настройваме протоколирането на стартирането на програми и ограничаваме PHP функциите до необходимото. Как PHP-FPM работи вътрешно, обяснява PHP-FPM обяснен.
Често задавани въпроси
Всеки shell под PHP-FPM нападение ли е?
Не всеки. Някои приложения умишлено извикват програми през PHP, например за обработка на изображения или изпращане на поща, и при това за кратко може да възникне shell. Подозрително става, когато shell работи по-дълго, стартира мрежови инструменти или работи от нетипични директории.
Трябва ли веднага да прекратя подозрителния процес?
Първо документирайте, после действайте. Запазете данните за процеса, командния ред, работната директория и мрежовите връзки. След това изолирайте сървъра. Прибързаното прекратяване унищожава следи и не пречи на нападателя да се върне.
Има ли потвърдени признаци за разпознаване на PHP2Shell?
Не. Няма публикувани, потвърдени Indicators of Compromise. Shell-овете под уеб сървъра са общ предупредителен сигнал за проникване през уеб приложения, не специфичен за PHP2Shell.
Как да попреча PHP изобщо да стартира shell-ове?
Чрез disable_functions могат да се блокират функции като exec, shell_exec, system и proc_open, ако приложението не се нуждае от тях. Това не затваря уязвимост в PHP интерпретатора, но затруднява използването ѝ.