Stavo testando un port-scanner per Android che mi dice, correttamente, che uno dei miei dispositivi ha la porta 53 aperta (è il Pi-hole). Scorrendo, tocco erroneamente il numero di porta e l’app apre quindi l’URL 192.168.1.2:53, dandomi un errore particolare: “ERR_UNSAFE_PORT”, con una classica schermata di pagina non raggiungibile.

Firefox, invece, mostra un ben più allarmante

Porta bloccata per motivi di sicurezza

L’indirizzo richiesto specificava una porta (per es. " Mozilla.org:80” per la porta 80 su mozilla.org) normalmente utilizzata per scopi diversi dalla navigazione sul web. Il browser ha annullato la richiesta per garantire la protezione e la sicurezza dell’utente.

Non conoscevo tale comportamento: ha ovviamente senso non mandare traffico HTTP (o TLS) a un mailserver o ad una sessione Telnet, e tale traffico potrebbe addirittura disturbare programmi scritti non particolarmente bene.

Ma questa attenzione da parte dei browser mi porta a supporre che ci sia una valida ragione di sicurezza, d’altronde i messaggi d’errore si riferiscono esplicitamente a quello.

Infatti, così è: non bloccare queste porte semplificherebbe nettamente attacchi del tipo HTML Form Protocol Attack, permettendo al browser di diventare un vero e proprio proxy aperto. Tale rischio è stato segnalato a Mozilla nel 2001, portando alla rapida modifica del browser…

Mandar dati arbitrari a qualsiasi porta TCP con un semplice browser (basta che il protocollo sia testuale)

Come forse saprete, HTTP si esprime con semplici comanti in testo semplice: penso che chiunque abbia studiato reti abbia fatto la prova di contattare un server web con netcat o simili e ottenere l’HTML. D’altronde, basta un:

GET /echo HTTP/1.1
Host: sciretti.eu
Accept: */*

Anche altri protocolli utilizzano il testo semplice, ad esempio SMTP, dov'è uso comune utilizzare Telnet per funzioni di debug. Un esempio, abbastanza classico:

HELO local.domain.name
250 smtp.domain.ext Hello local.domain.name [xxx.xxx.xxx.xxx], pleased to meet you
MAIL FROM: sender@adress.ext
250 2.1.0 sender@adress.ext... Sender ok
RCPT TO: recipient@adress.ext
250 2.1.5 recipient@adress.ext... Recipient ok
SUBJECT: Test message

Hello,
sciretti.eu is the best site of the world
.
250 2.0.0 ???????? Message accepted for delivery
QUIT
221 2.0.0 server.com closing connection

Che invia direttamente un’email. Il client mail medio si occupa di automatizzare questo scambio.

Io, form

Se conoscete l’HTML conoscerete anche il concetto di form, ossia un elemento che permette di inserire dei dati e di inviarli a un server per una successiva elaborazione (o anche di usarli lato client, ma diciamo che quando è stata scoperta tale vulnerabilità non era una cosa particolarmente diffusa).

Ora, immaginate di collegarvi col browser a un server SMTP: ovviamente non riconoscerebbe le classiche parole chiave di HTTP, però non rifiuterebbe la connessione: d’altronde, entrambi i protocolli usano il testo semplice e separano ogni comando con una nuova linea.

Cosa accadrebbe, dunque, se si riuscisse a mandare, tramite un form, una serie di dati che non hanno un chiaro senso per il browser, ossia dei banali campi di testo, ma sembrano comandi ad un mail server? Utilizzando la classica codifica application/x-www-form-urlencoded, non è possibile, poiché codifica i ritorni a capo con i codici HTML. Ma utilizzando multipart/form-data, è possibile invece inserire vari testi, spaziati con una nuova riga, che verranno interpretati dal server SMTP come comandi, mentre i campi di controllo HTTP saranno semplicemente ignorati.

Alcuni server si son fatti furbi e terminano immediatamente la connessione se rilevano una connessione HTTP, ma se così non fosse basterebbe convincere il browser a mandare un form (non è difficile, lo lascio come esercizio al lettore, che sia con JavaScript o con un po’ di ingegneria sociale) appositamente costituito per inviare un’email, un’azione sufficiente a superare protezioni semplici come un firewall che impedisce agli utenti esterni l’accesso ad un dato server. Con una vulnerabilità del genere si ottiene la possibilità di inviare dati ad ogni servizio a cui il computer vulnerabile può accedere, purché usi un protocollo abbastanza simile ad HTTP. Questo sistema d’attacco è stato denominato anche “cross-protocol scripting”, ma tale termine non ha avuto particolare successo.

Se l’email non vi sembra un obiettivo appetibile, evidentemente non vi rendete conto di quanto venga ritenuta un mezzo fidato nella nostra vita informatica, immaginate, in ogni caso, un’email mandata all’insaputa del ragionere dell’ufficio sinistri in cui dice alla mailing list di tutta l’azienda che “il megadirettore è uno stronzo”, o un link alle prove di un tradimento inviato dal computer di qualcuno così che sembri il responsabile della scoperta. Vai a spiegarlo, dopo, che è stato il “form multipart/form-data” a inviarla e non tu. Oppure, cosa possibile con un server POP, trovarsi tutte le e-mail cancellate, magari in un’azienda dove l’ultimo sistemista se n'è andato in pensione sei mesi fa e ora c'è quel collega che è tanto bravo con i computer a sostituirlo e a fare i backup…

Se ancora non siete convinti, con il cross-protocol scripting si possono contattare server FTP e, forse, calcolatori remoti con Telnet. Sarebbe stato dunque possibile rubare file da un server FTP altrimenti protetto, oppure prendere il controllo - conscendo la password (e se il computer non è accessibile dall’esterno un certo lassismo è prevedibile, chiedete a Conficker) - di un computer tramite Telnet e utilizzarlo come testa di ponte per qualcos’altro, installandoci malware magari (per quanto va detto che sulla possibilità di attaccare Telnet ci sono legittimi dubbi e non mi risulta sia mai stato provato, resta comunque una possibilità, tanto da portare gli sviluppatori a bloccare la sua porta).

La soluzione: chiudere le porte

Alcune porte sono, essenzialmente per standard, riservate a determinati scopi. In linea di massima, permessi di root permettendo, nulla vieta di mettere un web server sulla porta 23, ma chi lo fa non dovrebbe decisamente sviluppare software, specie accessibile a tutto il mondo.

Alle volte, però, gli sviluppatori scelgono porte che apparentemente sembrano inoffensive e spesso soddisfano un certo umorismo malato del BOFH, tipo la 6666, che però risulta bloccata. Tranquilli, non c'è dietro alcuna superstizione né Bill Gates che coi soldi dei microchip nel vaccino fa orge sataniche e ha scelto di onorare così Bafometto: quella porta è utilizzata da alcune implementazione di IRC ed Apple ne ha richiesto il blocco.

Per di più, alle volte, i produttori di browser debbono bloccare porte alla bisogna, per rispondere a determinati malware o exploit che ne fanno uso: ad esempio, tra il 2020 e il 2021, Firefox e Chrome hanno bloccato la porta 10080 contro NAT Slipstreaming

Nel 2016, invece, Bouke van der Bijl ha mostrato come con una variante della tecnica è possibile, sfruttando anche un DNS rebinding, sottrarre database Redis, rilasciando anche un semplice PoC. Tale attacco, in ogni caso, funziona solo con lo standard HTTP/0.9, poiché non invia header e ogni risposta senza di essi viene presunta tale. Chrome ha, dalla versione 55, eliminato il supporto a HTTP/0.9 eccetto che sulle porte standard, mitigando il problema, proprio su indicazione di van der Bijl.

Insomma, dopo vent’anni dalla scoperta qualcuno prova ancora ad utilizzare il browser come ariete nelle reti locali, ed è la vigilanza costante degli sviluppatori dei browser a tenerci al sicuro da attacchi molto semplici ma che potrebbero rivelarsi dannosi.

Alcuni test

Così, per sport, ho provato a far due cose:

  • Avviare un server web (quello di debug che viene offerto con PHP) su una porta protetta (23)
  • Avviare un servizio protetto su una porta non protetta (un server FTP ottenuto al volo con il modulo Python pyftpdlib)

Nel primo caso, sia Firefox Mobile che Chrome Mobile si son rifiutati di visualizzare la pagina, essenzialmente manca un check che verifichi l’eventualità che dall’altro lato ci sia comunque un server web (cosa comunque facilmente constatabile dal codice, almeno quello di Chrome, linkato nei riferimenti).

Nel secondo caso, Chrome si rifiuta di visualizzare la pagina, dichiarando che la risposta non è HTTP valido (per la ragione spiegata qualche paragrafo fa), mentre Firefox prova a comunicare, restituendo ciò:

220 pyftpdlib 1.5.6 ready.
500 Command "GET" not understood.
500 Command "HOST:" not understood.
500 Command "USER-AGENT:" not understood.
500 Command "ACCEPT:" not understood.
500 Command "ACCEPT-LANGUAGE:" not understood.
500 Command "ACCEPT-ENCODING:" not understood.
500 Command "CONNECTION:" not understood.
500 Command "UPGRADE-INSECURE-REQUESTS:" not understood.
500 Command "" not understood.

In sostanza, se utilizzare una porta meno nota e non standard, pratica spesso consigliata per evitare tentativi automatizzati di intrusione, rischiate di perdere la protezione del browser. Improbabile, certo, ma da tenere chiaramente a mente durante la propria attività di threat modeling. Nulla vi vieta, in ogni caso, di inserire nei browser le vostre porte personalizzate da proteggere, anche se ciò potrebbe rendere necessaria la compilazione…

Alcune porte bloccate

Per l’elenco totale delle porte bloccate potete guardare il codice sorgente di Chrome linkato, mentre il documento di Mozilla non è del tutto aggiornato: le più rilevanti sono la 1 (tcpmux), 13 (daytime), 15 (netstat), 20 e 21 (ftp), 22 (ssh), 23 (telnet), 25 (smtp), 53 (DNS), 79 (finger), 109 e 110 (POP2 e POP3), 115 (sftp), 123 (NTP), 143 (IMAP), 179 (BGP), 389 (ldap), 465 (smtp crittografato), 989 e 990 (ftps), 995 (pop3 crittografato), 2049 (nfs), 6000 (X11), 6566 (sane) e il range 6665-6669 e la porta 6697, utilizzata come detto in precedenza da IRC.

Ovviamente, queste porte sono limitate solo se l’accesso avviene via HTTP(S): se il vostro browser supporta ancora FTP è ovviamente possibile accedere alla porta 21 con quello, ma ormai sia Chrome che Firefox, nelle ultime versioni, hanno eliminato il supporto a tale protocollo, ritenuto deprecato, dopo un supporto esteso durante i primi mesi della pandemia da Covid-19, per permettere alle organizzazioni sanitarie di gestire i propri documenti FTP dal browser in maniera più semplice.

L’ennesima picconata alle origini della Rete, verrebbe da dire, ma se persino io che sono un nerd non me ne sono accorto sino ad oggi, forse non è una rinuncia così importante…

Conclusioni

Verrebbe da dire che è compito di chi sviluppa server “a rischio” il renderli più sicuri, un po’ come nel caso del XSS o dei CSRF, dove la maggioranza delle contromisure sono lato server. Alle volte, però, è bene che il browser faccia il suo per garantire la sicurezza (si veda la Same-Origin Policy).

Proprio nel caso delle XSS, Chrome ha mantenuto per anni un filtro che avrebbe provato ad identificarle e fermarle, poi rimosso per l’eccessiva complessità a fronte dei benefici.

Tuttavia, un filtro del genere basato sulle porte è poco invasivo, probabilmente nemmeno notato dalla stragrande maggioranza dell’utenza e aiuta a mantenere la sicurezza in rete. Insomma, per il costo minuscolo di averlo, il beneficio mi sembra elevato.

In ogni caso, tutto ciò che qui ho spiegato a parole (più o meno semplici) lo trovate nel paper linkato qui sotto, il primo nella lista, che contiene anche esempi di come usare i form per attacchi del genere.

Tra l’altro…

In alcuni casi, si possono sottrarre informazioni personali con tecniche del genere, com'è ben spiegato nel “Cure53 Browser Security White Paper” del 2017, che vi consiglio di leggere.

Riferimenti