# Prepoznavanje zakrite kode PHP

> eval, base64_decode in drugo: po čem prepoznate zakrito kodo PHP, kako iščete brez nevarnosti in kako ločite legitimne kodirnike od škodljive kode.

Vir: https://phpsos.de/sl/blog/verschleierter-php-code/  
Stanje: 25.10.2026  
Ponudnik: PHP SOS, Nujna pomoč za PHP in varnost strežnikov. Takojšnja pomoč po WhatsAppu: https://wa.me/491736494914?text=Pozdravljeni%2C%20PHP%20SOS%2C%20potrebujemo%20pomo%C4%8D%20z%20na%C5%A1im%20stre%C5%BEnikom%20PHP.%20Podjetje%3A%20%E2%80%A6%20Spletna%20stran%3A%20%E2%80%A6

**Na kratko:** Zakrita koda PHP je koda, ki je bila namenoma narejena neberljiva, večinoma s kodiranjem in stiskanjem, ki se razreši šele med izvajanjem. Tipični vzorci za prepoznavanje so `eval` skupaj z `base64_decode`, `gzinflate` ali `str_rot13`, zelo dolge vrstice, šestnajstiški nizi in imena funkcij, sestavljena iz delov. Iščite z neškodljivimi ukazi grep, kode nikoli ne izvajajte in najdbe primerjajte z izvirnim paketom.

## Zakaj napadalci svojo kodo skrivajo

Kdor na strežnik odloži webshell ali stranska vrata, želi, da dolgo ostanejo neodkrita. Berljiva koda bi padla v oči vsakemu skrbniku, ki datoteko odpre, in vsak pregledovalnik bi jo našel. Zato napadalci kodo pakirajo: kodirana je, stisnjena in šele ob priklicu znova sestavljena in izvedena.

Za PHP2Shell ni potrjenih indikatorjev ogroženosti (Indicators of Compromise). Zakrita koda ni značilnost te ranljivosti, ampak splošen znak, da je nekdo vnesel kodo, ne glede na pot. Kako webshelle v celoti najdete in odstranite, opisuje [Prepoznavanje in odstranjevanje webshellov](https://phpsos.de/sl/ratgeber/webshell-erkennen/). Ta prispevek se osredotoča na vprašanje, po čem zakrito kodo prepoznate.

## eval, base64 in drugo: tipični gradniki

Zakritje skoraj vedno sledi istemu načelu: neberljiv podatkovni blok ena ali več funkcij spremeni nazaj v kodo, ki se potem izvede. Naslednji gradniki se pri tem pojavljajo vedno znova.

| Gradnik | Primeri | Zakaj je opazen |
|---|---|---|
| Izvajanje | `eval`, `assert` z nizom (do PHP 7.x), `create_function` (do PHP 7.x) | besedilo izvede kot kodo |
| Dekodiranje | `base64_decode`, `str_rot13`, `hex2bin`, `strrev`, `convert_uudecode` | podatke naredi spet berljive |
| Razširjanje | `gzinflate`, `gzuncompress`, `gzdecode` | razpakira vdelano kodo |
| Sestavljanje | verige `chr()`, združevanje kratkih delov, ubežne sekvence `\x` | skrije imena funkcij |
| Dinamičen klic | spremenljivke kot ime funkcije, `call_user_func`, `array_map` z nizom | klic nikjer ni v jasnem besedilu |
| Dostop do sistema | `system`, `exec`, `shell_exec`, `passthru`, `proc_open`, `popen` | ukazi na strežniku |

Po priročniku PHP `assert()` od PHP 8.0 nizov ne vrednoti več kot kodo, `create_function()` pa je bila v PHP 8.0 odstranjena. Na strežnikih s starejšimi različicami PHP ostajata oba pomembna iskalna izraza.

Posamezen gradnik je redko sumljiv, `base64_decode` na primer mnoge aplikacije uporabljajo legitimno. Sumljiva postane kombinacija: dekodiranje, katerega rezultat teče neposredno v izvajanje.

## Iskanje brez nevarnosti: neškodljivi ukazi grep

Naslednji ukazi datoteke preiskujejo samo kot besedilo. Kode PHP ne izvajajo. Pot prilagodite.

```bash
# Izvajanje v kombinaciji z dekodiranjem ali razširjanjem
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Zelo dolge vrstice (pogosto zapakirana koda)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Veliko šestnajstiških ubežnih sekvenc ali verig chr() v eni vrstici
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*"

# Klic funkcije prek spremenljivke neposredno po dodelitvi iz nizov
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50
```

Zadetke najprej preverite z `ls -l` in časovnim žigom, nato jih odprite samo kot besedilo, na primer z `less`. Sumljivih datotek nikoli ne prikličite prek brskalnika, saj bi jih strežnik s tem izvedel.

## Kje zakrita koda tipično sedi

Zakrita koda redko stoji v lastni, opazni datoteki. Pogosteje je vstavljena v obstoječe datoteke, povsem na začetek ali povsem na konec, pogosto za mnogimi praznimi vrsticami, da ob odpiranju ne pade takoj v oči. Priljubljene so datoteke, ki se naložijo ob vsakem priklicu: osrednji `index.php`, konfiguracijske datoteke in funkcijske datoteke teme.

Posebej neopazna pot vodi prek konfiguracije. Z nastavitvijo `auto_prepend_file` PHP pred vsakim skriptom naloži dodatno datoteko. Če stoji v `.user.ini` ali `.htaccess`, ki ju je ustvaril napadalec, njegova koda teče ob vsakem priklicu strani, ne da bi bila spremenjena ena sama datoteka aplikacije. Vključena datoteka pri tem rada nosi neškodljivo končnico, kot sta `.ico` ali `.png`.

```bash
# Ali se pred ali po vsakem skriptu nalaga dodatna koda?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# Koda PHP v datotekah s končnico slike ali ikone
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null
```

## Ločevanje legitimnega zakritja od škodljive kode

Ni vsaka neberljiva koda zlonamerna. Pogosti so trije primeri:

1. **Komercialni kodirniki:** Nekateri proizvajalci vtičnikov in programske opreme svojo kodo ščitijo z orodji, kot sta ionCube ali SourceGuardian. Datoteke so neberljive, a praviloma kažejo na potreben nalagalnik (loader). Primerjajte jih z izvirnim paketom.
2. **Minificirana ali ustvarjena koda:** Predpomnilniki in mehanizmi predlog ustvarjajo dolge vrstice brez prelomov, vendar brez izvajanja dekodiranega besedila.
3. **Vdelani podatki:** Slike ali pisave kot niz Base64 v datoteki PHP so nenavadni, a neškodljivi, dokler se rezultat ne izvaja.

Najzanesljivejši preizkus je primerjava z virom: če datoteka nespremenjena izvira iz paketa proizvajalca, je legitimna. Če ni v nobenem izvirnem paketu ali od njega odstopa, jo je treba raziskati.

> **Pomembno:**
> Zakrite kode ne poskušajte dešifrirati na produkcijskem strežniku, na primer tako, da `eval` zamenjate z izpisom in datoteko prikličete. Že napaka pri tem izvede škodljivo kodo. Analiza sodi v izolirano okolje.

## Meje iskanja po vzorcih

Napadalci poznajo običajne iskalne ukaze. Imena funkcij razdelijo, jih sestavijo med izvajanjem ali pravo kodo preselijo v podatkovno bazo, slikovne datoteke ali konfiguracijske vnose. Iskanje po vzorcih zato najde veliko, a ne vsega. Zakaj tudi pregledovalniki tu naletijo na meje, pojasnjuje [Pregledovalniki škodljive programske opreme za spletne strani: kaj najdejo in česa ne](https://phpsos.de/sl/blog/grenzen-von-malware-scannern/).

Najdba je poleg tega redko edina. Napadalci v več datotekah pogosto uporabijo isti gradnik, na primer opazno oznako spremenljivke ali značilen niz na začetku kodiranega bloka. Po potrjeni najdbi zato ciljno iščite natanko ta niz v celotnem spletnem imeniku, tudi v drugih spletnih straneh na istem strežniku. Tako najdete sorojence, ki jih nobeno splošno iskanje po vzorcih ni zajelo.

Iskanje dopolnite s primerjavo z izvirnimi datotekami in pogledom v podatkovno bazo, glejte [Preverjanje podatkovne baze glede vnesene kode](https://phpsos.de/sl/blog/datenbank-auf-schadcode-pruefen/). Preventivno je mogoče nepotrebne sistemske funkcije zakleniti, kot opisuje vodnik [Pravilna uporaba disable_functions](https://phpsos.de/sl/ratgeber/disable-functions/).

## Kako PHP SOS pomaga konkretno?

- **Iskanje:** Datoteke in podatkovno bazo preiščemo z razširjenimi vzorci in primerjamo z izvirnimi paketi.
- **Analiza:** Sumljivo kodo raziščemo v izoliranem okolju, ne da bi ogrozili vaš sistem.
- **Čiščenje:** Z [odstranjevanjem škodljive programske opreme](https://phpsos.de/sl/leistungen/malware-entfernung/) odstranimo vse sestavne dele in zapremo pot vdora.
- **Zaščita:** Omejimo funkcije PHP in pravice pisanja ter nadzorujemo nove ali spremenjene datoteke.


## Pogosta vprašanja

**Ali je eval z base64_decode vedno škodljiva koda?**  
Ne vedno, a zelo pogosto. Legitimna koda te kombinacije skoraj ne potrebuje. V datotekah, ki ne sodijo k vaši aplikaciji ali znanemu vtičniku, je močan opozorilni znak.

**Ali smem zakrito kodo za branje dekodirati?**  
Samo brez izvajanja in ne na produkcijskem strežniku. Že nenamerno izvajanje lahko povzroči škodo. Ob dvomih analizo prepustite strokovnjakom, ki delajo z izoliranimi okolji.

**Zakaj moj pregledovalnik škodljive programske opreme kode ne najde?**  
Pregledovalniki iščejo znane vzorce. Napadalci svojo kodo nenehno spreminjajo, razdelijo imena funkcij ali jih sestavijo med izvajanjem. Prazen pregled zato ni dokaz za čist strežnik.

**Kaj pa komercialno šifrirani vtičniki?**  
Nekateri proizvajalci svojo kodo ščitijo s kodirniki, kot sta ionCube ali SourceGuardian. Take datoteke so neberljive, a legitimne, če izvirajo od proizvajalca. Primerjajte jih z izvirnim paketom.

**Ali disable_functions pomaga proti zakriti kodi?**  
Deloma. Funkcije, kot sta exec ali system, je mogoče zakleniti, eval pa ne, ker je jezikovna konstrukcija in ne funkcija. Zapora napadalcem otežuje naslednji korak, ne prepreči pa vsake škodljive kode.

## Viri

- [Priročnik PHP: assert()](https://www.php.net/manual/de/function.assert.php)
- [Priročnik PHP: create_function()](https://www.php.net/manual/de/function.create-function.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
