# Užmaskuoto PHP kodo atpažinimas

> eval, base64_decode ir kiti: kaip atpažinti užmaskuotą PHP kodą, kaip ieškoti nepavojingai ir kaip atskirti teisėtus užkoduotojus nuo kenkėjiško kodo.

Šaltinis: https://phpsos.de/lt/blog/verschleierter-php-code/  
Būsena: 2026-10-25  
Teikėjas: PHP SOS, PHP avarinė pagalba ir serverio sauga. Skubi pagalba per „WhatsApp“: https://wa.me/491736494914?text=Sveiki%2C%20PHP%20SOS%2C%20mums%20reikia%20pagalbos%20su%20m%C5%ABs%C5%B3%20PHP%20serveriu.%20%C4%AEmon%C4%97%3A%20%E2%80%A6%20Svetain%C4%97%3A%20%E2%80%A6

**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](https://phpsos.de/lt/ratgeber/webshell-erkennen/). Š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ą.

```bash
# 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`.

```bash
# 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](https://phpsos.de/lt/blog/grenzen-von-malware-scannern/).

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](https://phpsos.de/lt/blog/datenbank-auf-schadcode-pruefen/). Prevenciškai nereikalingas sistemos funkcijas galima užblokuoti, kaip aprašyta vadove [Teisingas disable_functions naudojimas](https://phpsos.de/lt/ratgeber/disable-functions/).

## 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](https://phpsos.de/lt/leistungen/malware-entfernung/) 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

- [PHP vadovas: assert()](https://www.php.net/manual/de/function.assert.php)
- [PHP vadovas: create_function()](https://www.php.net/manual/de/function.create-function.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
