Tutorial voor Fuzz-testen (Fuzzing).

⚡ Slimme samenvatting

Bij fuzz-testen worden ongeldige, onverwachte of willekeurige gegevens aan een programma toegevoerd, waarna wordt gezocht naar crashes, vastlopers en geheugenproblemen. Hierdoor worden beveiligingslekken blootgelegd die bij functionele tests met scripts vrijwel nooit aan het licht komen.

  • 🔘 Oorsprong: Barton Miller bedacht de term aan de Universiteit van Wisconsin-Madison, en de eerste fuzz-tests in 1989 lieten ongeveer een derde van de geteste UNIX-hulpprogramma's crashen.
  • ☑️ Zesstappenlus: Identificeer het doel, identificeer de invoer, genereer gefuzzde gegevens, voer de code uit, monitor het gedrag en registreer vervolgens elk defect dat zich voordoet.
  • Drie generatiestrategieën: Mutatiefuzzers vervormen geldige voorbeelden, generatiefuzzers bouwen invoer op basis van een model en protocolfuzzers werken vanuit een specificatie.
  • 🧪 De feedback op de berichtgeving heeft het vakgebied veranderd: Moderne engines bewaren alle invoer die nieuwe code bereikt, waardoor veel dieperliggende bugs worden opgespoord dan met puur willekeurige data.
  • De gereedschappen zijn geëvolueerd: Peach Fuzzer en WebScarab zijn gearchiveerd, terwijl AFL++, libFuzzer, OSS-Fuzz, boofuzz ​​en OWASP ZAP de opties zijn die nog worden onderhouden.
  • ⚙️ Bekende limieten: Fuzzing spoort crashes op, geen logische fouten, en vormt daarom een ​​aanvulling op code review en penetratietesten, in plaats van deze te vervangen.

Tutorial voor Fuzz-testen (Fuzzing).

Wat is Fuzz-testen?

Fuzz-testen of fuzzing Fuzz-testen is een softwaretesttechniek waarbij ongeldige of willekeurige data, ook wel fuzz genoemd, in een softwaresysteem wordt ingevoerd om programmeerfouten en beveiligingslekken te ontdekken. Het doel van fuzz-testen is het invoegen van data met behulp van geautomatiseerde of semi-geautomatiseerde technieken en het testen van het systeem op verschillende uitzonderingen, zoals systeemcrashes of het falen van ingebouwde code.

Fuzz-testen werden oorspronkelijk ontwikkeld door Barton Miller aan de Universiteit van Wisconsin-Madison. Hij bedacht de term nadat ruis op een modemverbinding de programma's die hij gebruikte deed vastlopen. Zijn studenten voerden in 1989 de eerste fuzzers uit en ontdekten dat ongeveer een derde van de UNIX-hulpprogramma's die ze testten, vastliepen of crashten. Fuzz-testen is een software testen techniek, en het is een soort Beveiligingstests.

Het onderstaande diagram toont de basis van de fuzzing-loop, waarbij gegenereerde data naar de te testen applicatie wordt gestuurd en de reactie wordt geobserveerd.

Fuzz-testworkflow: een fuzzer genereert onjuiste invoer en voert deze in de te testen applicatie.

Waarom Fuzz-testen doen?

Fuzzing verdient een plek in een testplan omdat het input verkent waar niemand aan gedacht heeft om een ​​testcase voor te schrijven. De belangrijkste redenen waarom teams het toepassen, worden hieronder opgesomd.

  • Fuzz-testen sporen doorgaans de ernstigste beveiligingsfouten en -defecten op, omdat een crash direct bewijs is van een onjuist verwerkt invoerpad.
  • Fuzz-testen geven een effectiever resultaat wanneer ze worden gebruikt in combinatie met Zwart Box Testen, bètatests en andere foutopsporingsmethoden.
  • Fuzz-testen worden gebruikt om de kwetsbaarheid van software te controleren en zijn een zeer kosteneffectieve testtechniek omdat de invoergegevens worden gegenereerd in plaats van handmatig ingevoerd.
  • Fuzz-testen is een van de black-box-testtechnieken. Het is ook een van de meest gebruikte methoden door hackers om kwetsbaarheden in een systeem te vinden, dus door het eerst uit te voeren, wordt de gemakkelijkste toegangsweg voor een aanvaller afgesloten.

