Dabartinė padėtis: PHP2Shell. Du kritiniai PHP pažeidžiamumai (CVSS 9,2) leidžia vykdyti kenkėjišką kodą be prisijungimo. Pataisos nuo 2026-10-21.Ką dabar daryti →

Užmaskuoto PHP kodo atpažinimas

Neįskaitomas PHP kodas su eval ir base64_decode yra klasikinis įterpto kenkėjiško kodo ženklas. Kokių šablonų ieškoti, kaip juos rasti nepavojingai ir kada maskavimas yra teisėtas.

Būsena 5 min. skaitymoAptikimas ir forensika

Trumpai: užmaskuotas PHP kodas yra tyčia neįskaitomu padarytas kodas, dažniausiai užkoduotas ir suspaustas taip, kad būtų atstatytas tik vykdymo metu. Tipiniai atpažinimo šablonai: eval kartu su base64_decode, gzinflate ar str_rot13, labai ilgos eilutės, šešioliktainės simbolių eilutės ir funkcijų pavadinimai, sudaryti iš atskirų dalių. Ieškokite nekenksmingomis grep komandomis, kodo niekada nevykdykite ir radinius palyginkite su originaliu paketu.

Kodėl užpuolikai slepia savo kodą

Kas deda webshell ar užpakalines duris į serverį, nori, kad jos ilgai liktų neaptiktos. Įskaitomas kodas krenta į akį kiekvienam administratoriui, atidarančiam failą, ir jį rastų bet kuris skaitytuvas. Todėl užpuolikai savo kodą supakuoja: jis užkoduojamas, suspaudžiamas ir tik iškviečiant vėl sudedamas bei vykdomas.

PHP2Shell atveju patvirtintų kompromitavimo indikatorių (Indicators of Compromise) nėra. Užmaskuotas kodas nėra šio pažeidžiamumo požymis, o bendras ženklas, kad kažkas įterpė kodą, kad ir kokiu keliu. Kaip apskritai rasti ir pašalinti webshell, aprašo Webshell atpažinimas ir šalinimas. Šis straipsnis sutelktas į klausimą, kaip atpažinti užmaskuotą kodą.

eval, base64 ir kiti: tipinės dalys

Maskavimas beveik visada seka tuo pačiu principu: neįskaitomą duomenų bloką viena ar kelios funkcijos paverčia atgal į kodą, kuris po to vykdomas. Šios dalys kartojasi nuolat.

Dalis Pavyzdžiai Kodėl krenta į akis
Vykdymas eval, assert su simbolių eilute (iki PHP 7.x), create_function (iki PHP 7.x) vykdo tekstą kaip kodą
Dekodavimas base64_decode, str_rot13, hex2bin, strrev, convert_uudecode duomenis vėl padaro įskaitomus
Išpakavimas gzinflate, gzuncompress, gzdecode išpakuoja įterptą kodą
Sudėjimas chr() grandinės, trumpų dalių sujungimas, \x escape slepia funkcijų pavadinimus
Dinaminis kreipinys kintamieji kaip funkcijos pavadinimas, call_user_func, array_map su simbolių eilute kreipinys niekur nerodomas aiškiu tekstu
Prieiga prie sistemos system, exec, shell_exec, passthru, proc_open, popen komandos serveryje

Pagal PHP vadovą assert() nuo PHP 8.0 simbolių eilučių kaip kodo nebevertina, o create_function() PHP 8.0 buvo pašalinta. Serveriuose su senesnėmis PHP versijomis abu lieka aktualūs paieškos terminai.

Atskira dalis retai įtartina, pavyzdžiui, base64_decode daug programų naudoja teisėtai. Įtartinas tampa derinys: dekodavimas, kurio rezultatas tiesiai patenka į vykdymą.

Ieškoti nepavojingai: nekenksmingos grep komandos

Toliau pateiktos komandos failus peržiūri tik kaip tekstą. Jos nevykdo PHP kodo. Pritaikykite kelią.

# Vykdymas kartu su dekodavimu ar išpakavimu
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Labai ilgos eilutės (dažnai supakuotas kodas)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Daug šešioliktainių escape ar chr() grandinių vienoje eilutėje
grep -rlE "(\\\\x[0-9a-fA-F]{2}){20,}" /var/www --include="*.php*"
grep -rlE "(chr\s*\(\s*[0-9]+\s*\)\s*\.\s*){8,}" /var/www --include="*.php*"

# Funkcijos kreipinys per kintamąjį iškart po priskyrimo iš simbolių eilučių
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50

Radinius pirmiausia patikrinkite su ls -l ir laiko žyma, tada atidarykite tik kaip tekstą, pavyzdžiui, su less. Įtartinų failų niekada nekvieskite per naršyklę, nes tuomet serveris juos įvykdytų.

Kur paprastai slypi užmaskuotas kodas

Užmaskuotas kodas retai būna atskirame, krintančiame į akis faile. Dažniau jis įterpiamas į esamus failus, pačioje pradžioje ar pačioje pabaigoje, dažnai po daugybės tuščių eilučių, kad atidarant iškart nekristų į akis. Mėgstami failai, įkeliami kiekvieno kreipinio metu: pagrindinis index.php, konfigūracijos failai ir temos funkcijų failai.

Ypač nepastebimas kelias eina per konfigūraciją. Su nustatymu auto_prepend_file PHP prieš kiekvieną skriptą įkelia papildomą failą. Jei jis nurodytas .user.ini ar .htaccess, kuriuos sukūrė užpuolikas, jo kodas veikia su kiekvienu puslapio atidarymu, nepakeitus nė vieno programos failo. Įtrauktas failas tuomet mėgsta turėti nekenksmingą galūnę, pavyzdžiui, .ico ar .png.

