Tutorial för fuzztestning (fuzzing).

⚡ Smart sammanfattning

Fuzztestning matar in ogiltig, oväntad eller slumpmässig data i ett program och letar efter krascher, låsningar och minnesfel, vilket avslöjar säkerhetsfel som skriptade funktionella tester nästan aldrig når på egen hand.

  • 🔘 Ursprung: Barton Miller myntade termen vid University of Wisconsin – Madison, och de första fuzz-körningarna 1989 kraschade ungefär en tredjedel av de testade UNIX-verktygen.
  • ☑️ Sexstegsslinga: Identifiera målet, identifiera indata, generera fuzzed data, kör, övervaka beteende och logga sedan varje defekt som uppstår.
  • Tre generationers strategier: Mutationsfuzzers manipulerar giltiga samplingar, generationsfuzzers bygger indata från en modell och protokollfuzzers arbetar utifrån en specifikation.
  • 🧪 Täckningsfeedback ändrade fältet: Moderna motorer behåller all inmatning som når ny kod, som hittar betydligt djupare buggar än rent slumpmässig data.
  • 🛠️ Verktygsframställningen har gått vidare: Peach Fuzzer och WebScarab arkiveras, medan AFL++, libFuzzer, OSS-Fuzz, boofuzz ​​och OWASP ZAP är de alternativ som underhålls.
  • ⚙️ Kända gränser: Fuzzing hittar krascher, inte logiska brister, så det kompletterar snarare än ersätter kodgranskning och penetrationstestning.

Tutorial för fuzztestning (fuzzing).

Vad är Fuzz-testning?

Fuzztestning eller Fuzzing är en mjukvarutestningsteknik där man lägger in ogiltig eller slumpmässig data, kallad FUZZ, i ett mjukvarusystem för att upptäcka kodningsfel och säkerhetshål. Syftet med fuzztestning är att infoga data med hjälp av automatiserade eller halvautomatiserade tekniker och testa systemet för olika undantag, som systemkrascher eller fel i inbyggd kod.

Fuzztestning utvecklades ursprungligen av Barton Miller vid University of Wisconsin–Madison, som myntade termen efter att linjebrus på en modemlänk kraschade de program han använde. Hans studenter körde de första fuzzrarna 1989 och fann att ungefär en tredjedel av de UNIX-verktyg de riktade in sig på kraschade eller hängde sig. Fuzztestning är en mjukvarutestning teknik, och det är en typ av Säkerhetstestning.

Diagrammet nedan visar den grundläggande fuzzing-slingan, där genererad data skickas till den applikation som testas och svaret observeras.

Fuzztestningsarbetsflöde: en fuzzer genererar felaktigt formaterad indata och matar den till applikationen som testas

Varför göra Fuzz Testing?

Fuzzing förtjänar sin plats i en testplan eftersom det utforskar indata som ingen tänkte på att skriva ett testfall för. De främsta anledningarna till att team använder det listas nedan.

  • Fuzz-testning hittar vanligtvis de allvarligaste säkerhetsfelen och defekterna, eftersom en krasch är ett direkt bevis på en ohanterad inmatningsväg.
  • Fuzztestning ger ett mer effektivt resultat när det används med Svart Box Testning, betatestning och andra felsökningsmetoder.
  • Fuzztestning används för att kontrollera programvaras sårbarhet, och det är en mycket kostnadseffektiv testteknik eftersom indata genereras snarare än skrivs för hand.
  • Fuzz-testning är en av de så kallade black box-testteknikerna. Fuzzing är också en av de vanligaste metoderna som hackare använder för att hitta en sårbarhet i ett system, så att köra den först tar bort en angripares enklaste väg in.

Typer av fuzztestning

Fuzzers grupperas vanligtvis efter hur mycket de vet om programmet de attackerar. Ju mer fuzzern vet, desto djupare in i koden kan den pusha.

Typ Vad fuzzern vet Typisk användning
Svart låda-fuzzing Inget om det interna; den ser bara ingångar och utgångar. Quick smoke körs mot en binärfil eller en live-slutpunkt.
Vit låda suddig Fullständig källkod, ofta kombinerad med symbolisk exekvering för att lösa svårnådda grenar. Djupgående analys av en komponent vars källkod är tillgänglig.
Grå lådans suddiga Ingen källgranskning, utan feedback under körning, till exempel vilka kodgrenar en inmatning nådde. Standardinställningen för moderna motorer som AFL++ och libFuzzer.