Soorten fuzz-testen

Fuzzers worden doorgaans ingedeeld op basis van hun kennis van het programma dat ze aanvallen. Hoe meer de fuzzer weet, hoe dieper hij in de code kan doordringen.

Type Wat de fuzzer weet Typisch gebruik
Zwarte doos wazig Niets over de interne werking; het ziet alleen in- en uitgangen. Snelle testruns op een binair bestand of een live endpoint.
Witte doos wazig De volledige broncode, vaak gecombineerd met symbolische uitvoering om moeilijk bereikbare vertakkingen op te lossen. Grondige analyse van een component waarvan de broncode beschikbaar is.
Grijze doos pluizen Geen broncodebeoordeling, maar wel feedback tijdens de uitvoering, zoals welke codevertakkingen een invoer heeft bereikt. De standaard voor moderne engines zoals AFL++ en libFuzzer.

Een tweede, oudere splitsing scheidt stomme fuzzing vanaf slimme fuzzingEen simpele fuzzer draait bits om zonder enig idee te hebben van het invoerformaat, waardoor de meeste gegevens door de eerste parser die hij tegenkomt worden afgewezen. Een slimme fuzzer begrijpt checksums, lengtevelden en berichtstructuur, waardoor de invoer de validatie doorstaat en de onderliggende logica bereikt. Dekkinggestuurde fuzzing Dit is de verfijning van de 'grey box' die fuzzing mainstream heeft gemaakt: de engine instrumenteert de binaire code, bewaart elke invoer die een nieuwe vertakking bereikt en muteert de overgebleven invoer, zodat het corpus gestaag evolueert naar onverkende code in plaats van opnieuw te beginnen met willekeurige ruis.

Fuzz-testen uitvoeren

De stappen voor fuzz-testen omvatten de basis teststappen:

Stap 1) Identificeer het doelsysteem — Kies het binaire bestand, de bibliotheek, de service of het protocol-eindpunt dat aangevallen zal worden, en bevestig dat je bevoegd bent om dit te testen.

Stap 2) Identificeer inputs — Geef een lijst van alle toegangspunten waaruit het doel leest: bestanden, opdrachtregelargumenten, omgevingsvariabelen, netwerkpakketten, formuliervelden en API-payloads.

Stap 3) Genereer Fuzzed-gegevens — Het produceren van onjuiste invoer door geldige voorbeelden te muteren, door ze te genereren op basis van een model van het formaat, of door een combinatie van beide.

Stap 4) Voer de test uit met behulp van vage gegevens. — Voer het doelprogramma uit met de gegenereerde invoer, idealiter in een lus die het proces na elke fout automatisch opnieuw start.

Stap 5) Controleer het systeemgedrag — Let op crashes, vastlopers, assertiefouten, buitensporig geheugengebruik en sanitizer-rapporten in plaats van alleen de afgedrukte uitvoer te controleren.

Stap 6) Registreer defecten — sla de exacte invoer op die elke fout veroorzaakte, reduceer deze tot het kleinst mogelijke reproduceerbare geval en voeg deze toe aan de stack. trace bijgevoegd.

Voorbeelden van Fuzzers

Fuzzers worden ook geclassificeerd op basis van de manier waarop ze hun input genereren, en de drie onderstaande benaderingen zijn de meest voorkomende.

  • Op mutaties gebaseerde Fuzzers Bestaande datamonsters aanpassen om nieuwe testdata te creëren. Dit is een zeer eenvoudige en rechtstreekse aanpak: het begint met geldige voorbeelden van een protocol en blijft elke byte of elk bestand bewerken.
  • Op generatie gebaseerde Fuzzers Ze definiëren nieuwe gegevens op basis van de invoer van het model. Ze beginnen met het genereren van invoer vanaf nul op basis van de specificatie.
  • Protocolgebaseerde fuzzers Het vereist gedetailleerde kennis van het te testen protocolformaat, en dat begrip komt voort uit de specificatie. Het houdt in dat een array van de specificatie in de tool wordt geschreven, waarna een modelgebaseerde testgeneratietechniek wordt gebruikt om de specificatie te doorlopen en onregelmatigheden in de data-inhoud, volgorde, enzovoort toe te voegen. Dit wordt ook wel syntaxtesten, grammaticatesten of robuustheidstesten genoemd. Een fuzzer kan testgevallen genereren op basis van een bestaand testgeval, of het kan geldige of ongeldige invoer gebruiken.