# Ar prieš arba po kiekvieno skripto įkeliamas papildomas kodas?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# PHP kodas failuose su paveikslėlio ar piktogramos galūne
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null

Teisėtą maskavimą atskirti nuo kenkėjiško kodo

Ne kiekvienas neįskaitomas kodas yra kenkėjiškas. Dažni trys atvejai:

  1. Komerciniai užkoduotojai: kai kurie įskiepių ir programinės įrangos gamintojai savo kodą saugo tokiais įrankiais kaip ionCube ar SourceGuardian. Failai neįskaitomi, bet paprastai nurodo reikalingą krautuvą (loader). Palyginkite juos su originaliu paketu.
  2. Sumažintas (minified) ar sugeneruotas kodas: talpyklos ir šablonų varikliai sukuria ilgas eilutes be lūžių, bet nevykdo dekoduoto teksto.
  3. Įterpti duomenys: paveikslėliai ar šriftai kaip Base64 simbolių eilutė PHP faile yra neįprasti, bet nekenksmingi, kol rezultatas nevykdomas.

Patikimiausias testas yra palyginimas su šaltiniu: jei failas nepakitęs ateina iš gamintojo paketo, jis teisėtas. Jei jo nėra jokiame originaliame pakete arba jis nuo jo skiriasi, jį reikia ištirti.

Svarbu

Nebandykite užmaskuoto kodo iššifruoti gamybiniame serveryje, pavyzdžiui, pakeisdami eval išvestimi ir iškviesdami failą. Net viena klaida paleidžia kenkėjišką kodą. Analizė priklauso izoliuotai aplinkai.

Šablonų paieškos ribos

Užpuolikai pažįsta įprastas paieškos komandas. Jie dalija funkcijų pavadinimus, sudeda juos vykdymo metu arba tikrąjį kodą perkelia į duomenų bazę, paveikslėlių failus ar konfigūracijos įrašus. Todėl šablonų paieška randa daug, bet ne viską. Kodėl čia ribų pasiekia ir skaitytuvai, paaiškina Svetainių kenkėjiškų programų skaitytuvai: ką jie randa ir ko ne.

Radinys, be to, retai būna vienintelis. Užpuolikai keliuose failuose dažnai naudoja tą pačią dalį, pavyzdžiui, krentantį į akis kintamojo pavadinimą ar būdingą simbolių seką užkoduoto bloko pradžioje. Todėl patvirtinę radinį, tikslingai ieškokite būtent šios simbolių sekos visame žiniatinklio kataloge, taip pat kitose to paties serverio svetainėse. Taip rasite brolius, kurių neaprėpė nė viena bendroji šablonų paieška.

Paiešką papildykite palyginimu su originaliais failais ir žvilgsniu į duomenų bazę, žr. Duomenų bazės patikra dėl įterpto kodo. Prevenciškai nereikalingas sistemos funkcijas galima užblokuoti, kaip aprašyta vadove Teisingas disable_functions naudojimas.

Kaip PHP SOS padeda konkrečiai?

  • Ieškoti: failus ir duomenų bazę peržiūrime išplėstais šablonais ir lyginame su originaliais paketais.
  • Analizuoti: įtartiną kodą nagrinėjame izoliuotoje aplinkoje, nesukeldami pavojaus jūsų sistemai.
  • Išvalyti: su kenkėjiškos programinės įrangos šalinimu pašaliname visas dalis ir uždarome patekimo kelią.
  • Apsaugoti: apribojame PHP funkcijas ir rašymo teises bei stebime naujus ar pakeistus failus.

Dažni klausimai

Ar eval su base64_decode visada yra kenkėjiškas kodas?

Ne visada, bet labai dažnai. Teisėtam kodui šio derinio beveik nereikia. Failuose, nepriklausančiuose jūsų programai ar žinomam įskiepiui, tai stiprus įspėjamasis ženklas.

Ar užmaskuotą kodą skaitymui galiu dekoduoti?

Tik jo nevykdydami ir ne gamybiniame serveryje. Net netyčinis vykdymas gali pridaryti žalos. Abejojant analizę palikite specialistams, kurie dirba su izoliuotomis aplinkomis.

Kodėl mano kenkėjiškų programų skaitytuvas kodo neranda?

Skaitytuvai ieško žinomų šablonų. Užpuolikai savo kodą nuolat keičia, dalija funkcijų pavadinimus arba sudeda juos vykdymo metu. Tuščias patikros rezultatas todėl nėra švaraus serverio įrodymas.

O kaip su komerciškai užšifruotais įskiepiais?

Kai kurie gamintojai savo kodą saugo užkoduotojais, tokiais kaip ionCube ar SourceGuardian. Tokie failai neįskaitomi, bet teisėti, jei yra iš gamintojo. Palyginkite juos su originaliu paketu.

Ar disable_functions padeda nuo užmaskuoto kodo?

Iš dalies. Funkcijas, tokias kaip exec ar system, užblokuoti galima, o eval ne, nes tai kalbos konstrukcija, o ne funkcija. Blokavimas užpuolikams apsunkina kitą žingsnį, bet ne kiekvieną kenkėjišką kodą.

Šaltiniai

Skubus kontaktas

Kiekviena valanda svarbi. Parašykite mums dabar.

Trumpai aprašykite sistemą, PHP versiją ir pastebėjimus. Mes atsakysime, išsiaiškinsime padėtį ir dirbsime nuotoliu, kol incidentas bus užbaigtas ir dokumentuotas.

Skubi pagalba