# Embedded CTF Challenge ## Abstract La challenge e' pensata in tre step, necessariamente consecutivi, che implicano tre vulnerabilita' concettualmente semplici ma di difficolta' facilmente variabile a seconda delle limitazioni imposte. Tecnicamente sono: 1. Generazione di password prevedibile 2. Command Injection 3. Race Condition ## Documentazione Il progetto e' organizzato in un repository Git. Ogni sezione ha un suo Readme con le informazioni necessarie per la comprensione e la modifica delle singole parti. ## Struttura Ad ogni squadra partecipante verra' consegnato un dispositivo gia' attivo, che sara' identificato da un numero seriale inizialmente noto solo agli organizzatori. Ogni dispositivo, sara' collegato all'alimentazione e via ethernet alla rete di monitoring, ed esporra' una rete WiFi di nome `CyberChallenge-ABCD`, dove `ABCD` sono la rappresentazione esadecimale degli ultimi due byte del seriale. Verra' quindi comunicato ad ogni squadra il seriale del dispositivo ad essi assegnato, e verra' pubblicato per tutte le squadre il binario di generazione delle chiavi WPA, cioe' il `keygen`. Per le considerazioni sulla distribuzione del keygen leggere la documentazione relativa. A questo punto, ogni squadra avra' il necessario per poter trovare la chiave WPA solo del proprio dispositivo ed iniziare quindi la challenge. In uno scenario attacco-difesa, dopo la prima fase sara' possibile rilasciare i seriali di tutte le squadre e quindi permettere a tutti quelli che abbiano risolto il primo step di eventualmente collegarsi ai dispositivi altrui. ## Gestione delle informazioni Al momento lo script di build produce una immagino ISO uguale per tutti i dispositivi. E' il `keygen` che al primo boot genera un seriale di 16 byte csuale che viene scritto nel filesystem. Se il `keygen` rileva che e' gia' presente un seriale, non ne generera' un altro a tutte le operazioni successive (generazione del nome della rete e della chiave) saranno sempre uguali. Sara' compito del sistema di monitoring oppure di chi si occupa di preparare i dispositivi raccogliere i seriali e indicizzarli. Ovviamente e' un procedimento che conviene fare prima della gara per verificare che funzioni tutto correttamente. ## Considreazioni di sicurezza Benche' la challenge si possa proteggere in qualche modo, ad esempio bloccando l'ordine di boot in Coreboot e disabilitando il boot da periferiche esterne, rendendo quindi inutile anche l'eventuale utilizzo di un cavo seriale, si presuppone che i partecipanti non possano smontare il case e leggere direttamente il disco mSata. In quel caso qualsiasi protezione sarebbe inutile essendo l'immagine che viene scritta nei dispositivi non cifrata. Inoltre prevenire un attacco di questo tipo risulterebbe particolarmente oneroso in quanto: * Se si sceglie di cifrare il disco risulta poi necessario decifrarlo, inserendo gli organizzatori una chiave all'inizio e ad ogni reboot (umanamente oneroso) oppure facendo si che il bootloader (ed esempio grub) abbia la chiave perimpostata e sblocchi autonomamente il disco (piu' difficile che senza cifratura, ma comunque inerentemente insicuro) * L'unico modo per prevenire questo scenario sarebbe l'utilizzo del TPM, da comprare in aggiunta alle board, e poi l'implementazione misure di protezione necessarie ## Considreazioni pratiche A seconda del numero di partecipanti e delle dimensioni dell'arena di gioco, occorre verificare che tutte le squadre abbiano segnale sufficiente per effettuare una connessione a tutti i dispositivi in gioco, tenendo presente che piu' che un problema di distanza potrebbero verificarsi problemi di interferenze. Occorre quindi integrare un meccanismo che scelga automaticamente il canale su cui esporre la rete wifi in modo da ottimizzare il segnale per tutti. Inoltre, nello scenario di una gara di tipo attacco-difesa occorre implementare un forte sistema di monitoring che verifichi che i dispositivi continuino a funzionare correttamente e che l'exploitation non venga bloccata semplicemendo spegnendo le funzioni del dispositivo. Allo stesso tempo, se si vuole che che ogni team sia in grado di patchare solo il proprio dispositivo e non quello altrui occorre pensare a delle misure aggiuntive che qui non sono descritte. Complessivamente, prevenire qualsiasi tipo di comportamento scorretto in un contesto dove le vulnerabilita' permettono di arrivare al livello di root e' un problema molto complesso, al punto che nel caso attacco difesa si potrebbe valutare una rimodulazione dei privilegi dell'ultimo step. ## Testing E' consigliabile trovare almeno due beta tester per la challenge che sperimentino personalmente che le assunzioni fatte nello sviluppo siano vere e che valutino ls fattibilita' complessiva nei tempi stabiliti. ## Build IL processo di creazione dell'immagine e' stato atuomatizzato con uno script. Per Debian 10, installare ``` sudo apt install -t build-essential libncurses-dev bison flex libssl-dev libelf-dev ``` Nello script di build e' possibile configurare le flag che andranno nell'immagine. Al termine dell'operazione verra' anche creata una coppia di chiavi per firmare gli update e una coppia di chiavi SSH utilizabili per il monitoring. Eseguire da utente normale ``` ./build.sh ``` La iso risultante sara' in `target/buildroot/output/images/rootfs.iso9660`. ## Buildroot Buildroot permette la crazione di una immagine linux minimale (20MB) con solo lo stretto necessario. L'ambiente e' basato su busybox, sono disponibili diversi pacchetti ed e' possibile configurare il kernel. ### Istruzioni manuali per buildroot Installare le dipendenze (debian 10) ``` apt install -t build-essential libncurses-dev bison flex libssl-dev libelf-dev ``` Clonare il repo ``` git clone https://github.com/buildroot/buildroot.git ``` Copiare i files presenti nella cartella `buildroot` di questo repo. ``` make pcengines_apu2_defconfig ``` Per cambiare la configurazione di buildroot (pacchetti, architettura, opzioni di compilazione): ``` make menuconfig ``` Per configurare direttamente il kernel linux ``` make linux-menuconfig ``` Avviare la compilazione ``` make ``` ## Keygen Per un esempio di backdoor reale di questo tipo [vedere qui](https://git.lsd.cat/g/nokia-keygen). Il codice responsabile per la generazione della chiave WPA di ogni dispostivo. Scrive il seriale in `/etc/serial`, il nome della rete in `/etc/ssid` e ila chiave WPA in `/etc/wpa`. E' poi uno script bash a inserirli nella conf di Hostapd. Per ottenere una chiave i partecipanti hanno due opzioni: 1. Effettuare il reverse engineering dell'algoritmo e reimplementarlo di nuovo. Non essendo il codice ne' offuscato ne' particolarmente lungo, premesso che riconoscano la funzione di md5 dovrebbe essere fattibile in un tempo ragionevole. 2. Nel caso che il binario sia per un target `x86` occorre danneggiarlo (ad esempio rimuoverne gli header) in modo che non sia direttamente eseguibile. Allo stesso tempo per altre architetture, occorre introdurre qualche limitazione per cui non sia semplicemente eseguibile con `qemu-static` (ad esempio verificare gli hash di alcuni file nel filesystem, o aggiungere dipendenze a cui l'attaccante non ha accesso). ### Pseudocode ``` function gen_password(mac, serial) { string password seed1 = hex(md5(mac)) seed2 = hex(md5(serial)) len = 32 xorshift(seed1[0:8], seed1[8:16], seed1[16:24], seed1[24:32]) for (i = 0; i < len; i++) { password += seed2[xorshift_get()%20] } return password } ``` ## Webpanel Per un esempio di command injection reale con blacklist [vedere qui](https://legalhackers.com/advisories/nagios-nrpe.html). Il pannello non e' autenticato, e cioe' una volta che un utente sara' connesso alla rete wifi potra' utilizzarlo visitando l'ip del dispostivo alla porta `80`. Il pannello simula molto limitatamente le funzioni base dei classici modem/router casalinghi, una pagina informatica, una pagina per testare la connessione (ping/traceroute) e una pagina per caricare eventuali aggiornamenti. ### Vulnerabilita' In `utils.php` nelle funzioni di ping e traceroute sono presenti delle command injection causate dal mancato utilizzo di `escapeshellarg()`. Normalmente, quando non vengono utilizzate le funzioni precise per effettuare l'escape degli argomenti dei comandi vengono invece utilizzate delle blacklist di caratteri, quasi sempre incomplete. La blacklist di caratteri e' specificata nel file `includes/config.php` e puo' essere piu' o meno completa a seconda delle difficolta' che si vuole stabilire per la challenge. Attualmente risulta configurata cosi': ``` $blacklist = array(';', '#', '(', ')', '|', '&', ' ', "\t", '<', '>'); ``` Come si puo' evincere i normali caratteri che permettono di terminare un comando e iniziarne un altro, cosi' come i carateri din whitespace sono bloccati. Tuttavia e' possibile utilizzare `${IFS}` come whitespace e il newline come command separator. Un esempio di exploit e' il seguente: ``` curl http://192.168.77.1/utils.php --data $'action=ping&host=127.0.0.1\nuname${IFS}-a' ``` ### Update La pagina di update suggerisce di guardare lo script di update la cui vulnerabilita' permette di acquisire la terza flag. Tuttavia per sfruttare tale vulnerabilita' e' richiesta una reverse shell e non e' quindi possibile solo tramite il pannello web. ### Flag Nella home page del pannello web viene rivelata la prima flag, che viene impostata dallo script di build in `includes/config.php`. E' chiaro che un attaccante puo' accedere a questa flag solo dopo essersi connesso via wifi. La flag della command injection e' invece inserita nel filesystem in fase di build. ## Update ### Intro Questo script consiste nell'ultimo step della challenge. Questo script viene eseguito con `sudo` dall'interfaccia nella pagina di aggiornamento firmware. Da inserire in `/etc/sudoers`: ``` www-data ALL=(root) NOPASSWD: /bin/bash /root/update.sh ``` Per generare la chiave per firmware le immagini: ``` openssl genrsa -out key.pem 2048 openssl rsa -in key.pem -outform PEM -pubout -out pub.pem ``` Per firmare un file: ``` openssl dgst -sha256 -sign private.pem -out update.tgz.sig update.tgz cat update.tgz.sig > update.tgz.cc cat update.tgz >> update.tgz.cc ``` ### Vulnerabilita' La vulnerabilita' presente e' una race condition di tipo time-of-check to time-of-use, ovvero la firma del pacchetto di update viene controllata in un punto del codice e poi estratto successivamente.. C'e' quindi una brevissima finestra di tempo in cui un attaccante puo' sostituire il pacchetto con uno non firmato. Il bug si potrebbe prevenire ad esempio garantendo che una volta iniziata la procedura il file non possa essere modificato da utenti non privilegiati modificandone i permessi.