Ukratko: Zamagljeni PHP kod je kod koji je namjerno učinjen nečitljivim, uglavnom kodiranjem i kompresijom koje se razrješuju tek tijekom rada. Tipični obrasci prepoznavanja su eval zajedno s base64_decode, gzinflate ili str_rot13, vrlo dugi retci, heksadecimalni nizovi znakova i nazivi funkcija sastavljeni od dijelova. Tražite bezopasnim grep naredbama, kod nikad ne izvršavajte i nalaze usporedite s izvornim paketom.
Zašto napadači skrivaju svoj kod
Tko na poslužitelj odloži web shell ili stražnja vrata, želi da dugo ostanu neotkriveni. Čitljiv kod upao bi u oči svakom administratoru koji otvori datoteku, a svaki bi ga skener pronašao. Zato napadači svoj kod pakiraju: kodira se, komprimira i tek se pri pozivu ponovno sastavlja i izvršava.
Za PHP2Shell nema potvrđenih Indicators of Compromise. Zamagljeni kod nije obilježje te ranjivosti, nego opći znak da je netko ubacio kod, bez obzira na put. Kako općenito pronaći i ukloniti web shellove, opisuje članak Prepoznati i ukloniti web shell. Ovaj prilog usredotočen je na pitanje po čemu prepoznati zamagljeni kod.
eval, base64 i slično: tipični građevni blokovi
Zamagljivanje gotovo uvijek slijedi isto načelo: nečitljivi blok podataka jedna ili više funkcija pretvara natrag u kod koji se potom izvršava. Sljedeći se građevni blokovi stalno ponavljaju.
| Građevni blok | Primjeri | Zašto upada u oči |
|---|---|---|
| Izvršavanje | eval, assert s nizom znakova (do PHP-a 7.x), create_function (do PHP-a 7.x) |
izvršava tekst kao kod |
| Dekodiranje | base64_decode, str_rot13, hex2bin, strrev, convert_uudecode |
podatke ponovno čini čitljivima |
| Dekompresija | gzinflate, gzuncompress, gzdecode |
raspakirava ugrađeni kod |
| Sastavljanje | lanci chr(), nizanje kratkih dijelova, \x escape sekvence |
skriva nazive funkcija |
| Dinamički poziv | varijable kao naziv funkcije, call_user_func, array_map s nizom znakova |
poziv se nigdje ne pojavljuje otvorenim tekstom |
| Pristup sustavu | system, exec, shell_exec, passthru, proc_open, popen |
naredbe na poslužitelju |
Prema PHP priručniku assert() od PHP-a 8.0 više ne evaluira nizove znakova kao kod, a create_function() je uklonjena u PHP-u 8.0. Na poslužiteljima sa starijim PHP verzijama oba ostaju relevantni pojmovi za pretragu.
Pojedini građevni blok rijetko je sumnjiv, base64_decode primjerice mnoge aplikacije legitimno koriste. Sumnjiva postaje kombinacija: dekodiranje čiji rezultat izravno teče u izvršavanje.
Bezopasno tražiti: bezazlene grep naredbe
Sljedeće naredbe pretražuju datoteke samo kao tekst. Ne izvršavaju nikakav PHP kod. Prilagodite put.
# Izvršavanje u kombinaciji s dekodiranjem ili dekompresijom
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"
# Vrlo dugi retci (često pakirani kod)
grep -rlE ".{2000,}" /var/www --include="*.php*"
# Mnogo heksadecimalnih escape sekvenci ili lanaca chr() u jednom retku
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*"
# Poziv funkcije preko varijable odmah nakon dodjele iz nizova znakova
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50
Pogotke najprije provjerite naredbom ls -l i vremenskim žigom, a zatim ih otvarajte samo kao tekst, primjerice s less. Sumnjive datoteke nikad ne pozivajte preko preglednika, jer bi ih poslužitelj tada izvršio.
Gdje se zamagljeni kod tipično nalazi
Zamagljeni kod rijetko stoji u zasebnoj, upadljivoj datoteci. Češće se umeće u postojeće datoteke, sasvim na početak ili na kraj, često nakon mnogo praznih redaka kako pri otvaranju ne bi odmah upao u oči. Omiljene su datoteke koje se učitavaju pri svakom pozivu: središnja index.php, konfiguracijske datoteke i datoteke funkcija teme.
Posebno neupadljiv put vodi preko konfiguracije. Postavkom auto_prepend_file PHP prije svake skripte učitava dodatnu datoteku. Ako stoji u .user.ini ili .htaccess koji je napadač stvorio, njegov kod radi pri svakom pozivu stranice, a da nije izmijenjena nijedna datoteka aplikacije. Uključena datoteka pritom rado nosi bezazlen nastavak poput .ico ili .png.
# Učitava li se prije ili poslije svake skripte dodatni kod?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null
# PHP kod u datotekama s nastavkom slike ili ikone
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null
Razlikovati legitimno zamagljivanje od zlonamjernog koda
Nije svaki nečitljivi kod zlonamjeran. Tri su slučaja česta:
- Komercijalni enkoderi: Neki proizvođači dodataka i softvera svoj kod štite alatima poput ionCubea ili SourceGuardiana. Datoteke su nečitljive, ali tipično upućuju na potreban loader. Usporedite ih s izvornim paketom.
- Minificiran ili generiran kod: Predmemorije i mehanizmi predložaka stvaraju duge retke bez prijeloma, ali bez izvršavanja dekodiranog teksta.
- Ugrađeni podaci: Slike ili fontovi kao Base64 niz u PHP datoteci su neuobičajeni, ali bezazleni dok se rezultat ne izvršava.
Najpouzdaniji test je usporedba s izvorom: ako datoteka nepromijenjena potječe iz paketa proizvođača, legitimna je. Ako se ne nalazi ni u jednom izvornom paketu ili odstupa od njega, treba je istražiti.
Ne pokušavajte dešifrirati zamagljeni kod na produkcijskom poslužitelju, primjerice zamjenom eval ispisom i pozivom datoteke. Već jedna pogreška pritom izvršava zlonamjerni kod. Analiza pripada u izolirano okruženje.
Granice pretrage po obrascima
Napadači poznaju uobičajene naredbe za pretragu. Dijele nazive funkcija, sastavljaju ih tijekom rada ili stvarni kod izmještaju u bazu podataka, slikovne datoteke ili konfiguracijske unose. Pretraga po obrascima stoga pronalazi mnogo, ali ne sve. Zašto i skeneri ovdje nailaze na granice, objašnjava članak Skeneri zlonamjernog softvera za web-stranice: što pronalaze, a što ne.
Nalaz je uz to rijetko jedini. Napadači u više datoteka često koriste isti građevni blok, primjerice upadljivo ime varijable ili upečatljiv niz znakova na početku kodiranog bloka. Nakon potvrđenog nalaza zato ciljano potražite upravo taj niz znakova u cijelom web-direktoriju, i u drugim web-stranicama na istom poslužitelju. Tako pronalazite srodnike koje nijedna opća pretraga obrascima nije obuhvatila.
Pretragu dopunite usporedbom s izvornim datotekama i pogledom u bazu podataka, vidi Provjeriti bazu podataka na ubačeni kod. Preventivno se nepotrebne sistemske funkcije mogu blokirati, kako opisuje vodič Ispravno koristiti disable_functions.
Kako PHP SOS konkretno pomaže?
- Tražiti: Pretražujemo datoteke i bazu podataka proširenim obrascima i uspoređujemo s izvornim paketima.
- Analizirati: Sumnjiv kod istražujemo u izoliranom okruženju, bez ugrožavanja Vašeg sustava.
- Očistiti: Uz uklanjanje zlonamjernog softvera uklanjamo sve sastavnice i zatvaramo put upada.
- Zaštititi: Ograničavamo PHP funkcije i prava pisanja te nadziremo nove ili izmijenjene datoteke.
Česta pitanja
Je li eval s base64_decode uvijek zlonamjeran kod?
Ne uvijek, ali vrlo često. Legitiman kod tu kombinaciju jedva treba. U datotekama koje ne pripadaju Vašoj aplikaciji ili poznatom dodatku to je jak znak upozorenja.
Smijem li zamagljeni kod dekodirati radi čitanja?
Samo bez njegova izvršavanja i ne na produkcijskom poslužitelju. Već nehotično izvršavanje može nanijeti štetu. U slučaju sumnje analizu prepustite stručnjacima koji rade u izoliranim okruženjima.
Zašto moj skener zlonamjernog softvera ne pronalazi kod?
Skeneri traže poznate obrasce. Napadači svoj kod stalno mijenjaju, dijele nazive funkcija ili ih sastavljaju tijekom rada. Prazan rezultat skeniranja stoga nije dokaz čistog poslužitelja.
Što je s komercijalno šifriranim dodacima?
Neki proizvođači svoj kod štite enkoderima poput ionCubea ili SourceGuardiana. Takve su datoteke nečitljive, ali legitimne ako potječu od proizvođača. Usporedite ih s izvornim paketom.
Pomaže li disable_functions protiv zamagljenog koda?
Djelomično. Funkcije poput exec ili system mogu se blokirati, eval nasuprot tome ne, jer je jezična konstrukcija, a ne funkcija. Blokada napadačima otežava sljedeći korak, ali ne sprječava svaki zlonamjerni kod.