Er zijn twee beperkingen aan protocolgebaseerd fuzzen:

  1. Het testen kan pas doorgaan als de specificatie volwassen is.
  2. Veel nuttige protocollen zijn een uitbreiding van gepubliceerde protocollen. Als fuzz-tests gebaseerd zijn op gepubliceerde specificaties, Test dekking voor nieuwe protocollen zal beperkt zijn.

De eenvoudigste vorm van fuzzing is het versturen van willekeurige invoer naar de software, hetzij als protocolpakketten, hetzij als een gebeurtenis. Deze techniek, waarbij willekeurige invoer wordt doorgegeven, is zeer krachtig voor het vinden van bugs in veel applicaties en services. Er zijn ook andere technieken beschikbaar, die zeer eenvoudig te implementeren zijn. Om deze technieken te implementeren, hoeven we alleen de bestaande invoer te wijzigen, en we kunnen een invoer wijzigen door simpelweg de bits ervan te verwisselen.

Soorten bugs gedetecteerd door Fuzz Testing

Omdat fuzzing een run beoordeelt op basis van hoe het programma zich gedraagt ​​in plaats van op basis van een verwachte waarde, vallen de defecten die het aan het licht brengt in drie categorieën uiteen.

  • Assertiefouten en geheugenlekken: Deze methodologie wordt veel gebruikt voor grote applicaties waar de bugs de geheugenveiligheid aantasten, wat een ernstige kwetsbaarheid is. Buffer Overflows, use-after-free en out-of-bounds reads komen hier allemaal voor.
  • Ongeldige invoer: Bij fuzz-testen worden fuzzers gebruikt om ongeldige invoer te genereren, die vervolgens wordt gebruikt om foutafhandelingsroutines te testen. Dit is belangrijk voor software die de invoer niet zelf beheert. Eenvoudig fuzzen kan worden gezien als een manier om te automatiseren. negatief testen.
  • Correctheidsfouten: Fuzzing kan ook worden gebruikt om bepaalde soorten 'correctheidsfouten' op te sporen, zoals een beschadigde database of slechte zoekresultaten. Differentiële fuzzing, waarbij dezelfde invoer aan twee implementaties wordt gegeven en de antwoorden worden vergeleken, is de gebruikelijke manier om deze fouten te detecteren.

Fuzz-testhulpmiddelen

Tools die gebruikt worden in webbeveiliging kunnen ook op grote schaal gebruikt worden bij fuzz-testen, zoals bijvoorbeeld: Burp Suite en Peach Fuzzer. Verschillende van de klassieke namen hieronder zijn inmiddels gearchiveerd, hun huidige status staat daarom bij elke vermelding vermeld.

  • Perzik FuzzerPeach Fuzzer biedt een robuustere beveiligingsdekking dan een scanner. Andere testtools kunnen alleen zoeken naar bekende bedreigingen, terwijl Peach Fuzzer gebruikers in staat stelt zowel bekende als onbekende bedreigingen te vinden. Peach Tech is overgenomen door GitLab en Community Edition v3 wordt niet langer onderhouden; de onderhouden opvolger is de GitLab Protocol Fuzzer Community Edition.
  • Spike-proxySPIKE Proxy is een professionele tool die zoekt naar kwetsbaarheden op applicatieniveau in webapplicaties. SPIKE Proxy behandelt de basisfunctionaliteiten, zoals: SQL Injectie en cross-site scripting, op een volledig open platform. Python infrastructuur, en het was beschikbaar voor Linux en WindowsHet is al vele jaren niet meer onderhouden en is hier opgenomen voor de historische context.
  • WebScarabWebScarab is geschreven in Java Het framework is daarom overdraagbaar naar vele platformen. WebScarab communiceert via HTTP- en HTTPS-protocollen en werkt als een onderscheppende proxy: het stelt de operator in staat om verzoeken van de browser te bekijken en te wijzigen voordat de server ze ontvangt, en om antwoorden van de server te bekijken en bij te werken voordat de browser ze ontvangt. Elk beveiligingslek dat WebScarab vindt, wordt toegevoegd aan de lijst met gemelde problemen. De repository is in april 2024 gearchiveerd en is nu alleen-lezen.
  • OWASP WSFuzzerWSFuzzer is een programma met een GPL-licentie, geschreven in Python die zich richtte op webdiensten, en in de laatste versie HTTP-gebaseerd was. SOAP-diensten waren het belangrijkste doelwit. Het werd als onderdeel van WebScarab uitgebracht en samen daarmee uitgefaseerd; OWASP ZAP en de Fuzzer-add-on zijn de aanbevolen vervanging.
  • Behoud van alternatieven: AFL++ en libFuzzer zijn de standaard, op dekking gebaseerde engines voor native code. OSS-Fuzz voert ze continu en gratis uit voor open-sourceprojecten, en boofuzz behandelt netwerkprotocol-fuzzing in PythonEen uitgebreidere lijst is te vinden in de gids voor beveiligingstesttools.

