Allvarlig säkerhet: Hur avsiktliga skrivsätt kan förbättra DNS-säkerheten

Allvarlig säkerhet: Hur avsiktliga skrivsätt kan förbättra DNS-säkerheten

Under åren har vi gjort det skriven och talat på Naked Security många gånger om det svåra problemet med DNS kapning.

DNS, som du säkert vet, är en förkortning för domännamnssystem, och du kommer ofta att höra det beskrivas som internets "telefonkatalog" eller "gazetteer".

Om du inte är bekant med ordet gazeteer, det hänvisar till indexet längst bak i en atlas där du slår upp, säg, Monrovia, Liberia i en bekväm alfabetisk lista, och det står något i stil med 184 - C4. Detta talar om för dig att svänga rakt till sidan 184 och följa rutnätslinjerna ner från bokstaven C överst på kartan och tvärs över siffran 4 till vänster. Där linjerna möts hittar du Monrovia.

För de flesta användare slocknar de flesta DNS-sökningar som innehåller ett servernamn och ber om ett svar för att komma tillbaka som inkluderar vad som kallas dess A-record eller dess AAAA-rekord.

(A-poster används för 32-bitars IPv4-internetnummer, som t.ex 203.0.113.42; AAAA-poster är motsvarande svar för en 128-bitars IPv6-adresser, som t.ex. 2001:db8:15a:d0c::42 – i den här artikeln kommer vi bara att använda A-poster och IPv4-nummer, men samma säkerhetsproblem gäller för uppslagsprocessen i båda fallen.)

Här är ett exempel där vi letar upp det imaginära domännamnet naksec.test via en DNS-server som skapats speciellt för att spåra och lära dig om DNS-trafik.

Vi har använt det gamla skolans Linux-verktyg dig, Förkortning av domän internet groper, för att generera en enkel DNS-begäran (dig söker som standard upp A-poster) för servern vi vill ha:

$ dig +noedns @127.42.42.254 naksec.test ;; FRÅGASDEL: ;naksec.test. I EN ;; SVARAVDELNING: NAKSEC.TEST. 5 IN A 203.0.113.42 ;; Frågetid: 1 ms ;; SERVER: 127.42.42.254#53(127.42.42.254) (UDP) ;; NÄR: mån 23 jan 14:38:42 GMT 2023 ;; MSG STORLEK rcvd: 56

Så här hanterade vår DNS-server begäran, som visar en hex-dump av den inkommande begäran och det framgångsrika svaret som gick tillbaka:

---> Begäran från 127.0.0.1:57708 till 127.42.42.254:53 ---> 00000000 62 4e 01 20 00 01 00 00 00 00 00 00 06 6b 61 6b | .........nak| 00000010 73 65 63 04 74 65 73 74 00 00 01 00 01 |sek.test..... | DNS-uppslag: A-record för naksec.test ==> A=203.0.113.42 <--- Svar från 127.42.42.254:53 till 127.0.0.1:57708 <--- 00000000 62 4 84 0 00 01 00 01 00 00 00e 00 06b |bN...........nak| 6 61 6 00000010 73 65 63 04 74 65 73 74 00 00 01 00e 01 |sek.test......NA| 06 4b 41 00000020 4 53 45 43 04 54 45 53 54 00 00 01 00 |KSEC.TEST.......| 01 00 00 00000030 00 cb 05 00 04a |......q* |

Observera att av prestandaskäl använder de flesta DNS-förfrågningar UDP, den användardatagram protokoll, som fungerar på sänd-och-hopp-basis: du avfyrar ett UDP-paket på servern du vill prata med, och väntar sedan för att se om ett svar kommer tillbaka.

Detta gör UDP mycket enklare och snabbare än sin stora kusin TCP, the överföringsprotokoll, som, som namnet antyder, automatiskt tar hand om massor av detaljer som UDP inte gör.

TCP hanterar särskilt att upptäcka data som går förlorade och frågar om det igen; se till att alla bitar av data kommer fram i rätt ordning; och tillhandahålla en enda nätverksanslutning som, när den väl har ställts in, kan användas för att skicka och ta emot samtidigt.

UDP har inte konceptet med en "anslutning", så att förfrågningar och svar i huvudsak reser oberoende:

  • En DNS-begäran kommer till DNS-servern i ett eget UDP-paket.
  • DNS-servern håller register av vilken dator som skickade just det paketet.
  • Servern börjar hitta ett svar att skicka tillbaka, eller besluta att det inte finns någon.
  • Servern skickar ett svar till den ursprungliga avsändaren med ett andra UDP-paket.

