De Nederlandse hackers Daan Keuper en Thijs Alkemade wonnen in april van dit jaar de hackwedstrijd Pwn2Own nadat ze een kwetsbaarheid hadden gevonden in Zoom. De hackers, die werken voor securitybedrijf Computest, bouwden een exploit waarmee ze van een afstand code konden uitvoeren op het Windows-systeem van een Zoom-gebruiker. Omdat het lek nog niet was gedicht, mocht het duo geen details vrijgeven over de kwetsbaarheid. Inmiddels mogen ze dat wel. De hackers hebben een technische analyse online gezet waarin ze hun exploit uitleggen. Tweakers sprak met hen over Pwn2Own en hoe je een effectieve exploit bouwt.
Vanaf nul beginnen
Pwn2Own is een wedstrijd waarbij onderzoekers veel soorten software kunnen hacken. Waarom kozen jullie specifiek voor Zoom?
Daan Keuper: "De wedstrijd vindt jaarlijks plaats. Ieder jaar doen ook bijvoorbeeld grote browsermakers mee, dus je kunt Chrome of Edge hacken. Het probleem is dat je weet dat die ieder jaar opnieuw mee gaan doen. Als onderzoeker kun je dus al lang van tevoren beginnen met het zoeken naar kwetsbaarheden. Bovendien doet Google zelf al heel veel aan beveiliging en er zijn veel externe onderzoekers bezig met Chrome. Zoom is echter een relatief nieuwe app. Daarom begint iedere onderzoeker eigenlijk vanaf nul. Dat maakt de wedstrijd eerlijker."
Thijs Alkemade: "Apps hebben ook allemaal hun eigen framework met hun eigen kwetsbaarheden. We zagen dat je naast Zoom bijvoorbeeld ook aan de slag kon met Microsoft Teams. Daar hebben we even over getwijfeld. Teams maakt gebruik van Electron. Dat betekent dat er dezelfde soorten kwetsbaarheden in kunnen zitten als in een web-app, dat zijn er al veel. Zoom is daarentegen gebouwd op C++. Daarin vind je sneller een buffer overflow en we vonden het persoonlijk toch wat leuker om daar onderzoek naar te doen."
Waar kijk je het eerst naar als je een kwetsbaarheid wilt vinden?
TA: "Je bekijkt eerst wat voor data de software verzendt. Wat gebeurt er op het netwerk als gebruiker A iets naar gebruiker B stuurt en wat gebeurt er als dat een plaatje is of juist een chatbericht? Er zijn allerlei tools voor en die gebruiken we om dat verkeer te analyseren."
DK: "Welke informatie je onderschept, hangt af van welk protocol er wordt gebruikt. We zagen dat de meeste configuratieberichten van Zoom over een gewone HTTP-verbinding liepen, maar chatberichten gingen via XMPP. Wat videogesprekken betreft, daar konden we geen wijs uit. We denken dat ze een of ander eigen formaat hebben ontwikkeld. Daar hebben we niet heel lang naar gekeken."
Zijn er doorgaans niet meer bugs te vinden in zelfgeschreven, ingewikkelde code van een bedrijf?
DK: "Dat denk ik wel. Een video decoderen is vaak erg foutgevoelig, dus daar zitten ongetwijfeld kwetsbaarheden in, maar we vonden eerder een andere kwetsbaarheid in een andere component waar we naar konden kijken."
TA: "Het is ook makkelijker om onderzoek te doen naar de chatfunctionaliteit. Als je een videobelverbinding wilt onderzoeken, moet je eerst veel meer stappen uitvoeren voordat je snapt hoe het werkt. Dat is vrij moeilijk en kost veel tijd."
Buffer overflow
De kwetsbaarheid zat in de manier waarop Zoom berichten naar het geheugen schrijft
Welke kwetsbaarheid kwamen jullie uiteindelijk wel tegen?
DK: "Die zit in de manier waarop Zoom XMPP-berichten afhandelt. Daar gebruikt Zoom de Gloox-library voor. Je kunt elkaar op Zoom versleutelde berichten versturen. In het afhandelen van zo'n bericht wijst het programma een buffer van 1024 bytes toe en als je de applicatie normaal gebruikt, hoort dat element nooit méér ruimte te bevatten. Wij zijn natuurlijk geen gewone gebruikers, dus we hebben geprobeerd om manieren te vinden om meer data te versturen. Zoom vergeet te controleren of de data die binnenkomt, precies binnen die 1024 bytes past. Daardoor kun je een buffer overflow veroorzaken. De OpenSSL-library die Zoom gebruikt voor versleuteling doet wat hij moet doen en schrijft versleutelde data naar de buffer weg, maar in ons geval, als we een datapakketje van meer dan 1024 bytes hebben, past dat niet. Dan veroorzaak je een buffer overflow of een memory corruption."
Een kwetsbaarheid vinden is één ding, maar die uitbuiten is een volgende stap. Hoe schrijf je daar een exploit voor?
DK: "Dat doen we in een paar stappen. De eerste is dat we achter het buffergeheugen moeten kunnen schrijven, dus dat we over iets heen schrijven dat ons een bepaalde mate van controle over het geheugen geeft. In het begin heb je die controle niet. Dan schrijf je gewoon over data heen die toevallig achter de buffer ligt. Wat er dan gebeurt, is afhankelijk van datgene dat daar ligt, achter die buffer. Als dat een plaatje is, gebeurt er misschien niet zo heel veel, maar in veel andere gevallen is er een kans dat de applicatie crasht. De eerste stap is dus zorgen dat je een aanname kunt doen over het geheugen waar je overheen schrijft. We moeten precies het juiste schrijven, anders crasht de applicatie. Pas als je dat consistent kunt maken, kunnen we ervoor zorgen dat onze code ook echt wordt uitgevoerd en de software blijft werken."
"Daar gaat uiteindelijk de meeste tijd in zitten. Het vinden van die kwetsbaarheid heeft ons ongeveer anderhalve week gekost. Het schrijven van de exploit zelf, iets bouwen dat we ook daadwerkelijk kunnen gebruiken om een pc over te nemen, kostte echter nog eens anderhalve maand."
Trial and error
Je hebt het over 'de juiste code die je moet schrijven' richting de buffer. Hoe kom je erachter wat voor code dat is? Is dat een trial-and-errorproces of kun je zoiets automatiseren?
DK: "De belangrijkste stap is dat we heel precies aannames moeten kunnen doen over hoe het geheugen er aan de kant van het slachtoffer uit ziet. Zeker als de applicatie al een tijdje draait, is dat geheugen best een rommeltje. Dat proces van zoeken naar aannames noemen we heap grooming. Dat doen we door heel veel berichtjes te sturen naar de client, waardoor we steeds meer van het geheugen volschrijven. Vervolgens gaan we heel precies die berichtjes weggooien en gaatjes prikken in het geheugen. Als je dat nauwkeurig doet, kun je specifiek bepalen waar de gaatjes zitten en kun je die aannames doen."
"Dat is het saaiste deel. Je moet eindeloos dingetjes proberen en observeren wat er gebeurt. Het is heel veel trial and error. Het is bovendien moeilijk te automatiseren, maar uiteindelijk is het wel de betrouwbaarste manier van werken. Tegelijk is dat het belangrijkste deel. Hoe meer tijd je eraan besteedt, hoe betrouwbaarder je exploit wordt."
Moet je de beveiliging van het besturingssysteem ook nog omzeilen?
DK: "Er zijn twee beschermlagen in het OS waar je omheen moet. De eerste is een functie waarbij een programma geen nieuwe code kan inladen als die eenmaal draait. Onze exploit werkt voor Windows, maar je zou dit ook voor macOS kunnen uitvoeren. In Windows heet die functie DEP, of Data Execution Prevention. We kunnen dus niet zomaar een chatbericht sturen met daarin wat code en vervolgens tegen de applicatie zeggen dat die de code moet uitvoeren. Dat betekent dat we stukjes code die al in het programma aanwezig zijn, aan elkaar moeten rijgen. We moeten dus weten waar de code van Zoom in het geheugen staat."
"Het tweede probleem is address space layout randomization of aslr. Dat zet een programma bij het starten op een willekeurige plek in het geheugen neer. Dus we moeten eerst heel expliciet weten waar Windows Zoom in het geheugen zet."
TA: "We hebben onze bufferoverflowkwetsbaarheid uiteindelijk zo weten in te zetten dat we hiermee een geheugenadres van het slachtoffer konden laten uitlekken. Dit noem je een information leak. Dat is uiteindelijk nodig om beschermingsmethodes zoals DEP en aslr te kunnen omzeilen."
Return oriented programming
Hoe voer je die exploit vervolgens concreet uit?
DK: "Daarvoor moeten wij als aanvallers kunnen bepalen welke code Zoom gaat uitvoeren. Normaal volgt Zoom zijn eigen programmapad, maar daar willen wij invloed op kunnen uitoefenen. We moeten dat zien te kapen. We kwamen erachter dat Zoom een audiobestand afspeelt als je iemand belt. Dat is zo'n geluidje van een telefoon die overgaat. Dat gebeurt via een adres waarin staat hoe dat bestand moet worden afgespeeld. Dat adres verwijst naar het stukje code om die ringtone af te spelen. We hebben dat adres kunnen aanpassen, zodat Zoom vanaf een ander adres code kon uitvoeren."
"Door dat te manipuleren gaat Zoom het adres in het geheugen zetten op precies de plek waar wij weten dat het gebeurt. De eerstvolgende keer dat de ringtone dan afgaat, kunnen wij bepalen vanaf waar Zoom de code uitvoert. Door kleine stukjes code aan elkaar te rijgen, een proces dat return oriented programming wordt genoemd, kunnen we Zoom uiteindelijk een commandprompt laten starten met een internetverbinding naar ons."
Pwn2own vond al in april plaats. Is deze kwetsbaarheid inmiddels gerepareerd?
DK: "Gelijk nadat we de exploit presenteerden op Pwn2Own, hebben we meer uitleg gegeven aan Zoom. Zo kan Zoom kijken of deze kwetsbaarheid niet al bekend was in zijn eigen bugtracker. Dan zou je de wedstrijd verliezen. Al vrij snel na de competitie heeft Zoom een mitigatie doorgevoerd aan de serverkant. Dat was mogelijk doordat berichten altijd via de servers van Zoom gingen. Dat, plus het feit dat het lek niet actief werd misbruikt, maakte het risico voor eindgebruikers laag."