Fjernkjøring av kode med XStream

1. Oversikt

I denne opplæringen vil vi dissekere et eksternt kodeutførelsesangrep mot XStream XML-serialiseringsbiblioteket. Denne utnyttelsen faller inn i utro av deserialisering kategori av angrep.

Vi får vite når XStream er sårbart for dette angrepet, hvordan angrepet fungerer, og hvordan vi kan forhindre slike angrep.

2. Grunnleggende om XStream

Før vi beskriver angrepet, la oss se gjennom noen grunnleggende om XStream. XStream er et XML-serialiseringsbibliotek som oversettes mellom Java-typer og XML. Tenk på en enkel Person klasse:

offentlig klasse Person {privat String først; privat streng sist; // standard getters og setters}

La oss se hvordan XStream kan skrive noen Person forekomst til XML:

XStream xstream = ny XStream (); Streng xml = xstream.toXML (person);

På samme måte kan XStream lese XML i en forekomst av Person:

XStream xstream = ny XStream (); xstream.alias ("person", Person.class); String xml = "JohnSmith"; Personperson = (Person) xstream.fromXML (xml);

I begge tilfeller bruker XStream Java-refleksjon for å oversette Person skriv til og fra XML. Angrepet finner sted under lesing av XML. Når du leser XML, instanserer XStream Java-klasser ved hjelp av refleksjon.

Klassene XStream instantiates bestemmes av navnene på XML-elementene den analyserer.

Fordi vi konfigurerte XStream til å være klar over Person type, Instruerer XStream en ny Person når den analyserer XML-elementer kalt “person”.

I tillegg til brukerdefinerte typer som Person, Gjenkjenner XStream kjerne-Java-typer ut av esken. For eksempel kan XStream lese a Kart fra XML:

String xml = "" + "" + "" + "foo" + "10" + "" + ""; XStream xStream = ny XStream (); Map map = (Map) xStream.fromXML (xml); 

Vi får se hvordan XStreams evne til å lese XML som representerer kjerne-Java-typer, vil være nyttig i den eksterne koden.

3. Hvordan angrepet fungerer

Eksterne kodeutførelsesangrep oppstår når angripere gir innspill som til slutt tolkes som kode. I dette tilfellet utnytter angripere XStreams deserialiseringsstrategi ved å oppgi angrepskode som XML.

Med riktig sammensetning av klasser kjører XStream til slutt angrepskoden gjennom Java-refleksjon.

La oss bygge et eksempelangrep.

3.1. Inkluder angrepskode i en ProcessBuilder

Angrepet vårt tar sikte på å starte en ny stasjonær kalkulatorprosess. På macOS er dette “/Applications/Calculator.app”. På Windows er dette “calc.exe”. For å gjøre det, vil vi lure XStream til å kjøre en ny prosess ved hjelp av en ProcessBuilder. Husk Java-koden for å starte en ny prosess:

ny ProcessBuilder (). kommando ("executable-name-here"). start ();

Når du leser XML, påkaller XStream bare konstruktører og setter felt. Derfor har ikke angriperen en grei måte å påberope seg ProcessBuilder.start () metode.

Imidlertid kan smarte angripere bruke riktig sammensetning av klasser for til slutt å utføre ProcessBuilder‘S start() metode.

Sikkerhetsforsker Dinis Cruz viser oss i blogginnlegget deres hvordan de bruker Sammenlignelig grensesnitt for å påkalle angrepskoden i kopikonstruktøren til den sorterte samlingen TreeSet. Vi oppsummerer tilnærmingen her.

3.2. Lage en Sammenlignelig Dynamisk proxy

Husk at angriperen må lage en ProcessBuilder og påkalle sin start() metode. For å gjøre det, oppretter vi en forekomst av Sammenlignelig hvem sin sammenligne metoden påkaller ProcessBuilder‘S start() metode.

Heldigvis tillater Java Dynamic Proxies oss å lage en forekomst av Sammenlignelig dynamisk.

Videre Java EventHandler klasse gir angriperen en konfigurerbar InvocationHandler gjennomføring. Angriperen konfigurerer EventHandler å påkalle ProcessBuilder‘S start() metode.

Når vi setter disse komponentene sammen, har vi en XStream XML-representasjon for Sammenlignelig fullmektig:

 java.lang.Comparable open /Applications/Calculator.app start 

3.3. Tving en sammenligning ved hjelp av Sammenlignelig Dynamisk proxy

For å tvinge en sammenligning med vår Sammenlignelig proxy, vi bygger en sortert samling. La oss bygge en TreeSet samling som sammenligner to Sammenlignelig forekomster: a String og vår fullmektig.

Vi bruker TreeSetKopikonstruktør for å bygge denne samlingen. Til slutt har vi XStream XML-representasjonen for en ny TreeSet inneholder vår fullmektig og en String:

 foo java.lang.Comparable open /Applications/Calculator.app start 

Til slutt oppstår angrepet når XStream leser denne XML-en. Mens utvikleren forventer at XStream leser en Person, utfører den i stedet angrepet:

Streng sortedSortAttack = // XML ovenfra XStream xstream = ny XStream (); Personperson = (Person) xstream.fromXML (sortedSortAttack);

3.4. Angrepssammendrag

La oss oppsummere de reflekterende samtalene som XStream foretar når den deserialiserer denne XML-en

  1. XStream påkaller TreeSet kopi konstruktør med en Samling inneholder en String “Foo” og vår Sammenlignelig fullmektig.
  2. De TreeSet konstruktør kaller vår Sammenlignelig fullmektiger sammenligne med metode for å bestemme rekkefølgen på elementene i det sorterte settet.
  3. Våre Sammenlignelig dynamisk proxy delegerer alle metodeanrop til EventHandler.
  4. De EventHandler er konfigurert til å påkalle start() metoden for ProcessBuilder den komponerer.
  5. De ProcessBuilder gafler en ny prosess som kjører kommandoen angriperen ønsker å utføre.

4. Når er XStream sårbar?

XStream kan være sårbar for dette eksterne kodeutførelsesangrepet når angriperen kontrollerer XML den leses.

Tenk for eksempel på et REST API som godtar XML-inngang. Hvis dette REST API bruker XStream til å lese organer for XML-forespørsler, kan det være sårbart for et eksternt kjøringsangrep fordi angripere kontrollerer innholdet i XML sendt til API.

På den annen side har et program som bare bruker XStream til å lese klarert XML, en mye mindre angrepsflate.

Tenk for eksempel på et program som bare bruker XStream til å lese XML-konfigurasjonsfiler satt av en applikasjonsadministrator. Dette programmet utsettes ikke for XStream ekstern kjøring av kode fordi angripere ikke har kontroll over XML-applikasjonen leser (administratoren er).

5. Herding av XStream mot eksterne kodeutførelsesangrep

Heldigvis introduserte XStream et sikkerhetsrammeverk i versjon 1.4.7. Vi kan bruke sikkerhetsrammeverket for å forsterke vårt eksempel mot ekstern kjøring av angrep. Sikkerhetsrammeverket lar oss konfigurere XStream med en hvitliste av typer det er tillatt å instantiere.

Denne listen vil bare omfatte grunnleggende typer og våre Person klasse:

XStream xstream = ny XStream (); xstream.addPermission (NoTypePermission.NONE); xstream.addPermission (NullPermission.NULL); xstream.addPermission (PrimitiveTypePermission.PRIMITIVES); xstream.allowTypes (ny klasse [] {Person.class});

I tillegg kan XStream-brukere vurdere å herde systemene sine ved hjelp av en RASP-agent (Runtime Application Self-Protection). RASP-agenter bruker bytecode-instrumentering på kjøretid for automatisk å oppdage og blokkere angrep. Denne teknikken er mindre utsatt for feil enn manuelt å lage en hvitliste av typer.

6. Konklusjon

I denne artikkelen lærte vi hvordan vi kan utføre et eksternt kodeutførelsesangrep på et program som bruker XStream til å lese XML. Fordi angrep som dette eksisterer, må XStream herdes når den brukes til å lese XML fra ikke-klarerte kilder.

Utnyttelsen eksisterer fordi XStream bruker refleksjon for å øyeblikkeliggjøre Java-klasser identifisert av angriperens XML.

Som alltid kan koden for eksemplene finnes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found