I ricercatori dell'Università di Cambridge hanno pubblicato una tecnica per l'inserimento invisibile di codice dannoso nei testi sorgente sottoposti a revisione. Il metodo di attacco preparato (CVE-2021-42574) è presentato con il nome di Trojan Source e si basa sulla creazione di testo che appare diverso per il compilatore/interprete e per una persona che visualizza il codice. Esempi di applicazione del metodo sono stati dimostrati per vari compilatori e interpreti forniti per i linguaggi C, C++ (gcc e clang), C#, JavaScript (Node.js), Java (OpenJDK 16), Rust, Go e Python.
Il metodo si basa sull'uso di caratteri Unicode speciali nei commenti al codice, che cambiano l'ordine di visualizzazione del testo bidirezionale. Con tali caratteri di controllo, alcune parti del testo possono essere visualizzate da sinistra a destra, mentre altre da destra a sinistra. Nella pratica quotidiana, questi caratteri di controllo possono essere utilizzati, ad esempio, per inserire nel file di codice righe in lingua ebraica o araba. Ma se si combinano righe con direzioni di testo diverse in una sola riga usando i caratteri suddetti, i segmenti di testo visualizzati da destra a sinistra possono sovrapporsi al testo normale visualizzato da sinistra a destra.
Utilizzando questo metodo, è possibile aggiungere una costruzione dannosa al codice, ma poi rendere invisibile il testo contenente tale costruzione durante la visualizzazione del codice, aggiungendo in un commento successivo o all'interno di un letterale caratteri che vengono visualizzati da destra a sinistra, il che porterà alla sovrapposizione della parte dannosa con altri simboli completamente diversi. Tale codice rimarrà semanticamente corretto, ma verrà interpretato e visualizzato in modo diverso.

Durante la revisione del codice, il sviluppatore si imbatterà nell'ordine visivo di uscita dei caratteri e vedrà in un moderno editor di testo, interfaccia web o IDE un commento che non suscita sospetti, ma il compilatore e l'interprete utilizzeranno l'ordine logico dei caratteri e tratteranno l'inserimento dannoso esattamente per quello che è, senza prestare attenzione al testo bidirezionale nel commento. Questa problematica colpisce vari editor di codice popolari (VS Code, Emacs, Atom), così come le interfacce per la visualizzazione del codice nei repository (GitHub, Gitlab, BitBucket e tutti i prodotti Atlassian).

Vengono identificati diversi modi di utilizzare il metodo per attuare azioni dannose: l'aggiunta di un'espressione nascosta 'return', che porta a terminare l'esecuzione della funzione prematuramente; l'inserimento in un commento di espressioni che sono normalmente visibili come costrutti attivi (ad esempio per disabilitare importanti controlli); l'assegnazione di valori stringa diversi che portano a errori nel controllo delle stringhe.
Ad esempio, un attaccante potrebbe proporre una modifica che include la linea: if access_level != "user{U+202E} {U+2066}// Check if admin{U+2069} {U+2066}" {
che verrà visualizzata nell'interfaccia per la revisione come if access_level != "user" { // Check if admin
Inoltre, è stata proposta un'altra variante di attacco (CVE-2021-42694), legata all'uso di omoglifos, caratteri che sembrano simili nella forma ma differiscono nel significato e hanno codici unicode diversi (ad esempio, il carattere 'ɑ' assomiglia a 'a', 'ɡ' a 'g', 'ɩ' a 'l'). Tali caratteri possono essere utilizzati in alcuni linguaggi nei nomi di funzioni e variabili per ingannare gli sviluppatori. Ad esempio, possono essere definite due funzioni con nomi indistinguibili che eseguono azioni diverse. Senza un'analisi dettagliata, non è immediatamente chiaro quale di queste due funzioni venga chiamata in un determinato punto.

Come misura di protezione, si raccomanda di implementare nei compilatori, interpreti e strumenti di build che supportano caratteri Unicode, l'emissione di errori o avvisi in presenza di caratteri di controllo dispari nei commenti, nei letterali stringa o negli identificatori, che alterano la direzione di output (U+202A, U+202B, U+202C, U+202D, U+202E, U+2066, U+2067, U+2068, U+2069, U+061C, U+200E e U+200F). Tali caratteri dovrebbero anche essere esplicitamente vietati nelle specifiche dei linguaggi di programmazione e dovrebbero essere considerati negli editor di codice e nelle interfacce di gestione dei repository.
Aggiornamento 1: Correzioni per risolvere la vulnerabilità sono state preparate per GCC, LLVM/Clang, Rust, Go, Python e binutils. Il problema è stato anche risolto da GitHub, Bitbucket e Jira. È in preparazione una correzione per GitLab. Per identificare il codice problematico, si consiglia di utilizzare il comando: grep -r $'[]' /path/to/source
Supplemento 2: Russ Cox, uno dei programmatori del sistema operativo Plan 9 e del linguaggio di programmazione Go, ha criticato l'eccessiva attenzione rivolta al metodo di attacco descritto, che è già noto da tempo (Go, Rust, C++, Ruby) e non è stato preso sul serio. Secondo Cox, il problema riguarda principalmente la correttezza della visualizzazione delle informazioni nei codici e nelle interfacce web, e può essere risolto utilizzando strumenti e analizzatori di codice adeguati durante le revisioni. Pertanto, invece di attirare l'attenzione su attacchi ipotetici, sarebbe più opportuno concentrarsi sul miglioramento dei processi di revisione del codice e delle dipendenze.
Russ Cox sostiene anche che i compilatori non siano il luogo giusto per affrontare il problema, poiché vietare caratteri pericolosi a livello di compilatore lascia un ampio ventaglio di strumenti in cui l'uso di tali caratteri rimane consentito, come sistemi di build, assembler, gestori di pacchetti e vari parser di configurazione e dati. Ad esempio, nel progetto Rust è stato vietato il trattamento del codice LTR/RTL nel compilatore, ma non è stata aggiunta una correzione nel gestore di pacchetti Cargo, il che consente di effettuare un attacco simile tramite il file Cargo.toml. Analogamente, fonti di attacco possono includere file come BUILD.bazel, CMakefile, Cargo.toml, Dockerfile, GNUmakefile, Makefile, go.mod, package.json, pom.xml e requirements.txt.
Fonte: opennet.ru