Från nivån på operativsystemet eller nätverket är de två UDP-paketen ovan oberoende, fristående överföringar – de är inte sammanbundna som en del av samma digitala anslutning.

Det är upp till servern att komma ihåg vilken klient som varje svar ska skickas till; och det är upp till kunden att ta reda på vilka svar som avser vilka förfrågningar den ursprungligen skickade ut.

Hur kan du vara säker?

Vid det här laget, särskilt när du tittar på den ringa storleken på DNS-begäran och svaret ovan, undrar du förmodligen: "Hur kan klienten vara säker på att det matchar rätt svar och inte ett som har förvanskats under transporten eller riktats felaktigt av misstag, antingen av misstag eller design?”

Tyvärr är många, om inte de flesta, DNS-förfrågningar (särskilt de från server till server, när den första servern du frågar inte vet svaret och behöver hitta en som gör det för att kunna formulera sitt svar) inte krypterade, eller annars märkt med någon form av kryptografisk autentiseringskod.

Faktum är att DNS-förfrågningar som standard inkluderar en enda "identifikationstagg", som i DNS-dataformatdokumentationen helt enkelt hänvisas till som ID.

Otroligt nog, trots att den har fått många uppdateringar och föreslagna förbättringar under åren, har den officiella internet-RFC (begäran om synpunkter) dokument som fungerar som DNS-specifikationen är fortfarande RFC 1035 (vi är för närvarande inne på RFCs i mitten av 9000-talet), som går tillbaka till november 1987, för drygt 35 år sedan!

Då var både bandbredd och processorkraft en bristvara: typiska CPU-hastigheter var cirka 10MHz; stationära datorer hade ungefär 1MByte RAM; Internetåtkomsthastigheter, för organisationer som överhuvudtaget kunde vara online, var ofta 56 kbits/sek eller 64 kbits/sek, delade mellan alla; och 1200bits/sek var det prisvärda valet för personlig anslutning via dagens uppringda modem.

Det är därför DNS-begäran och svarsrubriker var – och fortfarande är – klämda till ynka 12 byte, varav ID-taggen tar upp de två första, eftersom RFC 1035 är söt. ASCII art klargör:

 1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+ --+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | QR| Opkod |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+---+--+--+--+--+--+--+--+--+--+

Du kan se ID i aktion i hexdumparna som visas ovan, där både begäran och svarspaketen börjar med samma två tecken bN, som motsvarar 16-bitars identifieraren 62 4e i hex.

Mycket löst sett är dessa 16 bitar lika mycket som det officiella DNS-protokollet tillhandahåller i form av "autentisering" eller "feldetektering".

Inblandning genom gissningar

Som du kan föreställa dig, med tanke på den heltäckande enkelheten hos vanlig DNS-trafik, kan alla med en s.k. mellanlåda or skanning proxy vem som kan fånga upp, undersöka och modifiera din nätverkstrafik kan trivialt blanda sig i din DNS-trafik.

Detta inkluderar att skicka tillbaka svar som medvetet ger dig felaktig information, till exempel att ditt IT-team omdirigerar dig bort från servrar som det vet är fyllda med skadlig programvara.

Det kan också inkludera att din internetleverantör följer lagstiftningen i ditt land som kräver att vissa servrar rapporteras som obefintliga, även om de är vid liv och fungerar bra, eftersom de finns på en blocklista över olagligt innehåll som barnmissbruk.

Men vid första anblicken verkar denna ultrasvaga typ av DNS ID-taggning också göra det trivialt även för angripare som inte har någon synlighet av din nätverkstrafik alls att skicka falska DNS-svar mot dina användare eller dina servrar...

…med en farligt stor chans att lyckas.

När allt kommer omkring, om angripare vet att någon i ditt nätverk regelbundet gillar att besöka naksec.test, kan den servern verka som en saftig plats att implantera falska nyheter, tvivelaktiga uppdateringar eller oseriös JavaScript-kod.

Och om angriparna inte kan hacka sig in i naksec.test servern själv, tänk om de regelbundet och ofta skulle avfyra UDP-paket på din DNS-server, med hjälp av en påhittad ID-tagg, som påstod sig svara på frågan "Vad är A-posten för naksec.test"?

På så sätt kan de kanske kapa DNS-förfrågan, ge ett falskt svar och därför missrikta ditt nästa besök på webbplatsen – i princip kapa själva webbplatsen utan att någonsin behöva attackera naksec.test server överhuvudtaget.

Lite tur krävs

De skulle naturligtvis behöva ha lite tur, även om de kunde försöka om och om igen för att öka sina totala chanser, med tanke på att de bara behöver lyckas en gång, medan du behöver få ett riktigt DNS-svar varje gång.