En andra, äldre splittring separerar dum fuzzling från smart fuzzingEn dum fuzzer vänder bitar utan någon aning om inmatningsformatet, så det mesta av dess data avvisas av den första parsern den möter. En smart fuzzer förstår kontrollsummor, längdfält och meddelandestruktur, så dess indata överlever validering och når logiken under. Täckningsstyrd fuzzing är den grå box-förfining som gjorde fuzzing mainstream: motorn instrumenterar binärkod, behåller all inmatning som når en ny gren och muterar de överlevande, så att korpusen stadigt utvecklas mot outforskad kod istället för att starta om från slumpmässigt brus.

Hur man gör Fuzz Testing

Stegen för fuzztestning inkluderar de grundläggande teststegen:

Steg 1) Identifiera målsystemet — välj den binärfil, biblioteksfil, tjänstfil eller protokollfil som ska attackeras och bekräfta att du har tillstånd att testa den.

Steg 2) Identifiera ingångar — lista varje ingångspunkt som målet läser från: filer, kommandoradsargument, miljövariabler, nätverkspaket, formulärfält och API-nyttolaster.

Steg 3) Generera Fuzzed data — producera felaktigt utformade indata genom att mutera giltiga exempel, genom att generera dem från en modell av formatet eller genom att kombinera båda.

Steg 4) Kör testet med hjälp av fuzzy data — kör målet mot de genererade indata, helst i en loop som startar om processen automatiskt efter varje fel.

Steg 5) Övervaka systemets beteende — leta efter krascher, hängningar, felaktiga assertioner, skenande minnesanvändning och saneringsrapporter snarare än att bara kontrollera den utskrivna utskriften.

Steg 6) Logga defekter — spara exakt den indata som utlöste varje fel, krymp den till det minsta reproducerande fallet och arkivera den med stacken trace bifogad.

Exempel på Fuzzers

Fuzzers klassificeras också efter hur de bygger sin input, och de tre metoderna nedan är de du kommer att stöta på oftast.

  • Mutationsbaserade fuzzers ändra befintliga dataprover för att skapa nya testdata. Detta är en mycket enkel och okomplicerad metod: den börjar med giltiga exempel av ett protokoll och fortsätter att manipulera varje byte eller fil.
  • Generationsbaserade fuzzers definiera nya data baserat på modellens indata. De börjar generera indata från grunden baserat på specifikationen.
  • Protokollbaserade fuzzers bero på detaljerad kunskap om protokollformatet som testas, och den förståelsen kommer från specifikationen. Det innebär att man skriver en array av specifikationen i verktyget, och sedan använder en modellbaserad testgenereringsteknik för att gå igenom specifikationen och lägga till oregelbundenheter i datainnehållet, sekvensen och så vidare. Detta kallas även syntaxtestning, grammatiktestning eller robusthetstestning. En fuzzer kan generera testfall från ett befintligt testfall, eller så kan den använda giltiga eller ogiltiga indata.

Det finns två begränsningar för protokollbaserad fuzzing:

  1. Testning kan inte fortsätta förrän specifikationen är mogen.
  2. Många användbara protokoll är en förlängning av publicerade protokoll. Om fuzz-testning baseras på publicerade specifikationer, Testtäckning för nya protokoll kommer att begränsas.

Den enklaste formen av fuzzing-teknik är att skicka slumpmässig inmatning till programvaran antingen som protokollpaket eller som en händelse. Denna teknik för att skicka slumpmässig inmatning är mycket kraftfull för att hitta buggar i många applikationer och tjänster. Andra tekniker finns också tillgängliga, och de är mycket enkla att implementera. För att implementera dessa tekniker behöver vi bara ändra de befintliga inmatningarna, och vi kan ändra en inmatning genom att helt enkelt byta ut dess bitar.

Typer av buggar som upptäckts av Fuzz-testning

Eftersom fuzzing bedömer en körning utifrån hur programmet beter sig snarare än utifrån ett förväntat värde, grupperas de defekter som det uppdagar i tre familjer.

  • Påståendefel och minnesläckor: Denna metod används ofta för stora applikationer där buggarna påverkar minnessäkerheten, vilket är en allvarlig sårbarhet. Buffer överflöden, använd-efter-frigöring och läsningar utanför gränserna visas alla här.
  • Ogiltig inmatning: Vid fuzztestning används fuzzrar för att generera ogiltig indata som används för att testa felhanteringsrutiner, och detta är viktigt för programvara som inte kontrollerar dess indata. Enkel fuzzing kan ses som ett sätt att automatisera negativa tester.
  • Korrekthetsfel: Fuzzing kan också användas för att upptäcka vissa typer av "korrekthets"-buggar, såsom en korrupt databas eller dåliga sökresultat. Differentiell fuzzing, som matar samma indata till två implementeringar och jämför svaren, är det vanliga sättet att upptäcka dessa.

