Fuzzing e sicurezza dei DNS: Synopsys e il caso BIND 9

Tutti coloro che si occupano di sviluppo software devono prendere delle decisioni fondamentali che vanno dalla selezione di componenti di terze parti alla scelta di processi e strumenti capaci di garantire resilienza e sicurezza. In questo articolo vediamo come un team di sviluppo ISC gestisce gli aspetti di sicurezza attraverso BIND 9, un’applicazione divenuta ormai fondamentale nella moderna Internet.

Cos’è BIND 9 e il ruolo dell’ICS

BIND 9 è un name server, un’applicazione che traduce i nomi di dominio web, leggibili dall’uomo, nei loro equivalenti numerici. Ad esempio, se digito isc.org nel mio browser, il mio computer richiede l’indirizzo IP corrispondente a tale dominio. La comunicazione tra il mio computer e il name server si svolgerà attraverso un protocollo di rete chiamato Domain Name System o DNS e la conversazione si presenterà così:

Il mio computer: Hey, qual è l’indirizzo corrispondente a isc.org?
Name server: Ok, isc.org si trova al 149.20.1.66.

Una volta ottenuto tale indirizzo, il mio computer potrà connettersi direttamente al server e richiedere la pagina web di ISC.

Le funzionalità complete di BIND 9 sono però molto più complesse di quelle appena descritte e includono la memorizzazione nella cache, l’inoltro delle richieste, il bilanciamento del carico, molteplici protocolli di sicurezza e plug-in.

BIND 9 viene utilizzato da numerosi name server di tutto il mondo, vista l’ampia diffusione e siccome l’ascolto sulle query di rete in arrivo è intrinsecamente pericoloso, la sicurezza ricopre un ruolo di vitale importanza in tale applicazione.

BIND 9 è un software open source gratuito disponibile con licenza MPL 2.0 e sviluppato dall’Internet Systems Consortium (ISC), un’organizzazione non a scopo di lucro fondata nel 1994 con il preciso fine di continuare a lavorare su BIND.

Una delle sfide che i team ISC si trovano ad affrontare riguarda la longevità di BIND 9 che, sé contato in anni umani, corrisponde a circa 24 anni, che se relazionato alla storia di Internet potrebbero risultare un milione. Gran parte delle 683.000 righe di codice di BIND 9 sono state scritte in un’epoca diversa, più semplice se confrontata alla complessità del mondo virtuale di adesso, quando Internet era un luogo più amichevole e i cyber criminali erano pochi e meno esperti.
Dato che BIND è open source e scaricabile gratuitamente in modo anonimo da chiunque, nessuno sa quanti siti, ad oggi, lo stiano adoperando, su quale hardware o software, come lo stiano utilizzando e quindi quali funzionalità o configurazioni dovrebbero essere testate. Per far fronte a tutti questi fattori, si rende indispensabile l’utilizzo di tecnologie capaci di realizzare test automatizzati da parte del team di sviluppo.

Approccio olistico alla sicurezza del software

Rendere BIND 9 una parte sicura e resiliente del server DNS richiede l’integrazione della sicurezza in ogni sua fase di sviluppo. Con un team di sviluppatori di sole nove persone, tre delle quali dedicate al controllo della qualità, questa risulta una sfida ambiziosa. In quanto progetto open source, tuttavia, BIND 9 può sfruttare le preziose risorse della comunità.

Il team di BIND 9 esegue i test in due fasi del processo di sviluppo: nel momento in cui ci sono modifiche al codice sorgente (che si verificano come richieste di merge) e durante le pipeline notturne.

Le Merge Request si verificano durante ogni fase del ciclo di sviluppo. In genere, uno sviluppatore crea un nuovo branch in git per implementare una funzionalità o correggere un bug, quindi una volta terminato il proprio lavoro, invia una richiesta di merge per integrare nuovamente le modifiche nel brunch release principale. Per ogni merge request, il sistema di integrazione continua (CI) di BIND 9 esegue una varietà di tool, testing d’unità e test di sistema, per un totale di oltre 70 controlli.

Analisi Statica per aumentare il livello di sicurezza del codice

Un potente strumento per i test di sicurezza è l’analisi statica che viene effettuata attraverso mezzi automatizzati in grado di esaminare il codice sorgente di un’applicazione al fine di segnalare potenziali problemi. Questa metodologia di controllo è chiamata test di sicurezza delle applicazioni statiche (Static Application Security Testing, SAST) e include una gamma di soluzioni: strumenti molto semplici, che forniscono un controllo sulla presenza di pattern, e opzioni più sofisticate, in grado di creare una rappresentazione ad albero della struttura sintattica astratta del codice, capace di eseguire l’analisi interprocedurale e seguire il data flow all’interno dell’applicazione.

Ad esempio, un semplice strumento SAST (o grep) può dirti se hai usato una funzione non sicura come strcpy() quando probabilmente avresti dovuto usare strncpy(), mentre uno strumento SAST migliore può dirti se hai del codice irraggiungibile, errori logici off-by-one, potenziali deadlock o molti altri tipi di bug.

In un certo senso, il compilatore stesso fornisce un’analisi statica, poiché segnala una serie di situazioni che potrebbero causare problemi nell’applicazione. Il team di BIND 9 sfrutta la potenza del compilatore gestendo ogni avvertimento come errore di compilazione. Inoltre, il codice sorgente viene realizzato utilizzando due diversi compilatori, gcc e clang. Gli avvisi di entrambi i compilatori non possono essere ignorati.

Oltre a ciò, le pipeline di build di BIND 9 incorporano strumenti che aiutano a garantire l’igiene del codice sorgente. Coccinelle, ad esempio, aiuta a garantire la coerenza dello stile di codifica, mentre Danger fa rispettare le convenzioni durante il processo di sviluppo.

Funzionalità SAST complete sono fornite dalla soluzione Coverity SCAN che offre gratuitamente ai progetti open source tutta la potenza di Coverity. Il team di BIND 9 è proattivo nell’affrontare le scoperte di Coverity, in grado di fornire un set di risultati straordinariamente chiari: https://scan.coverity.com/projects/bind-v9_18

Gli sviluppatori di BIND 9 utilizzano anche altri strumenti che costringono ad un codice pulito, coerente e che lavori correttamente. Qualora ci si chiedesse “perché non si procurano una sola soluzione SAST davvero buona” la risposta è semplice, strumenti diversi garantiscono risultati diversi. L’esecuzione di più tools, a seconda delle esigenze, e la gestione dei diversi risultati fornisce la migliore protezione per l’applicazione.

Test di sicurezza

Uno dei punti di forza di BIND 9 è una solida suite di test, inclusi test di unità, sistema e prestazioni. Le pipeline di compilazione eseguono i test in una varietà di configurazioni, sfruttando appieno le funzionalità del compilatore come AddressSanitizer e ThreadSanitizer.

Il risultato è una matrice di test, con unit test eseguiti su binari creati con gcc e clang per più piattaforme. Gli unit test vengono eseguiti anche sui file binari creati con Address Sanitizer abilitato, sui file binari con Thread Sanitizer abilitato e così via.

Fuzz testing per la cyber security

Il test funzionale è, la maggior parte delle volte, un test positivo, ciò significa che i controlli sono impostati per fornire input validi e l’output viene confrontato con un valore corretto o previsto.
Il test funzionale verifica che tutto lavori correttamente in circostanze normali. Ma cosa succede se utenti o sistemi inviano input non funzionanti o quando gli attaccanti mettono alla prova l’applicazione alla ricerca di punti deboli?

Il fuzzing è un test negativo ed è complementare al test funzionale. Fornisce input e controlli deliberatamente non corretti per vedere se si verifica un errore. Ciò ha particolarmente valore per le applicazioni connesse a Internet come BIND 9 che, probabilmente, incontreranno tanti tipi di input sbagliati.

BIND 9 è impostato per utilizzare due fuzzer open source: American Fuzzy Lop (ALF) e libFuzzer. Entrambi sono fuzzer integrati e coverage-guided. Ciò significa che creano casi di test (input), eseguono tali input in una funzione del punto di ingresso nell’applicazione e controllano se si verifica un arresto anomalo del processo. I test case vengono mutati per creare nuovi test case e quando viene scoperto un nuovo percorso, viene eseguita una nuova serie di mutazioni.

L’anno scorso, il team del Synopsys Cybersecurity Research Center ha eseguito il protocollo DNS fuzzing con Defensics, lavoro che ha portato allo sviluppo di BIND 9.17.7 oltre che alla scoperta di una vulnerabilità. Gli sviluppatori di BIND 9 hanno una lunga storia di collaborazione con Defensics, cominciata con il rilevamento di una vulnerabilità situata in BIND 9.10.0 nel 2014.

Defensics esegue il fuzz testing in modo molto diverso da AFL e libFuzzer, ma il principio alla base è lo stesso, utilizza un modello di dati del protocollo di rete interno per creare casi di test. Sa esattamente come dovrebbe apparire ogni campo di ogni messaggio in base alle specifiche del protocollo, il che significa che Defensics può creare casi di test molto realistici ma ancora anonimi.