För att lyckas måste de skicka sitt falska DNS-svar:

  • Under en period som din egen server inte redan visste svaret på frågan. DNS-svar inkluderar ett 32-bitars nummer som kallas TTL, förkortning för tid att leva, som säger hur länge den andra änden kan fortsätta att återanvända svaret. Om du eller någon annan i ditt nätverk bad om naksec.test nyligen kan din DNS-server ha svaret i sin cache. Ingen ytterligare sökning skulle behövas, och det skulle inte finnas någon utgående begäran för angriparna att kapa.
  • Mellan den tid då du skickade din förfrågan och det officiella svaret kom tillbaka utifrån. Även förr i tiden var DNS-uppslagningstiderna sällan mer än några sekunder. Idag mäts de bäst i millisekunder.
  • Med rätt nummer i sina första 16 bitar. Du får plats med 65536 (216) olika värden till 16 bitar, så angriparna måste ha lite tur. Men vid dagens nätverksbandbredder tar det en liten bråkdel av en sekund att skicka 65536 olika falska svar på en gång, och därmed täcka alla möjliga ID-nummer.

Lyckligtvis tar anständiga DNS-servrar idag ett extra steg för att göra kapning svår som standard.

Åtminstone är det vad de har gjort sedan omkring 2008, då framlidne Dan Kaminsky påpekade att många DNS-servrar då inte bara var konfigurerade för att lyssna efter inkommande förfrågningar på en fast UDP-port (nästan alltid port 53, officiellt tilldelad DNS)...

…men också för att få inkommande svar på en fast port också, ofta även port 53, om så bara för att skapa en behaglig symmetri i trafiken.

Anledningen till att använda en fast port i båda riktningarna var troligen ursprungligen för enkel programmering. Genom att alltid lyssna efter svar på samma UDP-portnummer behöver du inte ha koll på vilka portar som ska öppnas för vilka svar. Detta innebär att begäranhanteraren och svarsgeneratorkomponenterna i din DNS-programvara kan fungera oberoende av varandra. Begäranslyssnaren behöver inte säga till svarsavsändaren, "Detta svar måste gå tillbaka på en speciell port, inte den vanliga."

Använd portnummer som extra ID

Nuförtiden lyssnar nästan alla UDP-baserade DNS-servrar på port 53, som alltid, men de håller reda på den så kallade "källporten" som används av DNS-beställaren, som den förväntar sig att väljas slumpmässigt.

UDP-källportar, som är lite som ett "anknytningsnummer" i en gammal kontorstelefonväxel, är avsedda att användas för att hjälpa dig och nätverket att skilja förfrågningar från varandra.

Internetprotokollportar (TCP använder dem också) kan köras från 1 till 65535, även om de flesta utgående anslutningar bara använder källportarna 1024-65535, eftersom portnummer 1023 och nedan vanligtvis reserveras för processer med systembehörighet.

Tanken är att avsändaren av en DNS-sökning inte bara ska infoga ett verkligt slumpmässigt 16-bitars ID i början av varje förfrågan, utan också välja ett verkligt slumpmässigt UDP-källportnummer där den kommer att lyssna efter det associerade svaret.

Detta lägger till en extra nivå av gissningar som skurkarna måste lägga till i sin "kapa tur"-lista ovan, nämligen att de måste skicka ett falskt svar som kryssar i alla dessa rutor:

  • Måste vara en fråga som nyligen ställdes, vanligtvis inom de senaste sekunderna.
  • Måste vara en sökning som inte fanns i den lokala serverns cache, betyder vanligtvis att ingen annan frågat om det under de senaste minuterna.
  • Måste ha rätt 16-bitars ID-nummer i början av datapaketet.
  • Måste skickas till rätt destinationsport på den relevanta serverns IP-nummer.

Och en annan sak

Faktum är att det finns ytterligare ett knep som DNS-begärare kan göra, utan att ändra det underliggande DNS-protokollet, och därmed (för det mesta) utan att bryta något.

Detta trick, förvånansvärt nog, var först föreslog tillbaka 2008, i en tidning med härlig titel Ökat motstånd mot DNS-förfalskning genom 0x20-bitars kodning: SÄKERHET VIA LeET QueRies.

Idén är konstigt enkel och bygger på två detaljer i DNS-protokollet:

  • Alla DNS-svar måste inkludera det ursprungliga frågeavsnittet i början. Frågor har uppenbarligen ett tomt svarsavsnitt, men svar krävs för att återspegla den ursprungliga frågan, vilket hjälper till att säkerställa att förfrågningar och svar inte av misstag blandas ihop.
  • Alla DNS-frågor är skiftlägesokänsliga. Oavsett om du ber om naksec.test, eller NAKSEC.TEST, eller nAksEc.tESt, du borde få samma svar.