Fuzz-testverktyg

Verktyg som används inom webbsäkerhet kan användas i stor utsträckning i fuzztestning, till exempel Burp Suite och Peach Fuzzer. Flera av de klassiska namnen nedan är nu arkiverade, så deras nuvarande status anges bredvid varje inlägg.

  • Peach FuzzerPeach Fuzzer ger ett mer robust säkerhetstäckning än en skanner. Andra testverktyg kan bara söka efter kända hot, medan Peach Fuzzer gör det möjligt för användare att hitta kända och okända hot. Peach Tech förvärvades av GitLab, och Community Edition v3 underhålls inte längre; den underhållna efterföljaren är GitLab Protocol Fuzzer Community Edition.
  • Spike Proxy: ett professionellt verktyg som letar efter sårbarheter på applikationsnivå i webbapplikationer. SPIKE Proxy täcker grunderna, till exempel SQL Injektion och cross-site scripting, på en helt öppen Python infrastruktur, och den var tillgänglig för Linux och WindowsDen har inte underhållits på många år och är inkluderad här för historiskt sammanhang.
  • WebScarabWebScarab är skrivet i Java och är därför portabel till många plattformar. WebScarab-ramverket kommunicerar med hjälp av HTTP- och HTTPS-protokoll och fungerar som en avlyssnande proxy: det tillåter operatören att granska och ändra förfrågningar som skapas av webbläsaren innan servern tar emot dem, och att granska och uppdatera svar som genereras av servern innan webbläsaren tar emot dem. Alla kryphål som WebScarab hittar läggs till i listan över rapporterade problem. Arkivet arkiverades i april 2024 och är nu skrivskyddat.
  • OWASP WSFuzzerWSFuzzer är ett GPL-licensierat program skrivet i Python som riktade sig mot webbtjänster, och i sin senaste version HTTP-baserad SOAP-tjänster var huvudmålet. Den levererades som en del av WebScarab och togs bort tillsammans med den; OWASP ZAP och dess Fuzzer-tillägg är den rekommenderade ersättningen.
  • Bibehållna alternativ: AFL++ och libFuzzer är de vanliga täckningsstyrda motorerna för native kod, OSS-Fuzz kör dem kontinuerligt och kostnadsfritt för projekt med öppen källkod, och boofuzz täcker fuzzing av nätverksprotokoll PythonEn bredare lista finns samlad i guiden till verktyg för säkerhetstestning.

Bästa praxis för fuzztestning

En fuzzer som riktas mot ett mål och lämnas ifred hittar sällan mycket. Metoderna nedan skiljer en kampanj som producerar arkiverade defekter från en som bara förbrukar CPU-tid.

  • Börja med en bra frösamling. Samla in riktiga, giltiga indata som applikationen redan accepterar. Att mutera en äkta fil når parsningskod mycket snabbare än att mutera slumpmässiga byte.
  • Skriv en liten, snabb sele. Startpunkten bör göra en sak per körning, undvika nätverksanrop och diskskrivningar och återgå snabbt, eftersom dataflödet mäts i körningar per sekund.
  • Slå på handsprit. Tyst minneskorruption kraschar ofta inte. AddressSanitizer och UndefinedBehaviorSanitizer omvandlar det till ett omedelbart, diagnostiserbart fel.
  • Spring länge, och spring kontinuerligt. En eller två timmars körning fångar ytliga insekter; djupa stigar kräver vanligtvis många timmar, vilket är anledningen till att fuzzing hör hemma i ett nattligt CI-jobb snarare än en manuell session.
  • Minimera och avduplicera varje krasch. Krymp den felande inmatningen till dess minsta form och gruppera krascher efter stack trace, annars anländer en bugg som hundratals ärenden.
  • Behåll en regressionskorpus. Lägg till varje reproducerande indata till en permanent uppsättning som körs på varje build, så att en fixad defekt inte kan återkomma i tysthet.
  • Avgränsa målet juridiskt. Att fuzza en tredjepartstjänst i realtid utan skriftligt tillstånd går inte att skilja från en attack.

Fördelar med Fuzz Testing

