Trumpai: jei PHP-FPM, Apache ar kitas žiniatinklio serverio procesas paleidžia apvalkalą (shell), pavyzdžiui, sh ar bash, tai vienas stipriausių įsilaužimo per svetainę įspėjamųjų ženklų. Prieš ką nors nutraukdami, patikrinkite procesų medį, apvalkalo komandinę eilutę ir darbo katalogą. Pavieniai trumpi apvalkalai gali būti teisėti; ilgai veikiantys apvalkalai su tinklo įrankiais teisėti beveik niekada.
Kodėl šis šablonas tiek daug pasako
Žiniatinklio serveris atsako į užklausas. PHP-FPM, t. y. procesų valdytojas, kuris žiniatinklio serveriui vykdo PHP skriptus, tam paprastai nepaleidžia jokių kitų programų. Apvalkalas po žiniatinklio serveriu reiškia, kad PHP kodas sąmoningai iškvietė programą. Arba programa tai daro tyčia, arba kažkas kitas įterpė kodą.
PHP2Shell atveju paskelbtų, patvirtintų kompromitavimo indikatorių (Indicators of Compromise), t. y. fiksuotų atpažinimo požymių sąrašo, nėra. Aptikimas remiasi elgsena. Pasak mūsų turimų pranešimų, žiniatinklio serverio ar PHP-FPM procesai, paleidžiantys apvalkalą, priklauso stipriausiems bendriesiems įspėjamiesiems ženklams. Tai galioja kiekvienam pažeidžiamumui, per kurį užpuolikai gali vykdyti kodą serveryje. Kitų požymių apžvalgą pateikia Ar jau esu pažeistas?.
Kodėl apvalkalas užpuolikui toks svarbus? Per spragą jis iš pradžių gali per PHP procesą pateikti tik atskiras komandas. Apvalkalas tai paverčia patogia darbo vieta: jis gali apsižvalgyti, atsisiųsti įrankių, skaityti prisijungimo duomenis iš konfigūracijos failų ir įsitvirtinti ilgam. Kas atpažįsta apvalkalą, užpuoliką dažnai atpažįsta kaip tik tą akimirką, kai jis iš pirmosios prieigos pereina prie tikrojo sumanymo.
PHP-FPM paleidžia bash: procesų medžio skaitymas
Kiekvienas procesas Linux sistemoje turi tėvinį procesą. Klausimas, ar apvalkalas veikia kaip žiniatinklio serverio proceso vaikas. Toliau pateiktos komandos tik skaito:
# Procesų medis su naudotoju, tėvinio proceso PID ir paleidimo laiku
ps -eo user,pid,ppid,lstart,cmd --forest | grep -B2 -A4 -E "[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp"
# Apvalkalai, veikiantys po tipiniais žiniatinklio serverio naudotojais
ps -eo user,pid,ppid,lstart,cmd | grep -E "^(www-data|apache|nginx) " | grep -E "[ /](ba|da)?sh( |$)"
# Medis nuo seniausio PHP-FPM proceso
pstree -alp "$(pgrep -o php-fpm)"
Radę įtartiną apvalkalą, daugiau užuominų pateikia įrašai /proc, taip pat tik skaitant:
PID=12345 # įtartino apvalkalo PID
tr '\0' ' ' < /proc/$PID/cmdline; echo # visa komandinė eilutė
ls -l /proc/$PID/cwd /proc/$PID/exe # darbo katalogas ir programos failas
ls -l /proc/$PID/fd 2>/dev/null | grep socket # atviri tinklo ryšiai
Procesų pavadinimai Debian ir Ubuntu dažnai yra php8.3-fpm ar panašūs; pritaikykite paieškos šablonus. Darbo katalogai /tmp, /dev/shm ar įkėlimų aplankuose yra aiškus ženklas.
Teisėtos išimtys ir tikri įspėjamieji ženklai
Kai kurios programos per PHP kviečia programas. Tuomet trumpam gali atsirasti apvalkalas, pavyzdžiui, kai PHP per sendmail_path perduoda laiškus arba programa paveikslėlius apdoroja išoriniu įrankiu. Tokie apvalkalai gyvena tik sekundes ir visada kviečia tą pačią programą. Šiuos tikėtinus atvejus vieną kartą tvarkingai dokumentuokite; tuomet kiekvienas nukrypimas iškart krinta į akis, užuot paskendęs žinomų pranešimų sraute.
| Stebėjimas | Greičiau nekenksminga, jei | Įtartina, jei |
|---|---|---|
| Trumpas apvalkalas po PHP-FPM | paleidžia žinomą programos programą | tikslas ir paskirtis neaiškūs |
| Ilgiau veikiantis apvalkalas | niekada | veikia minutes ar valandas |
| Tinklo įrankiai kaip vaiko procesas | žinoma programos atnaujinimo ar API užklausa | po to seka atsisiuntimai į laikinus katalogus |
| Darbo katalogas | programos projekto aplankas | /tmp, /dev/shm, įkėlimų aplankas |
| Laikas | atitinka žinomą veiksmą, pavyzdžiui, laiškų siuntimą | naktį, be naudotojo veiklos, dažnai |
Jei nežinote, ar jūsų programa kviečia programas, paklauskite kūrėjo arba kode ieškokite tokių funkcijų kaip exec, shell_exec, system, passthru, proc_open ir popen. Radiniai savo kode yra normalūs, radiniai nežinomuose failuose ne.
Stebėti nuolat, o ne pažiūrėti vieną kartą
Akimirkos vaizdas su ps pagauna tik tuos apvalkalus, kurie veikia dabar. Trumpalaikiai procesai praslysta. Patikimiau yra nuolat registruoti žiniatinklio serverio naudotojo programų paleidimus. Linux sistemoje tai atlieka audito tarnyba auditd su taisykle žiniatinklio serverio naudotojo programų paleidimams. Vertinama tik skaitant:
# Parodyti užregistruotus programų paleidimus pagal taisyklės raktą (raktas kaip pavyzdys)
sudo ausearch -k web_exec --start today -i | grep -E "exe=|proctitle="
Kaip atrodo taisyklė, priklauso nuo distribucijos ir naudotojo ID; pirmiausia ją išbandykite, nes labai apkrautuose serveriuose atsiranda daug įrašų.
Du papildymai padaro stebėseną patikimą. Pirma, žurnalai papildomai turėtų keliauti į centrinę sistemą, nes užpuolikas su root teisėmis gali ištrinti vietinius žurnalus. Antra, reikia pranešimo: žiniatinklio serverio naudotojo programos paleidimas, kurio nėra trumpame tikėtinų programų sąraše, turėtų sukelti pranešimą, o ne tik žurnalo įrašą. Kas jau naudoja sprendimą aptikimui galiniuose įrenginiuose ar serveriuose, tą pačią taisyklę gali atkartoti ten. Prevenciškai su disable_functions galima užblokuoti tai, ko programai nereikia. Tai neuždaro spragos interpretatoriuje, bet apsunkina kitą užpuoliko žingsnį. Išsami informacija skiltyje Teisingas disable_functions naudojimas.
Ką daryti radus apvalkalą po žiniatinklio serveriu
- Dokumentuoti:
psišvestį, komandinę eilutę, darbo katalogą ir atvirus ryšius išsaugoti faile už žiniatinklio katalogo ribų. - Netvarkyti: netrinti failų ir nenutraukti procesų, kol pėdsakai neišsaugoti.
- Izoliuoti: atjungti serverį nuo tinklo arba stipriai apriboti prieigą.
- Ieškoti priežasties: patikrinti žurnalus, naujus failus ir išliekamumą, pavyzdžiui, cron užduotis, žr. Įtartinų procesų radimas Linux serveriuose.
- Pakeisti prieigas: visi serveryje buvę slaptažodžiai ir raktai laikomi žinomais.
Jei programa veikia konteineriuose, tas pats principas galioja mažesniu mastu. Apvalkalas PHP konteineryje yra tiek pat įtartinas kaip klasikiniame serveryje, o konteinerių atvaizduose jis dažnai yra tik todėl, kad jį atsineša bazinis atvaizdas. Prieš paleisdami konteinerį iš naujo, išsaugokite jo būseną, nes su konteineriu išnyksta ir pėdsakai laikinojoje failų sistemoje.
Patikrinkite ir kaimynystę. Užpuolikas su apvalkalu žiniatinklio serveryje dažnai bando iš ten pasiekti kitas sistemas, pavyzdžiui, duomenų bazę, atsarginių kopijų saugyklą ar vidines valdymo sąsajas. Prisijungimo duomenys programos konfigūracijos failuose tai jam palengvina.
Ilgai veikiantis apvalkalas po PHP-FPM serveryje su klientų duomenimis yra saugumo incidentas. Taip jį ir traktuokite: išsaugoti, izoliuoti, struktūruotai išnagrinėti, leisti patikrinti pranešimo pareigas.
Kaip PHP SOS padeda konkrečiai?
- Įvertinti radinį: tikriname procesų medį, komandines eilutes ir ryšius bei atskiriame programos elgseną nuo įsilaužimo pėdsakų.
- Išsaugoti pėdsakus: sistemos būseną išsaugome atsekamai, prieš ką nors keisdami.
- Spręsti incidentą: su incidentų valdymu (Incident Response) vedame nuo suvaldymo iki dokumentuotos pabaigos.
- Apsaugoti ilgalaikiai: įrengiame programų paleidimų registravimą ir PHP funkcijas apribojame iki būtinų. Kaip PHP-FPM veikia viduje, paaiškina PHP-FPM paaiškinimas.
Dažni klausimai
Ar kiekvienas apvalkalas (shell) po PHP-FPM yra ataka?
Ne kiekvienas. Kai kurios programos per PHP sąmoningai kviečia programas, pavyzdžiui, paveikslėlių apdorojimui ar laiškų siuntimui, ir tuomet trumpam gali atsirasti apvalkalas. Įtartina tampa, kai apvalkalas veikia ilgiau, paleidžia tinklo įrankius arba dirba iš netipinių katalogų.
Ar įtartiną procesą reikėtų iškart nutraukti?
Pirmiausia dokumentuokite, tada veikite. Užfiksuokite proceso duomenis, komandinę eilutę, darbo katalogą ir tinklo ryšius. Po to izoliuokite serverį. Skubotas nutraukimas sunaikina pėdsakus ir neapsaugo nuo to, kad užpuolikas sugrįš.
Ar yra patvirtintų PHP2Shell atpažinimo požymių?
Ne. Paskelbtų, patvirtintų kompromitavimo indikatorių (IOC) nėra. Apvalkalai po žiniatinklio serveriu yra bendras įsilaužimų per žiniatinklio programas įspėjamasis ženklas, o ne būdingas tik PHP2Shell.
Kaip užkirsti kelią, kad PHP apskritai paleistų apvalkalus?
Per disable_functions galima užblokuoti tokias funkcijas kaip exec, shell_exec, system ir proc_open, jei programai jų nereikia. Tai neuždaro spragos PHP interpretatoriuje, bet apsunkina išnaudojimą.