Nu finns det inget i protokollet som säger att du MÅSTE använda samma stavning i den del av svaret där du upprepar den ursprungliga frågan, eftersom DNS inte bryr sig om skiftläge.

Men även om RFC 1035 kräver att du gör jämförelser som inte är skiftlägeskänsliga, föreslår det starkt att du ändra faktiskt inte fallet av alla textnamn som du får i förfrågningar eller hämtar från dina egna databaser för användning i svar.

Med andra ord om du får en förfrågan om nAKsEC.tEST, och din databas har den lagrad som NAKSEC.TEST, då anses dessa två namn ändå vara identiska och kommer att matcha.

Men när du formulerar ditt svar föreslår RFC 1035 att du Ändra inte skiftläge för data du lägger i ditt svar, även om du kanske tror att det skulle se snyggare ut, och även om det fortfarande skulle matcha i andra änden, tack vare den skiftlägesokänsliga jämförelsen som DNS kräver.

Så om du slumpmässigt blandar ihop fallet med bokstäverna i en DNS-förfrågan innan du skickar den, kommer de flesta DNS-servrar troget att återspegla den konstiga sammanblandningen av bokstäver, även om deras egen databas lagrar namnet på servern annorlunda, som du ser här :

$ dig +noedns @127.42.42.254 nAkSEc.tEsT ;; FRÅGASDEL: ;nAkSEc.TEsT. I EN ;; SVARAVDELNING: NAKSEC.TEST. 5 IN A 203.0.113.42 ;; Frågetid: 1 ms ;; SERVER: 127.42.42.254#53(127.42.42.254) (UDP) ;; NÄR: mån 23 januari 14:40:34 GMT 2023 ;; MSG STORLEK rcvd: 56

Vår DNS-server lagrar namnet naksec.test alla med versaler, så svarsdelen i svaret inkluderar namnet i formuläret NAKSEC.TEST, tillsammans med dess IPv4-nummer (A-posten) för 203.0.113.42.

Men i "här är frågedatan som returneras till dig för korskontroll" av svaret som vår DNS-server skickar tillbaka, bevaras den tecken-case mashup som ursprungligen användes i DNS-uppslagningen:

---> Begäran från 127.0.0.1:55772 till 127.42.42.254:53 ---> 00000000 c0 55 01 20 00 01 00 00 00 00 00 00 06 6e 41. .........nAk| 6 00000010 53 45 63 04 74 45 73 54 00 00 01 00 |SEc.TEsT..... | DNS-uppslag: A-record för nAkSEc.tEsT ==> A=01 <--- Svar från 203.0.113.42:127.42.42.254 till 53:127.0.0.1 <--- 55772 00000000 0 55 84 0 00 01 00 01 00 00 00 00 06 6 41e 6 00000010b |.U...........nAk| 53 45 63 04 74 45 73 54 00 00 01 00 01 06 4 41e 00000020 |SEc.tEsT......NA| 4 53b 45 43 04 54 45 53 54 00 00 01 00 01 00 00 00000030 |KSEC.TEST.......| 00 05 00 04 00 cb 71 2 XNUMXa |......q* |
Allvarlig säkerhet: Hur avsiktliga skrivsätt kan förbättra DNS-säkerheten PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Ovan. DNS-begäran i Wireshark.
Frågeavsnitt med blandat fall visas.
Allvarlig säkerhet: Hur avsiktliga skrivsätt kan förbättra DNS-säkerheten PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Ovan. DNS-svar i Wireshark.
Notera hur frågedata kopieras exakt från begäran, även om serverns databas angav ett ALL-UPPER-namn.

Extra säkerhetsmärkning, gratis

Bingo!

Det finns lite mer "identifikationsmärkning" som en DNS-sökning kan lägga till!

Tillsammans med 15-eller-så bitars värde av slumpmässigt vald källport och 16 bitar av slumpmässigt vald ID-nummerdata, får begäranden välja versaler kontra gemener för varje alfabetiskt tecken i domännamnet.

Och naksec.test innehåller 10 bokstäver, som var och en kan skrivas med versaler eller gemener, för ytterligare 10 bitars slumpmässig "taggning".

Med denna extra detalj att gissa skulle angriparna behöva ha tur med sin timing, UDP-portnumret, ID-taggvärdet och versaler i domännamnet, för att injicera ett falskt "kapningssvar" som den begärande servern skulle acceptera.