Defensics fornisce casi di test sulla rete lavorando con precisione sulla superficie di attacco esposta dell’applicazione. Monitora l’applicazione testata per gli arresti anomali del processo, ma può anche essere configurato per cercare errori di memoria, altri tipi di consumo di risorse e altri indicatori di integrità dell’applicazione.

Come con SAST, differenti fuzzer trovano bug diversi, quindi l’esecuzione di più tipi di fuzz testing può aiutare a scovare un maggior numero di vulnerabilità e ridurre il rischio complessivo.

Un modo in cui gli sviluppatori di BIND 9 possono rassicurare gli utenti che il loro software è privo di evidenti vulnerabilità è rendendo pubblici i risultati dei test in corso, tramite “badge” pubblicati nel repository aperto che si collegano allo stato più recente. Notare il badge in Figura 1 che indica uno stato “passato” con Coverity.

Figura 1: I risultati dei test in corso vengono pubblicati nel repository aperto con un collegamento allo stato più recente.

Mettere in sicurezza la Supply Chain del software open source

La sicurezza della supply chain del software è un argomento caldo, del quale fa parte un concetto importante, quello della distinta base del software (Software Bill of Materials, SBOM), cioè l’elenco dei componenti open source che fanno parte di un’applicazione.

BIND 9 è alquanto insolito in quanto non ha componenti open source integrate. Detto questo, ha alcune dipendenze dinamiche nei componenti software che invoca a runtime, inclusi Libuv, Libcrypto, OpenSSL e qualcun altro. In quanto dipendenze dinamiche, queste provengono dall’ambiente di runtime in cui è distribuito BIND 9 e, per le organizzazioni che eseguono BIND 9, l’ambiente di distribuzione fa parte della supply chain tanto quanto qualsiasi altra cosa.

Per i consumatori downstream di BIND 9, il team di sviluppo ha recentemente aggiunto, ai suoi file di origine, i tag di licenza SPDX. Ciò significa che oltre a distribuire il testo della licenza BIND 9 con il codice sorgente, ogni file sorgente include anche un SPDX-License-Identifier inequivocabile in un commento come questo:

/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * SPDX-License-Identifier: MPL-2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 */

Il tag MPL-2.0 aiuta i consumatori downstream ad identificare la licenza del codice sorgente di BIND 9 ed è facilmente rilevabile da strumenti automatizzati. Sebbene BIND 9 sia distribuito sotto forma di codice sorgente, sempre più utenti saltano il lavoro di compilazione, optando invece per installare e distribuire immagini preconfezionate da varie fonti, inclusi pacchetti ISC, “volontari” che pubblicano pacchetti su Internet e fornitori di applicazioni. Questo è esattamente il tipo di scenario per cui è progettato SBOM: in questo caso, BIND 9 sarebbe un componente elencato nell’applicazione.

Best practice di sicurezza per BIND 9

Il team di BIND 9 raggiunge un elevato livello di robustezza e sicurezza utilizzando un processo intriso di test funzionali e best practices di sicurezza:

  • Il codice solido e i processi di igiene sono integrati nel processo di sviluppo e realizzati con più strumenti.
  • Il test SAST viene eseguito regolarmente utilizzando Coverity SCAN e tutti i risultati vengono presi in considerazione.
  • Un’unità completa e una suite di test di sistema viene eseguita su una matrice di compilatori e sanitizers.
  • Molteplici fuzzer subissano l’applicazione con input mal formati e non validi.
  • I test di sicurezza sono automatizzati all’interno del processo di sviluppo.

Tutte queste best practice andranno a beneficio di quasi tutti i team di sviluppo, ma sono necessari anche altri tipi di test di sicurezza. Ad esempio, molte applicazioni fanno un uso massiccio di componenti software open source, in questo caso gli strumenti di analisi della composizione del software (Software Composition Analysis, SCA) sono fondamentali, mentre per le applicazioni web i test di sicurezza delle applicazioni interattive (Interactive Application Security Testing, IAST) sono un’importante tecnologia di test dinamici.

Volendo anticipare il futuro, il team di BIND 9 continuerà sicuramente ad ampliare e migliorare le sue solide e robuste fondamenta basandosi sulla sicurezza e automatizzando sempre più attività, eseguendo nuovi test e incorporando strumenti innovativi.

Condividi sui Social Network:

Articoli simili