Används med realistiska förväntningar, tillför fuzzing värde som andra tekniker har svårt att matcha.

  • Fuzz-testning förbättrar säkerhetstestning av programvara.
  • Buggar som hittas i fuzzing är ibland allvarliga och är ofta samma som används av angripare, inklusive krascher, minnesläckor och ohanterade undantag.
  • Om testarna inte upptäcker några buggar på grund av begränsad tid och resurser, hittas dessa buggar också i fuzz-testning.
  • Indata genereras av en maskin, så täckningen fortsätter att växa över natten utan extra manuell ansträngning.

Nackdelar med Fuzz Testing

Samma egenskaper som gör fuzzing billigt begränsar också vad det kan bevisa.

  • Fuzztestning ensamt kan inte ge en fullständig bild av ett övergripande säkerhetshot eller en uppsättning buggar.
  • Fuzz-testning är mindre effektivt för att hantera säkerhetshot som inte orsakar programkrascher, såsom vissa virus, maskar och trojaner.
  • Fuzztestning kan bara upptäcka relativt enkla fel eller hot, och den kommer inte att resonera om affärslogik.
  • För att fungera effektivt krävs det avsevärd maskintid.
  • Att sätta ett randvärdesvillkor med slumpmässiga indata är mycket problematiskt, även om testare nu löser mycket av detta med deterministiska algoritmer som drivs av användarindata.

Fuzztestning kontra penetrationstestning

Båda aktiviteterna letar efter säkerhetsbrister, men de besvarar olika frågor och är sällan utbytbara.

Kriterier Fuzz-testning Penetrationstestning
Driven av En automatiserad motor som genererar felaktigt formaterad indata En skicklig testare resonerar kring systemet
Letar efter Kraschar, låsningar och minnessäkerhetsfel Utnyttjbara svagheter, inklusive logik- och konfigurationsbrister
Djup Mycket bred inmatningstäckning, ytlig resonemang Smal täckning, djupgående resonemang
Produktion Reproducera ingångar och stack traces En resultatrapport med exploateringsvägar och riskklassificeringar
Bästa ögonblicket Kontinuerligt, i byggpipelinen Periodvis, mot en releasekandidat

I praktiken matar de två varandra: fuzzing rensar de billiga, automatiserbara krascherna så att en testares begränsade timmar går åt till de brister som bara en människa kommer att upptäcka.

Vanliga frågor

En frökorpus är startuppsättningen av giltiga indata som fuzzern muterar. Små, varierade, riktiga filer fungerar bäst, eftersom var och en redan passerar parsern och låter motorn spendera sin budget på djupare kod istället för den första giltighetskontrollen.

En fuzz-harness är den lilla funktion som överlämnar en buffert med fuzzade byte till koden som testas. Den ska undvika globala tillstånd, filskrivningar och nätverksanrop, så att motorn kan köra den tusentals gånger per sekund.

En timme eller två avslöjar ytliga buggar. Seriösa kampanjer pågår i många timmar eller dagar, eftersom ny bevakning anländer i periodvisa perioder. En platå i bevakningskurvan, inte en klockavläsning, är den ärliga signalen att en körning har slutat löna sig.

AddressSanitizer fångar buffertöverflöden och "use-after-free", UndefinedBehaviorSanitizer fångar felaktiga heltals- och pekarfunktioner, och MemorySanitizer fångar läsningar av oinitialiserat minne. Utan dem passerar många fel i tysthet och fuzzern rapporterar inga fel alls.

Reproducera det, minimera indata till det minsta felaktiga fallet, gruppera det med krascher som delar samma stack. trace, lämna sedan in en biljett via den vanliga process för felhantering och lägg till indata i en regressionskorpus.

De delar slumpmässighet men inte avsikt. Aptestning kastar godtyckliga användaråtgärder mot ett körande gränssnitt, medan fuzzing riktar sig mot en specifik inmatningstolk och mäter kodatäckning, så att den kan styra sig själv mot kod som de tidigare inmatningarna aldrig nådde.

Språkmodeller används för att utforma verktyg för okomplicerade API:er, för att syntetisera seed-input för exotiska format och för att klustra och sammanfatta kraschrapporter. Motorn tillhandahåller fortfarande täckningsfeedback; modellen tar huvudsakligen bort det manuella installationsarbetet.

GitHub Copilot kan utkasta en libFuzzer-ingångspunkt, en byggfil och en frögenerator från en befintlig API-signatur. RevGranska resultatet noggrant, eftersom en sele som tyst sväljer fel inte kommer att rapportera några krascher.

Sammanfatta detta inlägg med: