När Curl inte fungerar exakt som man vill … i juletider
Curl är ett toppenverktyg och, precis som antagligen alla andra med IT-relaterade yrken, använder jag det (ungefär) dagligen. Under en säkerhetsgranskning av ett webbsystem, för en tid sen, visade det sig dock att Curl (i standardkompilering) inte klarade av att kommunicera med webbsystemets (som jag då säkerhetsgranskade) TLS-version. Det vill säga att de cipher suites som webbsystemet godkände som standard fanns inte inkompilerat i OpenSSL. Utan att gå in på varför, så kan jag konstatera att det uppstår ibland. Då detta uppstår handlar det vanligtvis om att kompilera om OpenSSL (något som jag ägnat mycket tid åt i andra sammanhang). Men jag hade tidigare, i samma projekt, stött på ett annat problem nämligen ett överskådligt sätt att hantera manipulerade headers och body i en http-request i en och samma fil. I curl kan man förstås bifoga egna headers från kommandoraden (med –H-flaggan), men jag hade behov av att manipulera formatet på headers (ungefär som http-response-splitting och http-smuggling) inklusive cookie-headern samtidigt som detta även skulle matchas med POST-datan (som skickas från klient till server). I detta fall behövdes med andra ord exakt kontroll på byte-nivå.
Det finns många verktyg för att skicka http-requests i råformat men inget (som jag visste om) hade en TLS-version som kunde kommunicera med webbservern på ett enkelt sätt. Många av de tillgängliga verktygen är ju även inbäddat i ett fint lättanvänt GUI (exempelvis Acunetix, Fiddler, Burp suite etc). Verktyg utan en bra kommandorad är ju dock ofta oerhört olämpliga för penetrationstester utanför den allra mest grundläggande nivån eftersom de inte enkelt kan användas i skript, ofta är onödigt bloatade med funktioner … och i övrigt igenmurade med diverse irriterande buggar. Så jag testade med några kodrader i C# för att se ifall .NET hade en TLS-version som fungerade med webbsystemet… och det fungerade superfint.
Vanligen så brukar jag, precis som många andra i yrket, bara skapa verktyg för exakt det jag för tillfället behöver. Detta har gjort att jag har galet många småprogram i diverse programmeringsspråk som gör exakt en enda sak och innehåller hårdodade sökvägar, ip-addresser, attacksträngar och annat som kan tänka behövas för det specifika testet. Säkerhetsgranskningen som jag för tillfället arbetade med var dock ett blackbox-test och med mer komplicerade anslutningsförfaranden. Det fanns exempelvis flera ip-addresser, hostname, portar, cookies och annat som var tvunget att samarbeta för att kunna utföra kommandon i webbsystemet. Jag behövde således testa mig fram och bitvis fuzza mig fram till lämpliga attacksträngar. Därför byggde jag ett litet program vars enda uppgift är att just kunna skicka http-requests precis som jag ville ha det för det specifika projektet. Eftersom jag ville ha exakt kontroll över varje byte som skickas tänkte jag att allt ska läsas in från en fil. Filen kan man editera med sin favorit-ascii-text-editor eller favorit-hex-editor om man behöver editera binära format (vilket i vissa delar behövdes i min säkerhetsgranskning).
I händelse av att fler säkerhetskonsulter (eller andra) kan ha någon nytta av detta curl-liknande verktyg … och att jag tror att jag kommer ha nytta av programmet igen… så skickade jag upp det på github: https://github.com/jamesrep/nurl.
Programmet fungerar enligt följande:
- En fil med all data som ska skickas, inklusive post-data, http-verbet såsom post, get, options etc konstrueras manuellt enligt önskemål.
- Programmet läser in filen som skapats i steg 1. Binär inläsning görs av filen så att man även ska kunna skicka icke-ascii-tecken.
- Programmet letar upp raden med ”content-length:” (om den finns) och ersätter bifogat heltal med ”rätt” content-length. Ifall man vill undvika detta steg så skickar man med flaggan ”–skipadjust”.
- Programmet skickar därefter filen till vald host och ip-address och inväntar svar.
- Ifall svaret från servern (http-response) är gzip-komprimerat så dekomprimeras svaret från servern innan det skrivs ut till standard output.
Följande parametrar kan användas:
–host <host/ip>
–port <port number>
–request <input file>
–out <output file>
–ssl – Use SSL for HTTPS connections
–skipheaders – If headers should be skipped
–skipsent – If sent http-request should be skipped
–skipadjust – If we should NOT try to adjust the content-length
–binary – Do not try to interpret HTTP-headers. Use if we assume binary answers from server. If we don’t require to decompress gzip or interpret response-headers, then this works fine.
–nogzip – Use if response should not be decompressed
–parselength – Use if the content-length-parameter from the http-response should be parsed instead of waiting for send-timeout.
Exempel på användning är:
nurl.exe –ssl –host www.simovits.com –port 443 –request httprequesten.txt –out sparatillfil.txt
En sak man kanske bör tänka på är att inga tester på certifikat utförs. Man får inga varningar eller fel ifall certifikatet på servern man ansluter till är självsignerat eller utgånget… det kommer alltid funka (så använd inte programmet för att betala räkningarna i Internetbanken eller något annat giltigt-certifikat-krävande). I curl använder man ju ”-k”-flaggan för att åstadkomma detta. Men detta program är endast tänkt för tester och inte REST-anrop eller annat och därför bryr vi oss inte om hur certifikatet ser ut (det har vi ju andra verktyg till att utvärdera).
Nästa sak (som antagligen kommer implementeras) är en konverteringsfunktion från formateringen man får då man kopierar text i firefox-pluginet ”tamper data”. Det kan även vara smidigt att lägga en generell funktion för att ersätta godtyckliga värden i headers (inte bara content-length som nu är implementerat).
Fotnot: Självklart är programmet inte något vidare kommenterat och innehåller obefintlig felhantering. Men det är endast till för att vara ett verktyg till att testa andra program och är som sagt ett väldigt litet verktyg, snabbt ihopskrivet, få kodrader (och absolut ingen rocket-science).