Feltört WordPress oldalak takarítása: Kaszinóspam, hátsó ajtók, zombi szerverek – 1. rész: Mi történt, és hogyan bújt el a támadó?
Bevezető: egy szerver, négy oldal, nyolc hónap
Egy feltört WordPress oldal ritkán omlik össze látványosan. Sokkal gyakoribb, hogy hónapokig csendben rejtőzködve dolgozik a támadónak, miközben te és a látogatók semmit nem vesztek észre.
Ez a cikk egy valós, 2026-os incidensből indul ki, amelyet én vizsgáltam ki és takarítottam le. Egyetlen kisebb virtuális szerveren négy WordPress-oldal, egy webmail és egy adatbázis-kezelő felület (phpmyadmin basic auth védelemmel) futott. Az év elején a támadó kódfuttatási lehetőséget szerzett az egyik oldalon, és a következő nyolc hónapban a következők történtek:
- kaszinóspam-oldalakat hozott létre publikusan a keresőknek, miközben a látogatók és az adminok tiszta oldalt láttak;
- rejtett admin felhasználókat hozott létre, és egy rejtett (MU = must use) bővítménnyel minden más admin jelszavát átírta;
- kódolt botprogramot futtatott a szerveren, amely más gépeket vizsgált és megtöltötte a lemezt;
- legalább hétféle, egymástól független visszatérési utat hagyott hátra, köztük olyat is, amely a fájlrendszerben egyáltalán nem létezik.
Többször letakarítottam mindent, és többször azt hittem, hogy (végre) vége. Ez a háromrészes cikksorozat arról szól, miért nem volt vége, mit akarnak ezek a támadók, és mit kell tenned, hogy ne kerülj ilyen helyzetbe. Ebben, az 1. részben azt mutatom be, mi történt, hogyan jutott be a támadó, és milyen körmönfont módszerekkel rejtőzött el. Kitérek egy másik szerveren talált fertőzésre is, amely a bejelentkezéskor beírt jelszavakat lopta el.
Az ügyfelek adatait, a domaineket és a konkrét azonosítókat szándékosan kihagytam. A módszerek viszont bármely WordPress oldalon pontosan így működnek (több hasonló esettel találkoztam idén).
Hogyan jutott be a támadó?
Őszintén szólva a kezdeti behatolás pontos módját nem tudom bizonyítani. A webszerver naplói néhány hét után törlődtek, így az első hónapok naplói a vizsgálat idején már nem léteztek. A nyomok alapján három lehetséges út maradt:
- Elavult bővítmények ismert sérülékenységgel: Az egyik oldalon több, évek óta nem frissített bővítmény futott, köztük egy régóta ismert, nyilvánosan dokumentált sérülékenységgel. Az ilyen hibákat automata botok órák alatt megtalálják (sokszor readme.txt, style.css vagy egyéb javascript fájlokban).
- Érvényes admin hozzáférés: A médiatárban talált feltöltések azt mutatták, hogy a támadó már a fertőzés korai szakaszában egy valódi admin fiókkal is dolgozott. A jelszó tehát valahonnan kiszivárgott. Én ezt tartom a legvalószínűbbnek.
- Újrahasznosított jelszó: Ugyanaz a hozzáférés egy másik alkalmazás konfigurációjában nyílt szövegként is szerepelt.
Egy dolog viszont biztos: ha egyszer bejutott, akkor minden oldalhoz hozzáfért. Mind a négy oldal ugyanazzal a rendszerfelhasználóval és ugyanazzal a globális jogú adatbázis-felhasználóval futott (itt épp Apache webszerver futott). A támadó egy webshellből kiolvasta a wp-config.php-t (ebben benne van a WordPress mögötti adatbázis jelszó), és onnan bármelyik adatbázisba írhatott. Ezért kerültek nyomok olyan oldalra is, ahol fájlszintű behatolás soha nem történt.
Hogyan rejtik el a kaszinós cikkeket? Mindenki elől, kivéve a Google-t
A kaszinóspam lényege, hogy a Google lássa, a tulajdonos viszont ne (hiszen akkor gyanút fogna). Az általam vizsgált esetben a spamoldalak évekig indexelődtek, miközben a wp-admin bejegyzéslistája, a nyilvános oldal és a tulajdonos böngészője tiszta képet mutatott, és majdnem mindig ez a módszer.
1. Cloaking a Google IP-címei alapján. A kártevő letölti és helyben gyorsítótárazza a Google hivatalosan közzétett IP-tartománylistáját. Ha a kérés onnan jön, a spamtartalmat adja vissza, mindenki másnak az eredeti oldalt. A User-Agent alapú szűrésnél ez jóval megbízhatóbb, mert egy böngészőbővítménnyel „Googlebotnak öltözött” ember sem látja a spamet. A Google spam-irányelvei is leírják, hogy feltört oldalakon a támadók gyakran cloakinggal nehezítik a felfedezést.
2. Szellem-szerzők. A spambejegyzéseket nem a WordPress felületén, hanem közvetlen SQL lekérdezéssel szúrják be a wp_posts táblába (itt tárolódnak a WordPress tartalmai, oldalak, bejegyzések, stb.), olyan szerző (author) azonosítóval, amely nem létezik a felhasználók között. Gyakran tömegesen, másodpercre azonos dátummal.
3. Kiszűrés az admin listából. A kártevő egy szűrővel módosítja a wp-admin lekérdezését, hogy az előbb leírt szellem-szerzők bejegyzései ne jelenjenek meg. Az adminisztrátor a Bejegyzések menüben semmit nem lát, az adatbázisban viszont ott figyel több száz bejegyzés.
4. Az SEO-bővítmények kijátszása. Kikapcsolja a Yoast vagy a Rank Math (vagy épp feltöri a bővítményt is) noindex beállításait a spamoldalakra, hogy biztosan indexelődjenek.
5. Hamis sitemap és robots.txt. Külön XML-oldaltérképet generál kizárólag a spamoldalakból (például egy sitemap83.xml jellegű nevet), és a robots.txt-be hamis „Sitemap:” sorokat ír, hogy a keresők gyorsabban megtalálják őket.
6. Látogatóknak szóló JavaScript-átirányítás. Base64-kódolt, document.write-tal beszúrt script, amely kiüríti az oldal tartalmát, és egy külső szerencsejáték-oldal kódját tölti be. Gyakran csak keresőből érkezőknek vagy csak mobilon fut le.
7. Konfiguráció az adatbázisban, nem a kódban. A rejtett szerzőazonosítók (user_id), a linkszövegek és a JavaScript-payload a wp_options táblában vannak, egy véletlenszerűnek látszó, 32 karakteres hexadecimális nevű opcióban. A név valójában a domainnévből számolt hash. Emiatt a PHP-kód minden fertőzött oldalon azonos és sablonszerű, a tartalom viszont oldalanként más. Egy másik trükk, hogy a WordPress saját átmeneti gyorsítótár-bejegyzéseinek (_transient_update_plugins_…) nevét utánozzák.
8. Legitimnek tűnő kód. A beszúrt PHP-függvények neve WordPress-szerű (például wp_die_ajax vagy is_admin_queue), de egyik sem létezik a WordPress rendszer fájlokban. Ha csak gyorsan átfutod, akkor általában senkinek nem tűnik fel.
Hogyan veheted észre? Néhány egyszerű jel:
- Keress rá a Google-ben: site:sajatdomain.hu kaszinó vagy site:sajatdomain.hu casino. Ha olyan találat jön, amit nem te írtál, már baj van.
- Nézd meg a Search Console-ban az indexelt oldalak számát. Egy hirtelen, magyarázat nélküli ugrás tipikus jel.
- Figyeld meg, milyen kulcsszavakra jelenik meg az oldalad. Ha egy fogászati rendelő oldala bónuszkódokra kap megjelenéseket, azt nem a tartalommarketing hozta.
- Nézd meg a Search Console Biztonsági problémák és Kézi műveletek jelentését.
A hátsó ajtók: amiért egy takarítás soha nem elég
A támadó tudja, hogy előbb-utóbb takarítani fognak. Ezért nem egy, hanem több, egymástól független visszatérési utat hagy hátra, mindegyiket más rétegben. Ha az egyiket megtalálják, a többi tovább működik. Nálam a következők kerültek elő, nagyjából a felfedezés sorrendjében.
| # | Hátsó ajtó (backdoor) | Hol van? | Mi nem látja? |
|---|---|---|---|
| 1 | Kártékony blokk a téma functions.php-jában | Fájlrendszer, legitim fájlon belül | A „töröld a gyanús fájlt” típusú takarítás |
| 2 | Egysoros eval() egy HTTP-fejlécből a wp-config.php-ban | Fájlrendszer, a webgyökérben | wp core verify-checksums, a csak wp-content-et néző szkennerek |
| 3 | Kártékony kód egy kódrészlet-bővítményben (WPCode, Code Snippets) | Adatbázis | Minden fájlalapú vizsgálat |
| 4 | MySQL-trigger, amely admin felhasználót hoz létre | Adatbázis-motor | Fájl-, tartalom- és admin-lista-ellenőrzés, és a WordPress maga |
| 5 | Magát elrejtő kártékony bővítmény, képnek álcázott kóddal | Fájlrendszer + adatbázis | A wp-admin bővítménylistája, a checksum-ellenőrzés |
| 6 | Trójaivá alakított, nem hivatalos forrásból származó SEO-bővítmény | Fájlrendszer | A checksum-ellenőrzés (nem tudja ellenőrizni) |
| 7 | Hitelesítés nélküli feltöltők, jelszavas fájlkezelő webshell | Fájlrendszer, hamis néven és dátummal | Az eval-mintákra kereső szkennerek |
1–2. Kód a legitim fájlokban
A kártékony blokk egy már létező, valódi fájlba kerül, két egyedi, 32 karakteres hash-komment közé zárva. Gyerektéma esetén a szülő- és a gyerektémát (child) is ellenőrizni kell, mert a WordPress mindkettőt betölti.
A legveszélyesebb egyetlen sor volt a wp-config.php-ban. Ez egy véletlen nevű HTTP-fejléc tartalmát futtatta le PHP-kódként, hitelesítés nélkül. A támadónak így nem kellett se jelszó, se fájlfeltöltés: egyetlen kéréssel bármikor bármit futtathatott. Azért élte túl az első takarítást, mert a wp-config.php nem része a WordPress-magnak, így a checksum-ellenőrzés nem nézi, a szkennerem pedig csak a wp-content mappát vizsgálta.
3. Kód, ami csak az adatbázisban létezik
A támadó admin jogosultsággal a teljes kártékony kódot egy kódrészlet-bővítménybe illesztette (Code Snippets), ártalmatlan névvel (például „Completely Disable Comments”), mindenhol futó beállítással. PHP-fájl nincs, tehát fájlszintű vizsgálat nem találja meg. Ha a bővítményt később törlik, gyakran megmaradnak árva adatbázis-sorok, például egy korábbi hibaüzenet, amely a teljes kódot tartalmazza. Ez a technika annyira elterjedt, hogy biztonsági cégek és WordPress fejlesztői blogok külön is dokumentálták a Google Ads-tiltások egyik fő okaként.
4. Adatbázis-trigger: a legcizelláltabb csapda
Ez volt a legravaszabb módszer, amit találtam. Mind a négy adatbázisban egy MySQL-trigger figyelte a hozzászólások tábláját. Ha valaki egy bizonyos mondatot (`are you struggling to get comments on your blog?`) tartalmazó hozzászólást küldött be, a trigger az adatbázis szintjén automatikusan létrehozott egy adminisztrátor felhasználót a támadó által ismert jelszóval.
Miért zseniális ez a támadó szemszögéből?
- Nincs fájl, a WordPress nem tud róla, egyetlen biztonsági bővítmény sem nézi.
- A beszúrás előtt fut, tehát akkor is létrehozza a fiókot, ha a hozzászólást a spamszűrő vagy a moderátor később elutasítja.
- Bárki kiválthatja, regisztráció nélkül, ahol a hozzászólás nyitott.
- A létrehozott fiók régi regisztrációs dátumot és wordpress.com webcímet kap, ezért ártalmatlannak tűnik.
- Minden takarítást túlél: én szeptember elején töröltem a hamis adminokat, a trigger viszont bármikor újra létrehozhatta volna őket.
- A mysqldump alapértelmezetten menti a triggereket, így a takarítás előtti mentések is tartalmazták. Egy visszaállítás is visszahozta volna.
Egy véletlen leplezte le: amikor egy tesztkörnyezetbe importáltam az adatbázist, a trigger miatt hibát kaptam. Az egyik triggert ráadásul a takarítás után, az oldal saját adatbázis-felhasználójával hozták újra létre. Ez bizonyította, hogy a támadónak ekkor még élő kódfuttatása volt, éppen a wp-config.php-ba rejtett sor révén.
5. A magát elrejtő bővítmény
Egy ismeretlen nevű bővítmény egy WordPress-szűrővel kivette magát a wp-admin bővítménylistájából. A „képek” mappájában lévő PNG és GIF fájlok valójában kódolt szövegek voltak, valódi képfejléc nélkül. A betöltő ezeket dekódolta és futtatta. Benne volt egy teljes webshell (fájlkezelő, SQL-kliens, jelszótörő), egy távoli parancsszerverről kódot letöltő modul és obfuszkált (szándékosan olvashatatlanná tévő, de működő kód) JavaScript. Egy másik, médiatárba ZIP-ként feltöltött álcázott bővítmény rejtett admin usert hozott létre, és minden más admin jelszavát egyszer átírta.
A bővítmény a WP-CLI listájában látszott, és a checksum-ellenőrzés jelezte, hogy „nem tudja ellenőrizni”. Ezt a sort egy korábbi vizsgálat átsiklotta. Végül én vettem észre, nem a szkenner.
6. A trójaivá alakított SEO-bővítmény
Egy népszerű SEO-bővítményt (RankMath SEO) egy nem hivatalos forrásból származó másolatra cseréltek. A fő fájljába egy rövid betöltő került, mellé egy, a bővítmény részének látszó extra fájl. A beállítását a takarításkor töröltem, de a betöltő hetekig ott maradt, alvó állapotban.
7. Feltöltők és webshellek hamis névvel, hamis dátummal
Ugyanaz a néhány soros, hitelesítés nélküli feltöltő több helyen is ott volt, sablonfájlnak látszó nevekkel (…-less.php, …-merge.php, …-core.php). A dátumukat évekkel korábbira állították, hogy a „mi változott mostanában” keresések ne találják meg. A szövegfájlnak álcázott mentések (functions.txt, functions.php_bak) pedig kívülről olvashatók voltak, a webszerver egyszerű szövegként szolgálta ki őket.
A közös tanulság: egyik hátsó ajtó sem volt látható ugyanazzal a módszerrel. Fájl-checksum, tartalmi keresés, adatbázis-objektumok, admin jogosultságok, folyamatok és mentések: mindet külön kell ellenőrizni.
A jelszótolvaj: amikor a saját bejelentkezésed a szivárgás oka
Egy másik szerveren olyan fertőzést találtam, amely nem a fájlokat vagy az adatbázist támadta, hanem engem. A kártékony kód a WordPress bejelentkezési folyamatába épült be. Amikor beléptem a wp-adminba, a begépelt jelszót titkosítatlanul, még a hash-elés előtt elkapta, és szinte azonnal továbbküldte egy külső szerverre. Ez gyakorlatilag egy szerveroldali keylogger: nem a gépedet fertőzi meg, hanem azt az oldalt, ahová a jelszavadat beírod.
Miért ennyire veszélyes?
- A hash nem véd. A WordPress a jelszót csak hash-elve tárolja, de a bejelentkezés pillanatában a szerver megkapja a valódi jelszót. A kártevő pontosan itt csap le, így a támadónak semmit nem kell visszafejtenie.
- Az erős jelszó sem véd. Egy 32 karakteres, véletlen jelszót ugyanúgy elküld, mint a „123456”-ot.
- A jelszócsere is csak friss jelszót ad neki, amíg a kártevő a helyén van. A fő esetemben pontosan ez történt: a takarítás közben / után lecserélt admin jelszót egy még aktív, rejtett bővítmény elkapta, és a támadó három héttel később első próbálkozásra belépett vele.
Nem egyedi eset: a nyilvános nyomok
Ez a technika jól dokumentált, és az utóbbi két évben egyre kifinomultabb változatai jelentek meg.
| Elemzés | Mit csinált a kártevő? |
|---|---|
| Sucuri, 2025. június | Gyorsítótár-bővítménynek álcázott fájl. A bejelentkezési eseményre (wp_login) akaszkodva az admin és szerkesztő jogú felhasználók nevét, jelszavát és jogosultságait egy külső címre küldte, és elrejtette magát a bővítménylistából. A Sucuri szerint a támadók így később is be tudtak lépni. |
| Monarx, 2026. január | Wordfence-nek álcázott „must-use” bővítmény. A wp_authenticate hookkal a hash-elés előtt elkapta a felhasználónevet és a jelszót, sikeres admin belépéskor pedig a teljes szerverinformációval együtt kiküldte. Mellé jelszó nélküli belépést adó hátsó ajtót (backdoor) is tett. |
| Wordfence-elemzés, 2026. szeptember | „Must-use” bővítmény (amit nem lehet kikapcsolni, csak FTP-ről közvetlenül fájlszinten törölve), több ezer különböző fájlnévvel. Az authenticate szűrőn keresztül titkosítatlanul gyűjtötte az admin jelszavakat, rejtett admint hozott létre, és megosztott tárhelyen átmásolta magát a többi elérhető WordPress-telepítésbe. Fizetési szolgáltatók API-kulcsait is kereste. |
A Monarx kutatói külön kiemelik: ha az ellopott jelszót máshol is használod, a támadó minden olyan helyhez hozzáfér, ahol ugyanaz a jelszó él.
Mit kezd a támadó egy ellopott jelszóval?
Egy ellopott, működő felhasználónév + jelszó páros sokkal értékesebb, mint egy feltörendő hash. A támadónak nem kell feltörnie semmit, csak ki kell próbálnia máshol is. Az én esetemben minden jel arra mutat, hogy pontosan ez történt.
Az ilyen, hasonló weboldalak megtalálása nem nehéz. Egy WordPress-oldal sokat elárul magáról:
- A téma: a neve, verziója és szerzője kiolvasható a wp-content/themes/<téma>/style.css fájl fejlécéből, a mappanév pedig a forráskódban minden oldalon látszik. Egy fejlesztő vagy ügynökség oldalai gyakran ugyanarra a saját gyerektémára vagy keretrendszerre épülnek.
- A felhasználónevek: alapbeállítás mellett a szerzői oldalak és a REST API felhasználói végpontja is kiadja őket.
- A közös kód: azonos egyedi bővítmények, azonos fájlstruktúra, azonos lábléc-hivatkozás (backlink ellenőrzéssel is összegyűjthető pusztán a Google-ből).
Ezekből automatikusan összegyűjthető az azonos kézből származó oldalak listája. Ha ugyanaz az admin felhasználónév és jelszó több ügyféloldalon is él, egyetlen ellopott jelszó mindegyiket megnyitja. Nem kell hozzá se sérülékenység, se brute force (jelszótörés szótár alapján): egyszerű, érvényes bejelentkezés, amit a legtöbb biztonsági bővítmény nem is jelez gyanúsnak.
Hogyan védekezz?
- Kétlépcsős azonosítás (2FA) minden admin és szerkesztő fiókra, időalapú kóddal (TOTP) vagy hardverkulccsal. Ez az egyetlen védelem, amely egy titkosítatlanul ellopott jelszót is használhatatlanná tesz. Fontos korlát: a 2FA nem helyettesíti a takarítást, mert egy már bent lévő hátsó ajtó jelszó nélkül is beléptetheti a támadót (főleg, ha pl. a WordFence-ben whitelistelnek egy IP címet, ami a támadóé).
- Egyedi jelszó minden oldalra, jelszókezelővel. Soha ne legyen ugyanaz az admin jelszó két ügyfélnél, és a tárhely, az FTP vagy az e-mail jelszava se egyezzen vele.
- Ne legyen kitalálható az admin felhasználónév, és ne egyezzen a nyilvánosan megjelenő szerzői névvel. A REST API felhasználói végpontját is korlátozd.
- Legújabb WordPress, friss és támogatott PHP-verzió, és csak hivatalos forrásból származó bővítmények. A fenti esetek mindegyikében álca-bővítmény volt a hordozó.
- Nézd át a wp-content/mu-plugins mappát is. Az itt lévő fájlok automatikusan betöltődnek, és a wp-admin normál bővítménylistájában nem látszanak.
- Figyeld a kimenő forgalmat. Egy weboldalnak nincs oka bejelentkezéskor ismeretlen domainre adatot küldeni.
- Gyanú esetén minden jelszót tekints kompromittáltnak, amelyet az érintett oldalon valaha begépeltek, és cseréld mindenhol, ahol ugyanazt használták. Cseréld a WordPress-saltokat is. De csak a kártevő eltávolítása után.
Gyors ellenőrzés: mely fájlok akaszkodnak a bejelentkezési folyamatra? Legitim bővítmények (biztonsági, 2FA, naplózó) is használják ezeket a hookokat, ezért minden találatot egyenként kell megnézni, különösen az ismeretlen vagy egyfájlos bővítményeket.
# bejelentkezési hookokra akaszkodó kód (a találatokat kézzel kell átnézni) grep -rnE "add_(action|filter)\(\s*['\"](wp_login|wp_authenticate|authenticate)['\"]" \ /var/www/oldal/wp-content/ /var/www/oldal/wp-config.php # must-use bővítmények: ezek a wp-adminban nem látszanak ls -la /var/www/oldal/wp-content/mu-plugins/ # kimenő HTTP-hívás külső címre a bővítményekben és a témákban grep -rnlE "wp_remote_(post|request)|curl_exec" /var/www/oldal/wp-content/mu-plugins /var/www/oldal/wp-content/plugins
Mit nyer ezzel a támadó?
Most már tudod, hogyan jutott be a támadó, és milyen alattomos módszerekkel bujkált hónapokig. De mit nyer ezzel, és mit veszítesz vele te? Miért pont a WordPress a célpont, mit büntet a Google, és miért állhat le egy Google Ads- vagy Facebook-kampány egy fertőzött oldal miatt? Olvasd tovább a 2. részben: 2. rész – Mit okoz egy fertőzött oldal, és miért éri meg a támadónak? (HAMAROSAN!)
Források
- Google Search Central: Spam policies for Google web search
- Imunify360: Google Ads tiltás a WPCode-ba rejtett kód miatt
- Sucuri: Fake WordPress Caching Plugin Used to Steal Admin Credentials, 2025. június 4.
- Monarx: Malicious Fake Wordfence MU-Plugin, 2026. január 5.
- GBHackers: Stealthy WordPress Malware Uses Must-Use Plugin and EtherHiding (a Wordfence elemzése alapján), 2026. szeptember 23.
Gyanakszol, hogy az oldaladat megfertőzték? Vagy szeretnéd biztonságban tudni a weboldaladat és az adataidat? Keress meg bátran, és nézzük át együtt.