Op je firewall zit een functie die in je pakketten meeleest, daar een IP-adres en een poortnummer in de tekst vindt, en daarvoor een inkomend gat opent. Geen regel. Geen changeverzoek. Geen logregel die je ooit zou bekijken. Op de meeste apparatuur die hem heeft staat hij standaard aan, dat is al bijna vijfentwintig jaar zo, en de branche die hem daar neerzette is de laatste twintig jaar stilletjes tot de conclusie gekomen dat hij uit hoort te staan — in standaardendocumenten, in kernelinstellingen en in vier aparte rondes noodpatches voor browsers.
Het heet een protocol-helper, of Application Level Gateway, ALG, session helper, fixup, inspection engine, conntrack-helper. Hetzelfde ding. Het bestaat omdat NAT een handvol protocollen sloopte die adressen in hun eigen payload schrijven, en omdat iemand besloot dat de minst slechte oplossing was om de vertaler te leren die payload onderweg te lezen en te herschrijven.
Hier komt het deel dat je moet doen stilstaan.
De helper kan niet zien wie de tekst geschreven heeft. Hij leest bytes van een verbinding en handelt ernaar, meteen, zonder iets of iemand te vragen. Hij heeft geen manier om te weten of de reeks PORT 192,168,1,29,4,0 van een echte FTP-client kwam die een echte overdracht deed, of van een verborgen formulier op een webpagina die je gebruiker per ongeluk opende. Ze zien er op de lijn identiek uit, want ze zijn op de lijn identiek. Een vreemde op internet die iets in jouw netwerk zover krijgt de juiste bytes te sturen — een browser, een chatclient, alles wat verstuurt wat je het opdraagt — mag dus kiezen welke inkomende poort jouw firewall opent, en waarheen.
Dat is geen bug in de parser van één leverancier. Dat is wat de functie doet. De bugmeldingen en de CVE’s zijn het interessante detail erbovenop; de vorm eronder is dat een beveiligingsapparaat configuratie-instructies aanneemt uit niet-vertrouwde data en die meteen uitvoert.
Samy Kamkar liet de browserversie zien in januari 20101, een veel betere in oktober 20202, en drie maanden later breidde Armis die uit zodat de geopende poort niet eens op de machine hoeft te zitten die klikte — hij kan op je printer zitten, je camera, of een programmeerbare besturing twee VLAN’s verderop3. Daartussenin schreef de IETF op dat deze dingen standaard uit horen te staan4, zette Linux ze in de kernel uit5, en leverden de browserbouwers een lijst geblokkeerde poorten die bijna regel voor regel leest als een inhoudsopgave van de Linux-conntrack-modules6. Elk van die oplossingen is ergens anders aangebracht, omdat wat er echt gerepareerd moest worden in een doos zit die niemand gaat patchen.
Mijn conclusie is dat protocol-helpers overal standaard uit horen te staan, en op elk netwerk waar jij verantwoordelijk voor bent ook echt uit horen te staan. Niet afgeregeld. Niet als eerste maatregel beperkt tot vertrouwde subnetten. Uit, met de twee of drie echte uitzonderingen opgeschreven en gedateerd, precies zoals je elke andere inkomende regel zou documenteren — want dat is wat ze zijn.
Wat volgt is het mechanisme, dan de aanvallen in de volgorde waarin ze gevonden zijn, dan de compliancekant, want in het Verenigd Koninkrijk is dit niet alleen onverstandig maar een regelrecht falen van een certificeringseis die je misschien al hebt, en tot slot de commando’s om het recht te zetten.
Wat een vreemde eraan heeft
Begin bij het resultaat, want het mechanisme boeit makkelijker als je de rekening hebt gezien. Iemand opent een link. Dat is zijn hele bijdrage. De pagina draait JavaScript dat met de server van de aanvaller praat, en die server kneedt het gesprek — vult het op, meet het uit, bevestigt sommige delen en andere niet — tot er één segment bij je firewall aankomt dat er precies uitziet als het openingsbericht van een VoIP-gesprek. Je firewall gelooft het, want dat geloven ís de functie. Hij maakt een inkomende koppeling aan, en de aanvaller verbindt er meteen doorheen terug.
In de versie van 2020 gaat de poort open op de machine die klikte, dus elke dienst die op die host luistert, bereikbaar vanaf internet zolang de koppeling leeft2. Bestandsdeling. De remote desktop die niemand wilde laten luisteren. Over het Fisher-Price OS (Windows) maakte Armis de voor de hand liggende opmerking: bereik de poort voor bestandsdeling en je zit één ongepatchte host van het pad waar WannaCry langs ging3.
De versie van 2021 is erger, en dat is het deel dat het voor je zou moeten beslissen. Omdat de H.323-helper doorschakelen afhandelt, kan één bericht een derde adres noemen in plaats van een van de twee uiteinden van de verbinding. De aanvaller is dan niet meer beperkt tot de machine die klikte en kan in plaats daarvan je interne reeks aflopen, op elk adres een poort openen en teruglezen wat er antwoordt. Armis demonstreerde precies dat: poort 80 over een hele reeks, banners verzameld, een doelwit gekozen, daarna de rauwe printpoort van de printer geopend en er een opdracht heen gestuurd. Hun tweede demonstratie bereikte een besturing op de niet-geauthenticeerde beheerpoort en veranderde het programma3.
Op geen van die apparaten is een kwetsbaarheid misbruikt. De printer was een werkende printer, de camera een werkende camera, de besturing een werkende besturing, en het enige wat faalde was de grens — en die faalde door precies te doen waarvoor hij geconfigureerd was. Bedenk ook wie zich binnen die grens bevindt. Niet alleen je personeel: een bezoeker op het gastennetwerk, de laptop van een aannemer, iedereen met een browser. De aanval heeft geen inloggegevens nodig, geen voet tussen de deur en geen malware, want de browser is het transportmiddel en die staat er al op en wordt al vertrouwd.
Houd dat nu eens naast waar een firewall voor is: ervoor zorgen dat niets van buiten een gesprek begint met iets binnen tenzij jij het gezegd hebt. De helper is de uitzondering, en die uitzondering wordt verleend op gezag van een tekstreeks in een pakket.
Wat een protocol-helper eigenlijk is
Een gewone NAT is een dom, eerlijk ding. Er komt een pakket binnen, hij herschrijft het bronadres en de poort in de header, noteert een regel zodat het antwoord teruggedraaid kan worden, en stuurt het door. Hij kijkt nooit onder de transportheader, en het interesseert hem niet of de bytes erin een webverzoek, een databasequery of de foto van een hond zijn.
Dat werkt tot een protocol een adres in zijn eigen payload schrijft. FTP doet dat, in platte tekst in de commandostroom: verbind terug naar mij op dit adres, op deze poort. SIP doet het in de velden Via, Contact en SDP, H.323 doet het, en IRC doet het voor directe overdrachten. Ze zijn allemaal ontworpen toen het adres van een host het adres van die host was en elke machine elke andere kon bereiken, en onder die aanname is het volstrekt verstandig. Zet een vertaler in het pad en het adres in de payload wordt een leugen.
Dus werd de helper bedacht. Hij leest de payload, vindt het adres, herschrijft het naar het publieke adres, en doet dan het stuk waar iedereen overheen leest: hij maakt een regel die precies de inkomende verbinding toestaat die de payload zojuist beschreef. Netfilter noemt die regel een expectation. Cisco noemt het een pinhole, of een NAT-deur7. Palo Alto noemt het een dynamisch NAT-pinhole8. Juniper noemt het een gate. Ander woord, hetzelfde object: een gat in de grens, geslagen op gezag van iets dat uit een pakket is gelezen.
De IETF gaf het patroon een naam voordat de meeste van deze producten bestonden. Een ALG, zegt RFC 2663, is een “application specific translation agent” die “may interact with NAT to set up state, use NAT state information, modify application specific payload and perform whatever else is necessary to get the application running across disparate address realms”9. Lees dat nog eens met een tegenstander in gedachten: whatever else is necessary, aangestuurd door application specific payload. En in februari 2002 noemde de middlebox-taxonomie van de IETF het mechanisme al bij naam, met de opmerking dat sommige ALG’s fragmentatieproblemen veroorzaken “although in this case the problem is arguably the result of a deliberate layer violation (e.g., mucking with the application data stream of an FTP control connection by twiddling TCP segments on the fly)”10.
Een opzettelijke laagschending. Onderweg aan TCP-segmenten zitten frunniken. Dat is het mechanisme, beschreven door de mensen die het vierentwintig jaar geleden in kaart brachten, en het is hetzelfde mechanisme waar elke aanval in dit stuk regelrecht doorheen loopt.
De expectation is het hele probleem
Al het andere in dit stuk volgt uit één object, dus het loont dat goed te begrijpen.
Een expectation is een vooraf goedgekeurde verbinding: een tupel van bronadres, bronpoort, doeladres, doelpoort en protocol, sommige velden ingevuld en andere als jokers opengelaten, plus een timer. Komt er een passend pakket binnen, dan behandelt de firewall het als verwant aan een bestaande toegestane stroom in plaats van als een nieuwe inkomende verbinding, laat het door en verbruikt de expectation. Op Linux lees je ze rechtstreeks uit /proc/net/nf_conntrack_expect, of met conntrack -L expect. Op een gezond systeem is die lijst leeg, en dat is precies het punt — expectations horen zeldzaam te zijn, kortlevend en veroorzaakt door iets dat een host binnen echt heeft gevraagd.
Twee van die antwoorden zijn slechter dan mensen verwachten. De waarden komen uit de payload en niet van de firewall, dus van het uiteinde van het gesprek dat de helper toevallig las. En bij de IRC-helper is het bronadres per ontwerp een joker, omdat het protocol niet kan weten wie er gaat verbinden: hij “creates expectations whose destination address is the client address and source address is any address”11.
Dit is de zin om mee te nemen. Een expectation is een inkomende firewallregel, aangemaakt op lijnsnelheid, door een niet-vertrouwde partij, zonder enig spoor van wie erom vroeg of waarom. Houd hem vast tot de paragraaf over Cyber Essentials, want daar is hij het hele argument.
Zoals bedoeld: FTP zegt PORT, en de firewall gelooft het
Neem de eenvoudigste helper en kijk hoe hij correct werkt, want de aanval is dezelfde volgorde met één deelnemer vervangen. Actief FTP gebruikt twee verbindingen. De client opent een stuurverbinding naar de server op poort 21 en geeft die commando’s in gewone ASCII, en als er een overdracht moet komen opent hij een luisterende socket en stuurt een PORT-commando met het adres en de poort om naar terug te bellen, waarna de server inkomend verbindt. Dat is het protocol zoals gespecificeerd, en zo werkt het sinds 1985. Op de lijn zijn het zes getallen, vier voor het adres en twee voor de poort, hoogste byte eerst:
PORT 192,168,1,29,4,0
Dat is 192.168.1.29, poort 1024, want 4 × 256 + 0 = 1024.
De helper kijkt naar die stroom, ziet PORT, herschrijft het adres van het privéadres naar het publieke en past daarbij de volgnummers aan omdat de tekst van lengte veranderde, en maakt een expectation die de inkomende verbinding van de server op de genoemde poort toestaat. Echt nuttig, gezien de beperkingen van 1994 volstrekt redelijk, en bij elke stap correct.
Kijk goed naar wat er gecontroleerd werd voordat het gat openging. De bytes zaten op een verbinding naar poort 21. Ze begonnen met PORT. Dat is alles. Verder niets, want er valt verder niets te controleren — FTP heeft geen handtekening te bieden, geen sessiesleutel en geen enkele vorm van authenticatie, en de helper leest een stroom waar hij geen partij in is.
Er zit nog iets in die code, en het is een waarschuwing die de auteurs aan zichzelf schreven. Is het adres in het PORT-commando niet dat van de client zelf — vraagt de client de server dus ergens heel anders heen te verbinden — dan weigert de Linux-helper dat standaard, en het commentaar in de broncode zegt waarom: “DMZ machines opening holes to internal networks, or the packet filter itself”12. Zet de moduleparameter loose en die weigering is weg. De mensen die de helper schreven wisten precies waartoe hij te brengen was. Ze leverden de veilige standaard en een schakelaar, en vijfentwintig jaar later zit die schakelaar er nog.
Niet zoals bedoeld: dezelfde bytes, vanaf een webpagina
Een helper leest een bytestroom en zoekt naar een patroon. Hij controleert niet, en kan constructief niet controleren, of het ding aan de andere kant de client is waarvoor het zich uitgeeft. Samy Kamkar publiceerde het gevolg in januari 2010 en noemde het NAT Pinning1. Het trucje is gênant klein: zet een formulier op een webpagina, richt het op de server van de aanvaller op poort 6667, en zorg dat de inhoud een verzoek om direct chatten bevat.
PRIVMSG samy :^ADCC CHAT samy 3325256705 22^A
De browser stuurt het, in de veronderstelling een HTTP-POST te doen. De IRC-helper van de router, die een verbinding op poort 6667 in de gaten houdt, ziet DCC CHAT langskomen met een adres en een poort en doet waarvoor hij gebouwd is. Het adres daar is 198.51.100.1, geschreven als één decimaal getal, want zo codeert het protocol het, en de poort is 22; niets in die tekst is door het slachtoffer gekozen. De FTP-variant is hetzelfde idee gericht op poort 21, met een antwoordregel in passieve modus in plaats daarvan1.
Geen cross-site scripting. Geen request forgery in de gebruikelijke zin. Geen kwetsbaarheid in de browser. De browser deed wat browsers doen, de firewall deed waarvoor hij geconfigureerd was, en het resultaat is een poortdoorverwijzing naar de aanvaller.
Dat was 2010. Zestien jaar geleden. De browserbouwers zetten de IRC-poorten op hun blokkeerlijst, wat die ene deur sloot en de kamer erachter precies liet zoals hij was.
Zeg het punt onomwonden, want het gaat verloren tussen de leveranciersnamen en de CVE-nummers. De aanvallen buiten geen fout in de helpers uit. Ze gebruiken de helpers correct. Elk pakket is welgevormd en elke controle slaagt eerlijk. De functie doet haar werk, en haar werk is het probleem.
De bytes zetten waar de helper leest
Tussen NAT Pinning en iets veel ergers zat een echte hindernis, en de manier eromheen is het slimste van het hele onderwerp. De meeste helpers zoeken een patroon niet zomaar ergens in een stroom: ze controleren dat het sleutelwoord aan het begin van het datadeel van een pakket staat, wat bij een echt protocolbericht zo is en bij een HTTP-body nooit, omdat een body na een stapel headers aankomt die de aanvaller niet bepaalt. Samy citeert het gedrag van de kernel zelf — de handler haakt af als de methode niet aan het begin van de data staat2.
De aanvaller heeft dus een browser nodig die een segment uitstuurt waarvan de allereerste byte het sleutelwoord is. De headers kan hij niet schrijven, maar de body wel, en zo lang als hij wil — waarmee het probleem een rekensom wordt.
De browser stuurt een groot verzoek met een herkenbaar scheidingsteken verstopt in de body; de server van de aanvaller luistert mee, meet hoeveel bytes aan headers eraan voorafgingen, en kent daarmee de offset. Vervolgens kondigt hij ofwel een segmentgrootte aan die de gewenste byte op een grens legt, ofwel stuurt hij een gedeeltelijke bevestiging zodat het slachtoffer precies vanaf daar opnieuw verstuurt — en Armis voegt toe dat ook het TCP-venster in die bevestigingen te prepareren is, “in order to fully control how the TCP stream is to be segmented”3. Dat is de hele truc, en hij gebruikt niets anders dan het verre eind van een verbinding die de browser van het slachtoffer zelf opende.
Heb je dat eenmaal, dan is de browser een universele pakketgenerator die op de binnenkant van je firewall gericht staat. Geen perfecte, want hij kan geen willekeurige headers zetten en geen willekeurige protocollen kiezen, maar dat hoefde ook nooit. Hij hoeft alleen de juiste dertig bytes aan het begin van een segment te zetten.
Het werk uit 2021 sloeg het meeste rekenwerk over. Een relayverbinding van de browser over TCP draagt een gebruikersnaamveld dat de aanvaller bepaalt, vroeg verstuurd, dat regeleindes en nulbytes accepteert zolang het resultaat geldige tekst is — Armis toonde een opname waarin dat veld de reeks \r\nPORT 192,168,1,29,4,0\r\n is, met een gedeeltelijke bevestiging die het slachtoffer precies vanaf de PORT laat hersturen3. Erger nog: dat pad raadpleegde de blokkeerlijst van de browser helemaal niet, waarmee de ene maatregel die de branche twee keer had uitgeleverd eenvoudig omzeild was.
NAT Slipstreaming, van begin tot eind
Zet de stukken bij elkaar en dit is de hele aanval, op volgorde.
Totale verstreken tijd: seconden. Totale gebruikersinteractie: één klik. Op de machine van het slachtoffer misbruikte kwetsbaarheden: geen.
De tijdlijn van de bekendmaking is op zichzelf bewijs. Samy publiceerde op 31 oktober 2020, Armis nam drie dagen later contact op, en de gecoördineerde melding bij de browserbouwers begon op 11 november. Chrome leverde op 6 januari 2021 een maatregel, Edge de dag daarna, Safari op de 14e in bèta en op 1 februari stabiel, Firefox op de 26e3 — geregistreerd als CVE-2020-16043, CVE-2021-23961 en CVE-2021-1799.
Vier browserbouwers leverden noodpatches voor een firewallfunctie. Armis legt in eigen woorden uit waarom: “While the underlying issue of this attack is the way NATs are implemented (in various ways in routers and firewalls, throughout numerous vendors and applications), the easiest and fastest way to mitigate was through a patch to browsers”3.
Dat is geen oplossing. Het zijn vier andere branches die zandzakken voor andermans voordeur stapelen, omdat die deur zelf nooit vervangen zou worden.
H.323-doorschakelen wijst naar alles in je netwerk
De meeste helpers begrenzen de schade zonder het te willen. De FTP-helper pint het doel van de expectation vast op de client die hem maakte, dus het ergste wat een aanvaller krijgt is een poort op de machine die klikte — erg, maar te overleven.
H.323 is rampzalig, en de reden is een telefoniefunctie.
Een telefooncentrale moet doorschakelen ondersteunen, en een doorgeschakeld gesprek is per definitie een gesprek met iemand die niet aan de lijn is. De signalering moet dus een derde eindpunt noemen, en de helper moet daar een pad heen openen, anders werkt doorschakelen door NAT heen helemaal niet. Elke serieuze implementatie kan dat, en de netfilter-helper documenteert het gedrag uitdrukkelijk, met een tekening, op de netfilter-site13. Armis las de code en vatte het gevolg in één zin samen: “a single H.323 packet sent over TCP port 1720 that initiates call forwarding can open a pinhole (named an expectation in the conntrack subsystem) to any TCP port of any internal IP on the network”3.
Elke TCP-poort. Elk intern adres. Uit één pakket, dat de aanvaller een browser liet versturen.
De aanval gaat daarmee niet meer over de machine van het slachtoffer maar wordt een poortscan van je interne netwerk, uitgevoerd vanaf internet, met de resultaten teruggelezen over verbindingen die je eigen firewall toestaat. De apparaten die hij vindt zijn de kern, want die zijn niet gepatcht, vaak niet te patchen, en het hele beveiligingsmodel van de meeste ervan is het staat toch binnen. Armis hing een getal aan die aanname: een jaar na publicatie was 97% van de industriële besturingen die kwetsbaar waren voor een reeks kritieke fouten nog steeds ongepatcht3. Niemand beweert dat dat getal goed is. Het is de werkelijkheid die “het staat toch binnen” overeind houdt.
H.323 is dus op elk platform het eerste waar je wat aan doet, omdat het het enige is dat voorbij het slachtoffer reikt — en omdat het tegelijk het protocol is dat vrijwel niemand meer gebruikt, is het de goedkoopste beveiligingsverbetering in dit stuk. Zet het uit. Niemand belt je erover.
De helper kan afgaan op een bericht dat jij nooit stuurde
Eén variant verdient een eigen paragraaf, omdat hij de aanname onderuit haalt waar mensen naar grijpen als ze een reden zoeken om niets te doen: goed, maar de aanleiding moet nog altijd van binnen komen, dus beheers de browsers en je beheerst het probleem.
Nee.
In juli 2022 vond David Leadbeater twee fouten in de Linux-IRC-helper14. De module zoekt de reeks \1DCC overal in de stroom in plaats van te controleren dat die op de juiste plek in een correct omkaderd bericht staat, en de adrescontrole vergelijkt met het adres van de chatserver in plaats van de host achter de vertaler, waardoor het publiek bekende adres van een publieke server volstaat. Zet dat bij elkaar en een aanvaller stuurt de client van het slachtoffer een client-naar-client-ping — iets volstrekt normaals om van een andere gebruiker te krijgen — met een verzoek om directe overdracht erin:
PRIVMSG ExampleUser :^APING ^ADCC CHAT x 3325256705 22^A
Volgens de regels van het protocol beantwoordt de client een ping door de inhoud terug te echoën, dus stuurt de client van het slachtoffer die reeks plichtsgetrouw naar buiten, en de helper, die de uitgaande stroom in de gaten houdt, vindt er DCC in en opent de poort.
Niemand binnen deed iets fout en niemand klikte. De client volgde de specificatie, en de specificatie en de helper produceerden samen een inkomend gat naar poort 22 op een machine in het netwerk. Het werd CVE-2022-2663, en de omschrijving in de nationale kwetsbaarhedendatabase is prijzenswaardig helder: “A firewall may be able to be bypassed when users are using unencrypted IRC with nf_conntrack_irc configured”15.
Let op het woord unencrypted. Onthoud dat ook.
De aanbeveling van de auteur is precies waar de rest van dit stuk vanuit een andere richting uitkomt: “Potentially entirely deprecate and remove nf_conntrack_irc, it’s unclear it has much use anymore”14.
De parsers zijn de andere helft
Tot nu toe ging het over helpers die correct werken. Er is een tweede, los probleem: het zijn protocolparsers geschreven in C, draaiend in het snelle pad van een beveiligingsapparaat, op data die vreemden aanleveren, en ze hebben het foutenpercentage dat je bij die beschrijving verwacht. En dit is geen Linux-probleem en geen goedkope-routerprobleem — het komt bij elke leverancier voor, in de code waar ze het meest voor rekenen.
| CVE | Onderdeel | Wat een geprepareerd pakket doet |
|---|---|---|
| CVE-2018-0051 | Junos SIP ALG | Laat de flow-daemon op SRX en MX crashen; vermeldt ook dat SIP ALG standaard aan staat behalve op high-endmodellen |
| CVE-2018-15454 | Cisco ASA / FTD SIP-inspectie | Herstart het apparaat of zet de processor vast |
| CVE-2022-2663 | Linux nf_conntrack_irc | Opent poorten door de firewall heen, zoals hierboven |
| CVE-2023-22412 | Junos SIP ALG | “Specific SIP messages” laten de flow-daemon reproduceerbaar crashen |
| CVE-2023-22415 | Junos H.323 ALG | Schrijven buiten de grenzen door “specific H.323 packets” |
| CVE-2024-21616 | Junos SIP ALG | Eén SIP-pakket put de NAT-pool uit, echt verkeer wordt niet meer vertaald |
| CVE-2024-26851 | Linux nf_conntrack_h323 | Bitverschuiving buiten bereik bij het decoderen van de H.323-bitmap |
| CVE-2024-39551 | Junos H.323 ALG | Geheugen uitgeput door “specific packets” tot het verkeer stilvalt |
Elk daarvan is vanaf het netwerk te bereiken zonder enige authenticatie, door iedereen die een pakket bij de buiteninterface krijgt, dus door iedereen. En lees de bewoordingen: specific SIP messages, specific H.323 packets, a specific SIP packet. Dat is geen protocol dat bezwijkt onder belasting. Dat is iemand die met opzet een pakket bouwt.
Blijf even bij het Cisco-geval. CVE-2018-15454 werd op 31 oktober 2018 gepubliceerd met ernst 8,6, werd in het wild misbruikt, en het advies zei dat de software-update nog niet beschikbaar was16. Cisco’s maatregel is in het eigen advies no inspect sip. Het antwoord van de leverancier op een actief misbruikte fout in de functie was dus de functie uitzetten — en daarmee ligt de vraag op tafel waar de rest van dit stuk op rust. Als uitzetten tijdens een incident een aanvaardbaar antwoord is, op welke grond staat het de rest van de tijd aan?
Een helper werkt alleen als je niet versleutelt
Dit is het deel dat de discussie in zijn eentje zou moeten beëindigen, en het is het deel dat de minste aandacht krijgt. Een protocol-helper leest je payload en kan een versleutelde niet lezen. Een helper doet dus überhaupt alleen iets met verkeer dat je bewust onversleuteld hebt gelaten, en de helper werkend houden betekent dat verkeer onversleuteld houden.
Elk protocol op de lijst heeft al ruim tien jaar een versleutelde modus. FTP heeft TLS sinds 200517; zet het aan en de PORT- en PASV-uitwisselingen zijn onzichtbaar en de helper doet niets. SIP heeft TLS sinds de basisspecificatie, met versleutelde media ernaast. H.323 heeft een eigen beveiligingsbijlage. Chat heeft al heel lang TLS, en het officiële advies bij CVE-2022-2663 was letterlijk het te gebruiken zodat de helper je overdrachtsverzoeken niet ziet15.
De eerlijke formulering van “we hebben de SIP ALG nodig” luidt dus: we hebben onze gesprekssignalering onversleuteld over niet-vertrouwde netwerken nodig, zodat een middlebox die wij niet beheren hem kan herschrijven. Zeg het zo in een ontwerpreview en kijk hoe ver je komt.
Er is een scherpere versie, en daarom is dit geen close call. Een helper aan laten staan is een blijvende prikkel tégen versleuteling: op de dag dat iemand SIP over TLS aanzet, breken de gesprekken en is de helper de reden, dus wordt de wijziging teruggedraaid en blijft de klare tekst nog een jaar. Vraag iemand die het achter een consumentenfirewall geprobeerd heeft hoe dat ging.
Elk ander protocol op internet is de andere kant op gegaan: webverkeer standaard versleuteld, DNS versleuteld, mailtransport versleuteld, QUIC dat zelfs de transportheader versleutelt juist zodat middleboxen die niet kunnen lezen of veranderen. Het middlebox-tijdperk is op het open internet jaren geleden geëindigd, en de laatste plekken die nog leunen op een apparaat in het pad dat de payload leest, zijn de plekken waar iemand een helper aan heeft laten staan.
IPsec is het geval waarin de helper helemaal niets kan lezen
Wat de voor de hand liggende vraag oproept over het protocol dat niets dan versleuteling is. Het antwoord is erger dan je zou gokken.
ESP heeft geen poortnummers, want het is een IP-protocol op zichzelf en niet iets dat over UDP gaat, en een vertaler demultiplext retourverkeer op poort. Met twee clients achter één publiek adres die naar dezelfde gateway willen, valt er dus niets te vinden waaraan je hun inkomende pakketten kunt onderscheiden. RFC 3715 schreef dat in maart 2004 op: een NAT kan de koppeling niet door meekijken leren, en “it is possible that the NAT will deliver the incoming IPsec packets to the wrong destination”18.
Dus bouwden leveranciers een helper. Die kijkt mee met de IKE-uitwisseling op UDP 500, waarvan de eerste pakketten in klare tekst zijn, oogst de cookies en de security parameter index, en opent een poortje zodat inkomend ESP met die waarde bij de juiste host binnen aankomt. Juniper beschrijft het het helderst: “When ESP traffic hits the IKE ALG gates, sessions are created to capture subsequent ESP traffic”19. Cisco’s inspect ipsec-pass-thru doet hetzelfde voor ESP en AH “associated with an IKE UDP port 500 connection”, met een standaardtabel die helemaal geen limiet zet op het aantal ESP-verbindingen per client20.
Hetzelfde object, hetzelfde gezag, alleen matcht de helper hier niet eens een sleutelwoord. Hij kan ESP niet ontleden, want ESP is juist het versleutelde deel; hij stuurt pakketten op een 32-bits getal dat hij in klare tekst voorbij zag komen. De paragraaf van RFC 3715 die hierover gaat heet, zonder enige ironie, “Helper Incompatibilities”, en legt vast dat demultiplexen op cookies “results in problems with re-keying” en dat apparaten die ISAKMP-payloads ontleden “may not handle all payload ordering combinations”18. Een gok in plaats van een regel, en een zelfgebouwde parser in het pakketpad, tweeëntwintig jaar geleden opgeschreven.
De oplossing kwam tien maanden later, in het protocol, waar hij hoort: RFC 3947 laat de twee uiteinden tijdens de sleuteluitwisseling een vertaler ontdekken, en RFC 3948 verpakt ESP in UDP op poort 4500 zodat er weer poorten zijn21. Juniper zegt het daarna hardop: “IKE NAT-T traffic on floating port 4500 is not processed in an IKE ALG”19. Doe je het goed, dan wordt de helper volledig omzeild — dezelfde zin als bij passief FTP en bij ICE.
De mainline-Linuxkernel heeft deze nooit overgenomen. Onder de conntrack-protocollen zit geen ESP-module, en een patch uit 2021 die SPI-gebaseerde tracking toevoegde ging door de review op de netfilter-lijst en is nooit opgenomen22. De leveranciers die hem meeleveren doen dat buiten de boom om, op de apparaten die het minst waarschijnlijk ooit bijgewerkt worden.
Het haalt Cyber Essentials niet, regel voor regel
Tot hier was dit een beveiligingsargument. Voor wie zich in het Verenigd Koninkrijk laat certificeren is het ook een compliance-argument, en er komt geen slimme uitleg aan te pas — het zijn drie punten tegen drie punten. Cyber Essentials is het door de Britse overheid gedragen programma dat via IASME wordt uitgevoerd, de eerste technische eis gaat over firewalls, en het geldende eisendocument is versie 3.3 van april 2026. Dit legt het je op, letterlijk23:
- block unauthenticated inbound connections by default
- ensure inbound firewall rules are approved and documented by an authorised person, and include the business need in the documentation
- remove or disable unnecessary firewall rules, when they are no longer needed
Zet er nu een protocol-helper naast.
Een expectation bestaat juist om een inkomende verbinding toe te staan die anders geblokkeerd zou worden, en de partij wiens data hem veroorzaakte authenticeerde zich nergens tegen, dus het eerste punt faalt regelrecht. De regel werd op lijnsnelheid geschreven door een kernelmodule, dus er is geen document, geen vastgelegde zakelijke noodzaak en nergens in de keten een bevoegd persoon — vraag een auditor om het goedkeuringsbewijs van de regel die een verbinding tot poort 9100 op je printer liet komen en je hebt het niet en kunt het niet maken, want hij bestond achttien maanden geleden negentig seconden. En de regels van een helper worden door een timer verwijderd, en een timer is geen beoordeling.
Drie eisen, drie keer niet gehaald, bij de eerste maatregel van vijf, die in de woorden van het programma geldt voor “boundary firewalls, desktop computers, laptops, routers, servers”23, dus voor alles wat je bezit.
Wees eerlijk over wat dat betekent, want ik ben niet de certificerende instelling. Een beoordelaar werkt met de vragenlijst en het bewijs dat jij aanlevert, en die lijst vraagt of je niet-geauthenticeerde inkomende verbindingen standaard blokkeert en of je inkomende regels gedocumenteerd en goedgekeurd zijn. Antwoord ja terwijl er een helper op je grens draait en het antwoord klopt niet. Waarschijnlijk slaag je toch. Slagen en voldoen zijn niet hetzelfde, en het gat daartussen komt na een incident aan het licht in plaats van ervoor.
Cyber Essentials is ook niet ongewoon in wat het vraagt, alleen ongewoon helder geformuleerd. Een standaard uit de kaartenbranche, een overheidsprogramma, de vragenlijst van een klant en het aanvraagformulier van je verzekeraar vragen allemaal hetzelfde in andere woorden: weet je wat je firewall inkomend toestaat, en heeft iemand dat besloten? Dit is dus de paragraaf voor wie het certificaat tekent. Niet de aanvallen en niet de CVE’s. Drie punten, en het eerlijke antwoord op elk.
De branche heeft dit twintig jaar geleden beslist
Niets hiervan is nieuw en niets is omstreden. Opmerkelijk is hoe lang het besluit al vaststaat terwijl de standaardinstellingen onverstoorbaar doorliepen.
RFC 3027 bracht in januari 2001 elk protocol in kaart dat NAT sloopt24. RFC 3234 zette ALG’s een jaar later in de middlebox-taxonomie, noemde het mechanisme “a deliberate layer violation” en was helder over de kosten van extra dozen in een pad: het “creates extra points of attack, reduces or eliminates the ability to perform end to end encryption, and complicates trust models”10. Toen legde in januari 2007 RFC 4787 — een Best Current Practice en geen suggestie — vast hoe NAT zich hoort te gedragen, en eis tien zei dit:
REQ-10: To eliminate interference with UNSAF NAT traversal mechanisms and allow integrity protection of UDP communications, NAT ALGs for UDP-based protocols SHOULD be turned off.4
Uit. Negentien jaar geleden, met de reden erbij: helpers staan de mechanismen in de weg die wél werken, en ze verhinderen je de integriteit van je eigen verkeer te beschermen. Dezelfde paragraaf merkt vermoeid op dat sommige producten ALG’s “turned on permanently” hebben4.
Drie jaar later liet NAT Pinning een webpagina een poort openen1. Netfilter antwoordde in 2012 met een manier om dat bewust te doen in plaats van automatisch — het CT-doel, dat een helper via een expliciete regel aan een benoemde stroom koppelt, en een schakelaar om automatische toewijzing helemaal te stoppen11. Toen veranderde de kernel op 25 april 2016 zijn standaard, in een commitbericht dat de moeite waard is om helemaal te lezen, zo vermoeid klinkt het:
Four years ago we introduced a new sysctl knob to disable automatic helper assignment […] This knob kept this behaviour enabled by default to remain conservative. This measure was introduced to provide a secure way to configure iptables and connection tracking helpers through explicit rules. Give the time we have waited for this, let’s turn off this by default now, worse case users still have a chance to recover the former behaviour by explicitly enabling this back through sysctl.5
Dat kwam met Linux 4.7, en sindsdien doet een doos met die modules geladen er niets mee tot je een regel schrijft die er een aan een stroom koppelt, met een logregel die het je vertelt. Alles daarna staat in het diagram hierboven: Slipstreaming en de variant voor elk apparaat, vier browserbouwers met maatregelen terwijl de webplatformstandaard zelf de poortlijst kreeg25, de IRC-helper die afgaat op een bericht dat niemand opstelde, en nog vier ALG-kwetsbaarheden in de vlaggenschipfirewalls van één leverancier.
Kijk nu wat er op de lijst ontbreekt. In vijfentwintig jaar is geen enkele regel ervan een firewallleverancier die een firmware-update uitrolt die deze dingen uitzet op apparatuur die al is uitgeleverd. Het standaardisatieorgaan vroeg erom. De kernel deed het upstream. De onderzoekers bewezen het vier keer apart. De browsers betaalden ervoor. De dozen draaiden door.
En de blokkeerlijst van poorten is het teken aan de wand. De poorten 69, 137, 161, 554, 1719, 1720, 1723, 5060, 5061, 6566 en 10080 staan er allemaal op6 — TFTP, NetBIOS, SNMP, RTSP, H.323 twee keer, PPTP, SIP twee keer, het scannerprotocol en het Amanda-backupprotocol. Laat de helpermodules in een Linux-kernelboom opsommen en je zult merken dat je dezelfde lijst twee keer gelezen hebt. Geen toeval, en geen beveiligingsmaatregel. Het is de ene branche die permanent een groeiende blokkeerlijst van poorten bijhoudt, omdat een andere branche een standaardwaarde niet wil veranderen.
Onder de meeste logo’s zit Linux
Het netfilter-detail is het belangrijke deel en geen Linux-vormige uitweiding, en het loont te zeggen waarom voordat de leverancierslijst komt. Een heel groot deel van de dozen die op deze planeet NAT doen is Linux met netfilter onder een leveranciersschil: elke OpenWrt-afgeleide, dus het grootste deel van de consumenten- en mkb-routermarkt, de meeste door providers geleverde thuisrouters, een flink deel van de carrier-grade NAT-apparatuur, en volop commerciële appliances waarvan de webinterface niets verraadt over wat eronder zit. De helper die jouw SIP ontleedt is in heel veel gevallen datzelfde nf_conntrack_sip.c dat in de mainline-kernel zit, door iemand anders gecompileerd en via een menu aangestuurd.
Het bewijs zit in het onderzoek zelf. Toen Samy in een Netgear-router naar de SIP ALG zocht, pakte hij de firmware uit en vond een kernelmodule met ftp_decode en sip_decode2. De testlijst van Armis bevatte OpenWrt en VyOS plus een categorie die ze simpelweg “various consumer grade Linux routers, with likely older kernel versions” noemden, en de H.323-analyse die de bevinding “elke interne host” opleverde ontstond bij het lezen van de netfilter-broncode en werd daarna bevestigd op commerciële firewalls van drie leveranciers3.
Daaruit volgen twee praktische gevolgen.
De kernelstandaard bereikt jou niet. Linux 4.7 zette automatische toewijzing in 2016 uit, maar alleen als de kernel nieuw genoeg is en niemand hem weer heeft aangezet. Armis vond VyOS dat nf_conntrack_helper expliciet terugzet op 1, en merkte op dat volop Linux-gebaseerde producten hem weer aanzetten “as it is still useful for many users”3. Een kernel uit 2014 in een product uit 2026 krijgt het gedrag van 2014, en een actuele kernel met de schakelaar om krijgt hetzelfde. Geen van beide staat op een datasheet.
Wie het netfilter-model kent, weet wat hij elke andere doos moet vragen. De drie vragen uit de paragraaf over expectations zijn geen Linux-vragen. Het zijn dé vragen. Elke leverancier heeft hetzelfde object onder een andere naam, de documentatie geeft de antwoorden vrijwel nooit, en weten wat de referentie-implementatie doet is hoe je uitvogelt wat je moet testen.
Doe het Linux-werk goed, en lees daarna elke andere leverancier daartegen af.
De Linux-helpers, netjes
Begin met wat er daadwerkelijk geladen is:
lsmod | grep -E 'nf_conntrack|nf_nat'
De helpermodules zijn die naar protocollen genoemd zijn — nf_conntrack_ftp, _sip, _h323, _irc, _tftp, _pptp, _snmp, _amanda, _sane, _netbios_ns en _talk — elk met een bijbehorende nf_nat_* waar adressen herschreven worden. Controleer daarna of automatische toewijzing aan staat, want dat is de schakelaar die bepaalt of een geladen module uit zichzelf iets doet:
sysctl net.netfilter.nf_conntrack_helper
Nul is wat je wilt, en nul is de standaard vanaf Linux 4.75. Eén betekent dat elke geladen helper actief is op elke stroom die bij zijn poort past, vanaf elk adres, wat het gedrag van 2015 is en het gedrag waar de aanvallen in dit stuk van uitgaan.
Kijk daarna naar conntrack -L expect op een draaiende firewall. Met helpers uit blijft het leeg; met ze aan zet je er een opname naast en zie je regels verschijnen terwijl mensen het netwerk gebruiken. Die oefening is het één keer in je leven waard, want niets maakt het punt sneller dan een inkomende toestemming die jij niet geschreven hebt voor je ogen te zien verschijnen en verdwijnen.
Staat automatische toewijzing uit en wil je tóch een bepaalde helper op een bepaalde stroom, dan is de geëigende weg een expliciete regel, die hem in elk geval tot één bestemming en één poort beperkt:
iptables -t raw -A PREROUTING -p tcp --dport 21 -d 192.0.2.10 -j CT --helper ftp
Het nftables-equivalent declareert een ct helper-object en koppelt het met ct helper set in de prerouting-keten, dezelfde discipline met betere syntaxis.
Kijk wat die regel is: een gedocumenteerde, goedgekeurde, zakelijk onderbouwde inkomende uitzondering, door een mens geschreven, in de regelset, waar een auditor hem kan lezen. Precies wat de automatische variant nooit kon zijn.
Wil je ze weg hebben in plaats van slechts slapend — en op een firewall zou je dat moeten willen — voorkom dan dat de modules überhaupt laden:
for m in ftp sip h323 irc tftp pptp snmp amanda sane netbios_ns talk; do
echo "install nf_conntrack_$m /bin/false"
done > /etc/modprobe.d/no-conntrack-helpers.conf
install ... /bin/false in plaats van blacklist is met opzet: blacklist voorkomt alleen automatisch laden via aliassen, en wie de module bij naam opvraagt krijgt hem alsnog. En laadt de firewalllaag van je distributie ze voor je — firewalld doet dat als een zone de FTP- of TFTP-dienst aan heeft staan — dan is dat de laag die je moet aanpakken, want die legt ze behulpzaam terug.
Alle andere logo’s, en hoe je het uitzet
Controleer je eigen versie in plaats van iets van internet te geloven, het mijne inbegrepen, want deze standaardwaarden verschuiven tussen releases en tussen modellen in dezelfde serie.
pfSense en OPNsense zijn het bewijs dat de discussie voorbij is. Er valt geen SIP ALG uit te zetten, want er is er nooit een geweest om aan te zetten. Ze horen tot de breedst uitgerolde firewalldistributies die er zijn, ze draaien telefonie voor heel veel organisaties, en als een helper echt nodig was om moderne VoIP te laten werken zou dat niet kunnen. Het kan duidelijk wel. Met de FTP-proxy ging het net zo: Netgate haalde hem in januari 2015 uit het basissysteem en degradeerde hem tot een aanvullend pakket dat de meesten nooit geïnstalleerd hebben.
Het ontwerp van OpenBSD is dat wat alle anderen hadden moeten kopiëren. pf herschrijft in het doorstuurpad helemaal geen payload. Wil je FTP geholpen hebben, dan draai je ftp-proxy, een aparte userspace-daemon, en schrijf je een expliciete divert-to-regel die de stuurverbinding daarheen stuurt; de proxy verbindt dan namens de client met de server26. Daar vallen meteen drie eigenschappen uit: hij staat uit tenzij je hem bewust aanzet, hij ziet alleen verkeer dat je in een regel benoemd hebt, en een fout erin laat een userspaceproces crashen in plaats van het pakketpad. Zo ziet opt-in eruit als iemand het ontwerpt in plaats van er achteraf aan vast te schroeven.
OpenWrt levert de ALG-modules niet mee, en automatische toewijzing blijft uit ook als je ze installeert.
Cisco ASA en FTD dragen inspection engines in het standaard globale beleid, en no inspect sip is Cisco’s eigen advies tijdens een incident:
policy-map global_policy
class inspection_default
no inspect sip
no inspect h323 h225
no inspect h323 ras
no inspect skinny
Op FTD is het configure inspection sip disable vanaf de CLI van het apparaat16. IPsec-passthrough is het ene dat Cisco goed deed: inspect ipsec-pass-thru staat helemaal niet in het standaardbeleid, dus tenzij iemand hem bewust toevoegde valt er niets te verwijderen20.
Cisco IOS en IOS XE hebben het ook standaard aan — “NAT support for SIP is enabled by default on port 5060”, in Cisco’s eigen woorden7, en hetzelfde voor H.323:
no ip nat service sip tcp port 5060
no ip nat service sip udp port 5060
no ip nat service h225
Juniper SRX zet SIP en H.323 aan op de branchmodellen en niet op de high-endapparatuur, wat op zichzelf al verraadt wat Junipers technici ervan vinden. Kijk met show security alg status waar je staat, dan:
set security alg h323 disable
set security alg sip disable
set security alg ftp disable
set security alg ike-esp-nat disable
FortiGate inspecteert VoIP standaard via het VoIP-profiel, met daaronder een kernel-sessionhelper. De door Fortinet gedocumenteerde volgorde haalt eerst de helper weg27:
config system session-helper
show
delete <het SIP-item>
end
config system settings
set default-voip-alg-mode kernel-helper-based
end
Lees het itemnummer uit je eigen show-uitvoer in plaats van er een over te schrijven, want het verschuift tussen modellen en releases. Fortinet waarschuwt dat vaak een herstart nodig is.
Check Point is het lastige geval voor een audit, want er is geen enkele schakelaar. De helper is een eigenschap van het serviceobject in de regel, dus de vooraf gedefinieerde SIP-service brengt je de protocolhandler en alles wat die doet. Hem vermijden betekent een eigen eenvoudige UDP- of TCP-service op poort 5060 definiëren met protocoltype “none”, matching aanzetten, en die regel boven alles zetten wat nog de ingebouwde gebruikt. “Staat de ALG aan?” is dus geen vraag die een instellingenpagina kan beantwoorden. Wees daarom voorzichtig voordat je iemands woord aanneemt dat hij uit staat.
Palo Alto geeft je een schakelaar per applicatie, en de eigen documentatie zegt dat de SIP ALG “creates dynamic NAT pinholes”8. Objects, Applications, zoek sip, pas de ALG-optie aan, vink Disable ALG aan, commit.
MikroTik levert tien helpers onder /ip firewall service-port — SIP, H.323, FTP, IRC, TFTP, PPTP, RTSP en meer — elk in één regel gedocumenteerd, zonder enige veiligheidswaarschuwing op de pagina. Eerst opsommen, dan uitzetten wat je vindt:
/ip firewall service-port print
/ip firewall service-port set [find name=sip] disabled=yes
/ip firewall service-port set [find name=h323] disabled=yes
/ip firewall service-port set [find name=ftp] disabled=yes
Consumenten- en providerrouters. Zoek naar “SIP ALG”, “SIP helper”, “VoIP passthrough” of “application layer gateway”, meestal onder een pagina voor geavanceerde NAT. Bij veel ervan, zeker bij providerapparatuur, is er helemaal geen instelling — wat je vertelt of die doos thuishoort op een netwerk waar jij verantwoordelijk voor bent.
Op welk platform ook, sluit het op dezelfde manier af: bewijs het. Zet een opname op de buiteninterface, stuur van buitenaf een geprepareerde PORT- of REGISTER-regel naar de betreffende poort, en controleer dat er niets opengaat. Een instelling die je niet getest hebt, is een geloof.
Het meeste dat stukgaat is toch al dood
Eerlijk zijn over de kosten is de hele grond om dit van iemand te vragen, dus hier zijn ze. De SIP-helper uitzetten op een netwerk met slecht geconfigureerde telefoons kan gesprekken slopen, meestal eenzijdig geluid of registraties die wegvallen. De FTP-helper uitzetten sloopt uitgaand actief FTP. De H.323-helper uitzetten sloopt H.323, als je dat nog hebt. Dat is echt, en je moet op minstens één daarvan rekenen als je dit in één wijziging doet op een netwerk waar jaren niemand naar gekeken heeft.
Lees de lijst nu terug en merk op dat vrijwel elk protocol dat een helper bedient er een is dat de rest van de branche allang begraven heeft. H.323 verloor twintig jaar geleden van SIP. PPTP is sinds 1998 onverdedigbaar, en dat betoog heb ik uitgebreid gevoerd in IPsec was een goed idee. Directe IRC-overdrachten horen bij een decennium waar niemand met weemoed aan terugdenkt. NetBIOS-naamdienst, de community-stringversies van SNMP, het scannerontdekkingsprotocol en het oude backupprotocol zijn relikwieën voor lokale netwerken die nooit een grens hoorden over te steken. Kale FTP is helemaal uit de browsers verdwenen — Firefox zette het in versie 88 uit en haalde het er in 90 in juli 2021 uit, en Chrome verwijderde de code in oktober daarop in versie 95, beide op grond dat het gebruik verwaarloosbaar was en de beveiliging het onderhoud niet waard28.
“We kunnen de helper niet uitzetten, er gaat iets stuk” is dus meestal een argument om een dood protocol aan de beademing te houden om een functie te rechtvaardigen die poorten opent voor vreemden. Uitzetten sloopt je netwerk niet. Het legt het ene ding erop bloot dat jaren geleden uitgefaseerd had moeten worden, en dat is informatie die je toch al wilde hebben.
SIP is de echte uitzondering en de enige. Al het andere op die lijst is een argument dat je blij mag zijn te verliezen — en niets ervan is onoplosbaar, want elk betrokken protocol heeft zijn eigen vertaalprobleem jaren geleden zelf opgelost, in het protocol, waar het hoort.
Wat je in plaats daarvan doet
FTP. Passieve modus, sinds 1985 in de specificatie en al twintig jaar de standaard in elke client: beide verbindingen gaan naar buiten en er blijft voor een helper niets te doen. En verplaats je in 2026 bestanden tussen organisaties, dan is FTP niet het protocol daarvoor — SFTP en FTPS zijn versleuteld, en bij geen van beide komt een helper.
SIP en al het andere realtime. Het eindpunt vraagt een server op internet hoe zijn publieke adres en poort er van buiten uitzien, biedt elk pad aan dat het heeft, en de twee uiteinden testen de paden tegen elkaar en houden er een die werkt, met een relay waar geen direct pad bestaat. Dat is STUN, TURN en ICE, en dat is wat elke browser ter wereld doet bij elk videogesprek, door elke soort vertaler, zonder één ALG in het pad. Kan je telefooncentrale dat in 2026 niet, dan ligt het probleem bij de telefooncentrale.
IPsec. NAT-traversal, oftewel RFC 3947 en RFC 3948: de twee uiteinden merken de vertaler op tijdens de sleuteluitwisseling en verpakken ESP de rest van de sessie in UDP 450021, zonder poortje op welke doos ertussen dan ook.
H.323. Uitfaseren. SIP won die discussie rond 2005, dus er valt geen migratie te plannen, alleen een verwijdering. Directe overdrachten, TFTP, SNMP, NetBIOS, scannerontdekking en het backupprotocol gaan dezelfde kant op: geen ervan heeft een grens te kruisen.
IPv6. Daar bestaat niets hiervan, want er is geen vertaling en dus niets wat een helper kan herschrijven. Een host heeft zijn eigen adres, het adres in de payload klopt, en een stateful firewall staat toe wat jij gezegd hebt en verder niets. Elk probleem in dit stuk stamt af van adresvertaling, en adresvertaling stamt af van IPv6 niet uitrollen — een betoog dat ik elders uitgebreid heb gevoerd en hier niet herhaal.
Nu het deel waarin ik niet diplomatiek ga zijn.
Zegt iemand je dat je deze dingen aan moet zetten — een leverancier, een telefonie-installateur, een managed service, een integrator op een raamcontract — dan is dat geen netwerkengineer en geen beveiligingsspecialist. Hij is misschien heel goed in wat hij werkelijk doet, en dit zal dat niet zijn. Het juiste antwoord op een telefooncentrale die een firewall nodig heeft om haar signalering te herschrijven, is de telefooncentrale repareren, en wie je in plaats daarvan zegt je grens open te zetten voor een tekstzoekende parser, vertelt je dat hij ofwel niet weet wat een expectation is ofwel dat het hem niet uitmaakt. Wij zijn hier geen amateurs. Sinds 2007 staat in standards-trackdocumenten hoe het hoort, en “zet gewoon de SIP-helper aan” is het geluid van iemand die grijpt naar wat het ticket vandaag sluit.
Vraag hem, in de kamer, waarop de joker voor het bronadres van de expectation staat. Verrast die vraag hem, dan heb je je antwoord, en het ging nooit over het protocol.
Draai je ze nog — mag je jezelf professional noemen?
Dat is een serieuze vraag en hij verdient een serieus antwoord, dus hier zijn er drie, want er zijn drie gevallen. Het hangt ervan af of je het weet — en weten is niet iets wat je overkomt. Zorgen dat je het weet, dat is het werk.
Staat er op een grens waar jij verantwoordelijk voor bent een SIP-, H.323- of FTP-helper aan, en kun je niet zonder opzoeken zeggen wat een expectation is, welke van zijn velden jokers zijn, wie de waarden aanlevert, en wat je certificeringsopgave over inkomende regels beweert — dan nee. Hierop niet. Je hebt geen configuratie gekozen, je hebt een standaardwaarde geërfd en die nooit nagelezen. Het tekort is niet het gat; iedereen heeft gaten, en dit had ik ook. Het is een grens bouwen over een gat dat je nooit bent gaan dichten, en daarna iets tekenen waarin staat dat de grens deugt.
Weet je precies wat het doet, en staat het aan omdat een toezichthouder het protocol noemt, omdat de apparatuur van een partner niets anders termineert, of omdat de telefooncentrale in maart vervangen wordt en dit tot dan moet werken — dan ja, uiteraard, en je doet het werk goed. Dat zijn echte beperkingen en ik heb om ergere heen gewerkt. Professioneel in plaats van nalatig wordt het doordat je hebt opgeschreven welke helper, op welke interface, voor welke stroom, waarom, en op welke datum hij eraf gaat. Precies het papierwerk waar de firewall-eis al om vroeg.
Het onverdedigbare geval is het middelste. Genoeg weten om ongemakkelijk te zijn, en het toch laten draaien omdat niemand je ooit dwong het te verantwoorden. Dat is geen engineering. Dat is gewoonte met een changenummer eraan, en zo staat een functie die een Best Current Practice je in januari 2007 opdroeg uit te zetten in 2026 nog aan.
Dit telt het zwaarst als je iemand betaalt voor zijn oordeel, want oordeel valt bij oplevering niet te inspecteren. Inspecteer het dus vooraf. Vraag wat hun standaardbouw met protocol-helpers doet en waarom, vraag wat er gebeurt als iemand op het gastennetwerk een link opent, en vraag welke interne apparaten bereikbaar zouden zijn met de H.323-helper aan — en let op of ze zeggen “alleen de machine die klikte”, want dat is fout, en het is het foute antwoord dat een competent klinkend iemand geeft. Je weet binnen twee minuten of je iets verteld krijgt of voorgelezen, en twee minuten is een veel goedkopere toets dan een incident.
Komt het antwoord als een schouderophalen en teken je toch, dan is dat ook een beslissing. Hij is alleen opgehouden de hunne te zijn en de jouwe geworden.
Niemand hoefde het ooit te verantwoorden
Ik wil eerlijk zijn tegenover de mensen die deze dingen bouwden, want dat verdienen ze.
In 1994 was de helper een redelijk antwoord op een echt probleem. Adressen raakten op, NAT was de pragmatische oplossing, een handvol belangrijke protocollen overleefde dat niet, en de keuze was elke FTP-client ter wereld aanpassen of de doos leren lezen. Ze leerden de doos lezen, leverden de veiligste standaarden die ze konden bedenken, en schreven in de broncode waarschuwingen over waartoe het te brengen was. Die waarschuwingen staan er nog. Eén ervan heb ik geciteerd.
Wat daarna misging is geen technisch falen. Het is dat niets in deze branche ooit iemand dwong er nog eens naar te kijken. De IETF zei ze uit te zetten en had geen macht om iemand daartoe te brengen. De kernel veranderde zijn standaard en kon de al uitgeleverde apparaten niet bereiken. Onderzoekers bewezen het in zestien jaar vier keer, en elke keer landde de oplossing ergens anders dan in de firewall.
Ondertussen bleef de standaardwaarde aan. Niet omdat iemand hem verdedigde. Maar omdat een standaardwaarde waar niemand over twist onbeperkt blijft bestaan, en omdat er nergens een afdeling is wier taak het is dingen te beëindigen.
Dat is het patroon, en het is groter dan één firewallfunctie. Dit vak is uitstekend in onderhouden en hopeloos in stoppen. Onderhoud is begroot, bemenst, factureerbaar en veilig, terwijl uitfaseren één persoon vraagt die zijn naam zet onder een wijziging zonder voordeel als hij goed gaat en met zijn naam er overal op als hij misgaat. Dus blijft het ding, en blijft het, en op een dag ontdekt iemand dat het poorten opent naar je printer.
Het teken is voor mij die formulering in Cisco’s eigen documentatie: de ALG maakt een NAT-deur. Geen filter. Geen controle. Een deur, in de muur waar jij voor betaald hebt, geopend door iedereen die er een pakket met de juiste woorden vooraan doorheen krijgt — en het ingesleten antwoord van de branche is voorbijgangers te vragen alsjeblieft niet aan de klink te trekken.
Die van jou kun je vanmiddag dichtdoen, en daar is het de moeite waard om mee te eindigen. Niet de aanvallen; de aanvallen zijn alleen wat er gebeurt als niemand het doet. Ga kijken wat je grens inkomend toestaat zonder dat je het ooit hebt opgeschreven, bepaal of je dat zo bedoelde, en haal eruit wat je niet bedoelde — met een datum naast wat je houdt.
Meer is een grens nooit geweest: een lijst dingen die iemand koos toe te staan en kon verantwoorden. Wat erop staat zonder dat iemand het koos is geen beveiliging. Dat is meubilair.
Samy Kamkar — NAT Pinning, 5 januari 2010. De oorspronkelijke aanval van de browser op het ALG, met een verborgen formulier dat een browser een IRC-
DCC CHATof een FTP-227-antwoordregel laat versturen, zodat de helper van de router een inkomende poort opent. “No XSS or CSRF required.” ↩︎ ↩︎ ↩︎ ↩︎Samy Kamkar — NAT Slipstreaming, 31 oktober 2020, bijgewerkt in januari 2021. Door de auteur samengevat als “an attacker to remotely access any TCP/UDP service bound to a victim machine, bypassing the victim’s NAT/firewall (arbitrary firewall pinhole control), just by the victim visiting a website”. Bevat de techniek met de segmentgrenzen, de opmerking dat de SIP-handler “will bail unless the method (eg, REGISTER) occurs at the start of the data portion of the packet”, en de firmware-analyse van een Netgear-apparaat die
ftp_decodeensip_decodein een kernelmodule vond. ↩︎ ↩︎ ↩︎ ↩︎Ben Seri en Gregory Vishnepolsky, Armis — NAT Slipstreaming v2.0, 26 januari 2021. Het H.323-doorschakelprimitief, het omzeilen van de blokkeerlijst van de browsers via het relay, de lijst met geteste producten (OpenWrt, VyOS, consumenten-Linux-routers, FortiGate, Cisco ASAv en csr1000v, HPE vsr1000, SonicWall TZ300), het verloop van de bekendmaking en de conclusie dat “resolving the issue will require a fundamental change of their implementations by various router/firewall vendors”. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
RFC 4787 — Network Address Translation (NAT) Behavioral Requirements for Unicast UDP, januari 2007, BCP 127. Paragraaf 7 bevat REQ-10, en de constatering dat “Certain NATs have these ALGs turned on permanently, others have them turned on by default but allow them to be turned off”. ↩︎ ↩︎ ↩︎
Pablo Neira Ayuso — netfilter: nf_ct_helper: disable automatic helper assignment, commit
3bb398d9, 25 april 2016, geleverd met Linux 4.7. Verandert de standaardwaarde vannf_conntrack_helpervan aan naar uit. ↩︎ ↩︎ ↩︎Chromium-broncode —
net/base/port_util.cc. De arraykRestrictedPortsbevat 69, 137, 139, 161, 554, 1719, 1720, 1723, 5060, 5061, 6566 en 10080. De aankondiging van de SIP-poorten door Adam Rice, 5 november 2020: “a carefully-crafted HTTP request to port 5060 on an attacker’s server can fool some NAT devices into treating it as a SIP packet and setting up port forwarding to an attacker-controlled port number.” ↩︎ ↩︎Cisco — SIP ALG Hardening for NAT and Firewall, IP Addressing Configuration Guide, Cisco IOS XE 17.x. “SIP ALG creates a firewall pinhole or a Network Address Translation (NAT) door based on the first value in the Via header field for each SIP request received.” NAT-ondersteuning voor SIP is “enabled by default on port 5060”. Zie ook Using Application-Level Gateways with NAT, waarin staat dat SIP en H.323 standaard aan staan. ↩︎ ↩︎
Palo Alto Networks — Disable the SIP Application-level Gateway (ALG). “SIP ALG creates dynamic NAT pinholes but may interfere with VoIP applications that have NAT traversal capabilities, causing communication failures.” ↩︎ ↩︎
RFC 2663 — IP Network Address Translator (NAT) Terminology and Considerations, augustus 1999. Paragraaf 2.9 is waar het Application Level Gateway gedefinieerd wordt. ↩︎
RFC 3234 — Middleboxes: Taxonomy and Issues, februari 2002. De regel over de laagschending staat in paragraaf 2.11; de kosten van extra dozen in het pad staan in paragraaf 5, die eraan toevoegt dat het “creates extra points of attack, reduces or eliminates the ability to perform end to end encryption, and complicates trust models and key distribution models”. ↩︎ ↩︎
Eric Leblond, Pablo Neira Ayuso, Patrick McHardy, Jan Engelhardt en Mr Dash Four — Secure use of iptables and connection tracking helpers. “This system relies on parsing of data coming either from the user or the server. It is therefore vulnerable to attack and great care must be taken when using connection tracking helpers.” Bron van het citaat over de IRC-joker, en beschrijft de sysctl
nf_conntrack_helperen het doelCT --helper. ↩︎ ↩︎Linux-kernelbroncode —
net/netfilter/nf_conntrack_ftp.c. De moduleparameterloosestaat standaard op false en beschermt het geval waarin het adres in hetPORT-commando niet dat van de client zelf is; het commentaar noemt het risico “DMZ machines opening holes to internal networks, or the packet filter itself”. ↩︎netfilter — H.323 conntrack/NAT helper, door de auteur van de module. Bevat het doorschakelscenario waarin een sessie naar het adres van een derde partij kan verwijzen. ↩︎
David Leadbeater — NAT-Again: IRC NAT helper flaws, augustus 2022. Toont de aanleiding via de ping-echo, merkt op dat het ook gebruikt kan worden om te scannen, om gemaskeerde gebruikers te ontmaskeren en om ze te verbreken door poort 0 te noemen, en beveelt aan: “Potentially entirely deprecate and remove nf_conntrack_irc, it’s unclear it has much use anymore.” ↩︎ ↩︎
CVE-2022-2663 — “An issue was found in the Linux kernel in nf_conntrack_irc where the message handling can be confused and incorrectly matches the message. A firewall may be able to be bypassed when users are using unencrypted IRC with nf_conntrack_irc configured.” ↩︎ ↩︎
Cisco — advies voor CVE-2018-15454, voor het eerst gepubliceerd op 31 oktober 2018. De gegeven maatregel is
no inspect sipop ASA enconfigure inspection sip disableop FTD; de vermelding in de nationale kwetsbaarhedendatabase legt vast dat bij publicatie “Software updates that address this vulnerability are not yet available.” ↩︎ ↩︎RFC 3715 — IPsec-Network Address Translation (NAT) Compatibility Requirements, maart 2004. Paragraaf 2.1 punt (f) gaat over de SPI-keuze tegenover NAT; paragraaf 2.3 heet Helper Incompatibilities en bevat de geciteerde regels over demultiplexen op IKE-cookies en het ontleden van ISAKMP-payloads. ↩︎ ↩︎
Juniper — IKE and ESP ALG, Application Layer Gateways User Guide. Bron van de beschrijving van het poortje, van de opmerking dat NAT-T-verkeer op poort 4500 niet door het ALG wordt verwerkt, en van de waarschuwing dat het apparaat bij twee clients achter hetzelfde vertaalde adres “will be unable to distinguish and route return traffic properly”. ↩︎ ↩︎
Cisco — IPsec Pass Through Inspection, ASA Firewall CLI Configuration Guide 9.20. “IPsec Pass Through application inspection provides convenient traversal of ESP (IP protocol 50) and AH (IP protocol 51) traffic associated with an IKE UDP port 500 connection.” Staat niet in het standaardbeleid; de meegeleverde
_default_ipsec_passthru_map“sets no maximum limit on ESP connections per client”. ↩︎ ↩︎RFC 3947 — Negotiation of NAT-Traversal in the IKE, en RFC 3948 — UDP Encapsulation of IPsec ESP Packets, beide januari 2005. ↩︎ ↩︎
Cole Dishington — netfilter: nf_conntrack: Add conntrack helper for ESP/IPsec, mei 2021, derde versie. Beoordeeld op netfilter-devel en niet opgenomen;
net/netfilterin de mainline-kernel bevat nog steeds geennf_conntrack_proto_esp.c. ↩︎NCSC en IASME — Cyber Essentials: Requirements for IT Infrastructure v3.3, april 2026. Maatregel 1, Firewalls, geldt voor “boundary firewalls, desktop computers, laptops, routers, servers, IaaS, PaaS, SaaS”, en de drie eisen die in de tekst geciteerd worden zijn haar eigen woorden. ↩︎ ↩︎
RFC 3027 — Protocol Complications with the IP Network Address Translator, januari 2001. “The purpose of this document is to identify the protocols and applications that break with NAT enroute.” ↩︎
WHATWG Fetch — pull request 1109, de wijziging in de standaard die de items voor slechte poorten in alle browsers toevoegde. ↩︎
OpenBSD —
ftp-proxy(8). “ftp-proxy is a proxy for the Internet File Transfer Protocol.” Stuurverbindingen bereiken hem alleen omdat jij ze daarheen gestuurd hebt: “FTP control connections should be redirected into the proxy using the pf(4) divert-to command, after which the proxy connects to the server on behalf of the client.” ↩︎Fortinet — Technical Tip: Disabling VoIP Inspection. Beschrijft het verwijderen van het SIP-item uit
config system session-helper,set default-voip-alg-mode kernel-helper-based, en merkt op dat het weer aanzetten een herstart vereist. ↩︎Mozilla — Stopping FTP support in Firefox 90, 20 juli 2021, en Google — Deprecations and removals in Chrome 95, oktober 2021: “Use of FTP in the browser is sufficiently low that it is no longer viable to invest in improving the existing FTP client.” ↩︎