Daljinsko izvršavanje koda s XStreamom

1. Pregled

U ovom uputstvu ćemo secirati napad na daljinsko izvršavanje koda protiv XStream XML biblioteke za serializaciju. Ovaj pothvat spada u nepovjerena deserializacija kategorija napada.

Saznat ćemo kada je XStream ranjiv na ovaj napad, kako napad djeluje i kako spriječiti takve napade.

2. Osnove XStreama

Prije opisa napada, pregledajmo neke osnove XStreama. XStream je XML knjižnica za serializaciju koja prevodi između Java vrsta i XML-a. Razmislite o jednostavnom Osoba razred:

javni razred Osoba {prvo privatni niz; private String last; // standardni geteri i postavljači}

Pogledajmo kako XStream može nešto napisati Osoba instanca u XML:

XStream xstream = novi XStream (); Niz xml = xstream.toXML (osoba);

Isto tako, XStream može čitati XML u instanci Osoba:

XStream xstream = novi XStream (); xstream.alias ("osoba", osoba.razred); Niz xml = "JohnSmith"; Osoba osoba = (Osoba) xstream.fromXML (xml);

U oba slučaja XStream koristi Java refleksiju za prevođenje Osoba upišite u i iz XML-a. Napad se događa tijekom čitanja XML-a. Kada čita XML, XStream instancira Java klase pomoću refleksije.

Klase XStream instanciraju određene su imenima XML elemenata koje on raščlanjuje.

Budući da smo konfigurirali XStream da bude svjestan Osoba tipa, XStream pokreće novi Osoba kada raščlanjuje XML elemente pod nazivom "osoba".

Uz korisnički definirane vrste poput Osoba, XStream prepoznaje osnovne tipove Java izravno. Na primjer, XStream može čitati a Karta iz XML-a:

Niz xml = "" + "" + "" + "foo" + "10" + "" + ""; XStream xStream = novi XStream (); Karta karte = (Map) xStream.fromXML (xml); 

Vidjet ćemo kako će sposobnost XStreama za čitanje XML-a koji predstavlja osnovne tipove Java biti korisna u udaljenom eksploatacijskom izvršavanju koda.

3. Kako djeluje napad

Daljinski napadi izvršavanja koda događaju se kada napadači daju ulaz koji se u konačnici tumači kao kôd. U ovom slučaju napadači iskorištavaju strategiju deserializacije XStreama pružajući napadački kôd kao XML.

Uz pravilan sastav klasa, XStream u konačnici pokreće kôd napada kroz Java refleksiju.

Izgradimo primjer napada.

3.1. Uključite kod napada u a ProcessBuilder

Naš napad ima za cilj pokretanje novog postupka izračunavanja stolnih računala. Na macOS-u je ovo /Applications/Calculator.app. U sustavu Windows ovo je "calc.exe". Da bismo to učinili, prevarit ćemo XStream da pokrene novi postupak pomoću a ProcessBuilder. Prisjetite se Java koda da biste započeli novi postupak:

novi ProcessBuilder (). naredba ("ime-izvršne-ovdje-ovdje"). start ();

Kada čita XML, XStream poziva samo konstruktore i postavlja polja. Stoga napadač nema izravan način pozivanja na ProcessBuilder.start () metoda.

Međutim, pametni napadači mogu koristiti pravi sastav klasa da bi u konačnici izvršili ProcessBuilder‘S početak() metoda.

Istraživač sigurnosti Dinis Cruz u svom blogu pokazuje nam kako koriste Usporedive sučelje za pozivanje napadačkog koda u konstruktoru kopiranja razvrstane kolekcije TreeSet. Ovdje ćemo rezimirati pristup.

3.2. Stvoriti Usporedive Dinamički proxy

Podsjetimo da napadač mora stvoriti ProcessBuilder i zazovite svoje početak() metoda. Da bismo to učinili, stvorit ćemo primjerak Usporedive čija usporedi metoda poziva na ProcessBuilder‘S početak() metoda.

Srećom, Java Dynamic Proxies omogućuju nam stvaranje instance Usporedive dinamički.

Nadalje, Java Rukovatelj događajima klasa pruža napadaču konfigurabilnu mogućnost InvocationHandler provedba. Napadač konfigurira Rukovatelj događajima pozivati ​​se na ProcessBuilder‘S početak() metoda.

Sastavljajući ove komponente, imamo XStream XML prikaz za Usporedive proxy:

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

3.3. Prisilite usporedbu pomoću Usporedive Dinamički proxy

Da forsiramo usporedbu s našom Usporedive proxy, izgradit ćemo sortiranu zbirku. Izgradimo a TreeSet zbirka koja uspoređuje dvije Usporedive slučajevi: a Niz i naš opunomoćenik.

Koristit ćemo TreeSetKonstruktor kopija za izgradnju ove kolekcije. Napokon, imamo XStream XML predstavljanje za novi TreeSet koji sadrži naš proxy i a Niz:

 foo java.lang.Uporedni otvor /Applications/Calculator.app start 

U konačnici, napad se događa kada XStream pročita ovaj XML. Iako programer očekuje da XStream pročita a Osoba, umjesto toga izvršava napad:

Niz sortedSortAttack = // XML odozgo XStream xstream = new XStream (); Osoba osoba = (Osoba) xstream.fromXML (sortedSortAttack);

3.4. Sažetak napada

Rezimirajmo reflektirajuće pozive koje XStream upućuje kada deserializira ovaj XML

  1. XStream poziva na TreeSet copy konstruktor s a Kolekcija koji sadrži a Niz "Foo" i naš Usporedive opunomoćenik.
  2. The TreeSet konstruktor poziva naš Usporedive punomoćnici usporediTo metoda kako bi se odredio redoslijed stavki u razvrstanom skupu.
  3. Naše Usporedive dinamički proxy delegira sve pozive metode na Rukovatelj događajima.
  4. The Rukovatelj događajima je konfiguriran za pozivanje datoteke početak() metoda ProcessBuilder ono sastavlja.
  5. The ProcessBuilder forksira novi proces koji izvodi naredbu koju napadač želi izvršiti.

4. Kada je XStream ranjiv?

XStream može biti ranjiv na ovaj napad na daljinsko izvršavanje koda kada napadač kontrolira XML koji čita.

Na primjer, razmotrite REST API koji prihvaća XML unos. Ako ovaj REST API koristi XStream za čitanje tijela XML zahtjeva, tada je možda ranjiv na daljinski napad izvršenja koda jer napadači kontroliraju sadržaj XML-a poslan API-ju.

S druge strane, aplikacija koja koristi XStream samo za čitanje pouzdanog XML-a ima mnogo manju površinu napada.

Na primjer, razmotrite aplikaciju koja koristi XStream samo za čitanje XML konfiguracijskih datoteka koje je postavio administrator aplikacije. Ova aplikacija nije izložena izvođenju daljinskog koda XStream jer napadači nemaju kontrolu nad XML-om koji aplikacija čita (admin je).

5. Učvršćivanje XStreama protiv napada na daljinsko izvršavanje koda

Srećom, XStream je predstavio sigurnosni okvir u verziji 1.4.7. Sigurnosni okvir možemo koristiti za učvršćivanje primjera protiv napada na daljinsko izvršavanje koda. Sigurnosni okvir omogućuje nam konfiguriranje XStreama s bijelim popisom vrsta koje je dopušteno instancirati.

Ovaj će popis sadržavati samo osnovne tipove i naš Osoba razred:

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

Osim toga, korisnici XStreama mogu razmotriti učvršćivanje svojih sustava pomoću agenta Runtime Application Self-Protection (RASP). RASP agenti koriste bytecode instrumentaciju u vrijeme izvođenja za automatsko otkrivanje i blokiranje napada. Ova je tehnika manje podložna pogreškama nego ručna izrada bijele liste vrsta.

6. Zaključak

U ovom smo članku naučili kako izvršiti napad na daljinsko izvršavanje koda na aplikaciji koja koristi XStream za čitanje XML-a. Budući da napadi poput ovog postoje, XStream mora biti ojačan kada se koristi za čitanje XML-a iz nepouzdanih izvora.

Eksploatacija postoji jer XStream koristi refleksiju za instanciranje Java klasa koje je identificirao XML napadača.

Kao i uvijek, kod za primjere možete pronaći na GitHubu.