Best practices voor fuzz-testen

Een fuzzer die op een doelwit is gericht en verder met rust wordt gelaten, vindt zelden veel. De onderstaande werkwijzen onderscheiden een campagne die daadwerkelijk defecten oplevert van een campagne die alleen maar CPU-tijd verspilt.

  • Begin met een goede basisdataset. Verzamel echte, geldige invoer die de applicatie al accepteert. Het wijzigen van een echt bestand bereikt de parseercode veel sneller dan het wijzigen van willekeurige bytes.
  • Schrijf een klein, snel harnas. Het startpunt moet per uitvoeringssessie slechts één taak uitvoeren, netwerkoproepen en schrijfbewerkingen naar de schijf vermijden en snel terugkeren, omdat de doorvoer wordt gemeten in uitvoeringen per seconde.
  • Zet de desinfectieapparaten aan. Stille geheugenbeschadiging leidt vaak niet tot een crash. AddressSanitizer en UndefinedBehaviorSanitizer zetten dit om in een onmiddellijke, diagnosticeerbare fout.
  • Ren lang en ren onafgebroken. Een test van één of twee uur spoort oppervlakkige fouten op; dieperliggende problemen vereisen meestal vele uren, daarom hoort fuzzing thuis in een nachtelijke CI-taak in plaats van een handmatige sessie.
  • Minimaliseer en verwijder dubbele meldingen van elk crashgeval. Verklein de foutieve invoer tot de kleinste vorm en groepeer crashes per stack. trace, anders komt één bug binnen als honderden meldingen.
  • Houd een regressiecorpus bij. Voeg elke reproduceerbare invoer toe aan een permanente set die bij elke build wordt uitgevoerd, zodat een opgelost defect niet ongemerkt kan terugkeren.
  • Bepaal het doel op legale wijze. Het uitvoeren van fuzzing op een live dienst van een derde partij zonder schriftelijke toestemming is niet te onderscheiden van een aanval.

Voordelen van Fuzz-testen

Mits toegepast met realistische verwachtingen, voegt fuzzing waarde toe die andere technieken moeilijk kunnen evenaren.

  • Fuzz-testen verbeteren de beveiligingstesten van software.
  • De fouten die tijdens fuzzing worden gevonden, zijn soms ernstig en vaak dezelfde als die door aanvallers worden gebruikt, waaronder crashes, geheugenlekken en onafgehandelde uitzonderingen.
  • Als testers door tijdgebrek en beperkte middelen bepaalde bugs niet opmerken, worden die bugs ook gevonden tijdens fuzz-testen.
  • De input wordt door een machine gegenereerd, waardoor de dekking 's nachts blijft groeien zonder extra handmatige inspanning.

Nadelen van Fuzz-testen