Förresten, namnet 0x20-kodning ovan är lite av ett skämt: 0x20 i headecimal är 00100000 i binär, och den ensamma biten i den byten är det som skiljer stora och små bokstäver i ASCII-kodningssystemet.

Bokstäverna A till I, till exempel, kommer ut som 0x41 till 0x49, medan a till i kommer ut som 0x61 till 0x69.

 ASCII-kodningsdiagram som ASCII-text +------+------+------+------+-------+------+- -----+------+ |00 ^@ |10 ^P |20 |30 0 |40 @ |50 P |60 ` |70 p | |01 ^A |11 ^Q |21 ! |31 1 |41 A |51 Q |61 a |71 q | |02 ^B |12 ^R |22 " |32 2 |42 B |52 R |62 b |72 r | |03 ^C |13 ^S |23 # |33 3 |43 C |53 S |63 c |73 s | |04 ^D |14 ^T |24 $ |34 4 |44 D |54 T |64 d |74 t | |05 ^E |15 ^U |25 % |35 5 |45 E |55 U |65 e |75 u | |06 ^F |16 ^V |26 & |36 6 |46 F |56 V |66 f |76 v | |07 ^G |17 ^W |27 ' |37 7 | 47 G |57 W |67 g |77 w | |08 ^H |18 ^X |28 ( |38 8 |48 H |58 X |68 h |78 x | |09 ^I |19 ^Y |29 ) |39 9 |49 I |59 Y |69 i |79 y | |0A ^J |1A ^Z |2A * |3A : |4A J |5A Z |6A j |7A z | |0B ^K |1B ^ [ |2B + |3B; |4B K |5B [ |6B k |7B { | |0C ^L |1C ^ |2C, |3C < |4C L |5C |6Cl |7C | |0D ^M | 1D ^] |2D - |3D = |4D M |5D] |6D m |7D} | |0E ^N |1E ^^ |2E. |3E > |4E N |5E ^ |6E n |7E ~ | | 0F ^O |1F ^_ |2F / |3F ? |4F O |5F _ |6F o |7F | +------+------+------+--- ---+------+------+------+------+

Med andra ord, om du lägger till 0x41+0x20 för att få 0x61, vänder du A in a; om du subtraherar 0x69-0x20 för att få 0x49 så vänder du i in I.

Varför nu?

Du kanske vid det här laget undrar, "Varför nu, om idén dök upp för 15 år sedan, och skulle den faktiskt göra någon nytta ändå?"

Vårt plötsliga intresse, som det händer, kommer från en senaste offentliga e-postmeddelandet från Googles tekniker och erkänner att deras experiment 2022 med det här gamla skolans SÄKERHETSKNIP har implementerats i verkligheten:

Som vi tidigare meddelat är Google Public DNS i färd med att möjliggöra slumpmässiga fall av DNS-frågenamn som skickas till auktoritativa namnservrar. Vi har framgångsrikt distribuerat det i vissa regioner i Nordamerika, Europa och Asien och skyddar majoriteten (90 %) av DNS-frågorna i de regioner som inte täcks av DNS över TLS.

Spännande nog föreslår Google att de huvudsakliga problemen den har haft med denna enkla och till synes okontroversiella justering är att medan de flesta DNS-servrar antingen är konsekvent skiftlägesokänsliga (så att det här tricket kan användas med dem) eller konsekvent inte (så att de är blockerade), som du kan förvänta dig...

…några maintream-servrar hamnar då och då i "case-sensitive" läge under korta perioder, vilket låter som den sortens inkonsekvens du hoppas att stora tjänsteleverantörer skulle undvika.

Hjälper det verkligen?

Svaret på frågan, "Är det värt det?" är inte klart ännu.

Om du har ett fint långt tjänstnamn, som nakedsecurity.sophos.com (22 alfabetiska tecken), då finns det gott om extra signalkraft, eftersom 222 olika versaler betyder 4 miljoner kombinationer för skurkarna att prova, multiplicerat med de 65536 olika ID-numren, multiplicerat med de cirka 32000 till 64000 olika källportarna att gissa...

…men om du har betalat en mindre förmögenhet för ett superkort domännamn, som Twitters t.co, dina angripare har bara ett jobb som är 2x2x2=8 gånger svårare än tidigare.

Ändå tror jag att vi kan säga "Chapeau" till Google för att vi provade detta.

Som cybersäkerhetsobservatörer vill säga, blir attacker alltid snabbare, så allt som kan ta ett befintligt protokoll och lägga till extra spricktid till det, nästan "gratis", är ett användbart sätt att slå tillbaka.


Tidsstämpel:

Mer från Naken säkerhet