Dezelfde eigenschappen die fuzzing goedkoop maken, beperken ook wat het kan bewijzen.

  • Fuzz-testen alleen geven geen volledig beeld van een algehele beveiligingsdreiging of een reeks bugs.
  • Fuzz-testen zijn minder effectief in het opsporen van beveiligingsrisico's die geen programmacrashes veroorzaken, zoals sommige virussen, wormen en Trojaanse paarden.
  • Fuzz-testen kunnen alleen relatief eenvoudige fouten of bedreigingen detecteren en kunnen geen inzicht geven in de bedrijfslogica.
  • Om effectief te presteren, is aanzienlijke machinetijd nodig.
  • Het vaststellen van een randvoorwaarde met willekeurige invoer is zeer problematisch, hoewel testers dit tegenwoordig grotendeels oplossen met deterministische algoritmen die worden aangestuurd door gebruikersinvoer.

Fuzz-testen versus penetratietesten

Beide activiteiten zijn gericht op het opsporen van beveiligingslekken, maar ze beantwoorden verschillende vragen en zijn zelden uitwisselbaar.

criteria Fuzz-testen Penetratietests
Gedreven door Een geautomatiseerde engine die onjuiste invoer genereert Een ervaren tester die over het systeem redeneert.
Zoekt naar Storingen, vastlopers en geheugenbeveiligingsfouten Kwetsbare punten, waaronder logische en configuratiefouten.
Diepte Zeer breed scala aan invoergegevens, oppervlakkige redenering. Beperkte dekking, diepgaande argumentatie
uitgang Invoer en stack reproduceren traces Een rapport met bevindingen, exploitatiemogelijkheden en risicobeoordelingen.
Beste moment Continu, in de build-pipeline Periodiek, tegen een releasekandidaat

In de praktijk versterken de twee elkaar: fuzzing verwijdert de goedkope, automatiseerbare fouten, zodat de beperkte tijd van een tester kan worden besteed aan de fouten die alleen een mens kan ontdekken.

Veelgestelde vragen

Een seed corpus is de beginset van geldige invoer die de fuzzer muteert. Kleine, gevarieerde, echte bestanden werken het beste, omdat elk bestand de parser al doorstaat en de engine zijn budget kan besteden aan diepere code in plaats van aan de eerste validatiecontrole.

Een fuzz harness is de kleine functie die één buffer met gefuzzde bytes aan de te testen code doorgeeft. Het moet globale variabelen, schrijfbewerkingen naar bestanden en netwerkoproepen vermijden, zodat de engine het duizenden keren per seconde kan uitvoeren.

Een uur of twee legt oppervlakkige fouten bloot. Serieuze campagnes duren vele uren of dagen, omdat nieuwe dekking in golven binnenkomt. Een plateau in de dekkingscurve, en niet een klokstand, is het eerlijke signaal dat een campagne niet langer vruchten afwerpt.

AddressSanitizer detecteert bufferoverloop en gebruik na vrijgave, UndefinedBehaviorSanitizer detecteert misbruik van gehele getallen en pointers, en MemorySanitizer detecteert leesbewerkingen van niet-geïnitialiseerd geheugen. Zonder deze functies blijven veel corrupties onopgemerkt en rapporteert de fuzzer helemaal geen fouten.

Reproduceer het probleem, minimaliseer de invoer tot het kleinste foutgeval en groepeer het met crashes die dezelfde stack delen. trace, dien vervolgens één ticket in via de gebruikelijke procedure. defectbeheerproces en voeg de invoer toe aan een regressiecorpus.

Ze hebben wel willekeurigheid gemeen, maar geen opzet. Apenproeven Bij het uitvoeren van een test worden willekeurige gebruikersacties op een draaiende interface losgelaten, terwijl fuzzing zich richt op een specifieke invoerparser en de codedekking meet, zodat het zichzelf kan bijsturen naar code die de eerdere invoer nooit heeft bereikt.

Taalmodellen worden gebruikt om testomgevingen te ontwerpen voor API's zonder fuzzing, om startinputs te genereren voor exotische formaten en om crashrapporten te clusteren en samen te vatten. De engine levert nog steeds de feedback over de testdekking; het model neemt voornamelijk het handmatige instelwerk over.

GitHub-copiloot Je kunt een libFuzzer-ingangspunt, een buildbestand en een seedgenerator ontwerpen op basis van een bestaande API-signatuur. RevBekijk het resultaat zorgvuldig, want een kabelboom die fouten stilletjes negeert, zal geen crashes melden.

Vat dit bericht samen met: