Così Ho Preso il Controllo dei Compilatori Online
Pubblicato il – 4 minuti di lettura – 765 parole

Molti compilatori online permettono di risparmiare tempo e risorse all’utente, facilitandolo lo sviluppo e l’apprendimento di programmini semplici come “Hello world” nei vari linguaggi di programmazione. Premetto che anche io non amo scaricare tutte le mie risorse per un compilatore e uso molto spesso uno online se l’esercizio è molto semplice.
Partendo dal presupposto che un compilatore online banalmente non è altro che un compilatore in remoto con un interfaccia web, si può ipotizzare che iniettando dei comandi si possa avere un certo controllo della macchina; dei compilatori analizzati dal sottoscritto, molti potevano eseguire codice senza filtering e teoricamente avendo un controllo sufficiente per exploitarla.
Abusando infatti di alcune funzioni built-in di C e librerie POSIX, execl()
, system()
, and GetEnv()
è possibile eseguire qualsiasi comando nella shell built-in del sistema operativo sul quale la piattaforma web è basata.
Descrizione della vulnerabilità
In alcuni compilatori C/C++ online, tramite system()
, getenv()
e fork()
è stato possibile eseguire qualsiasi tipo di comando, questo identifica un controllo completo della macchina remota; La vulnerabilità da me scoperta è “Command Injection”, per cui era possibile trovare la versione del OS in uso, il nome dell’utente e si poteva accedere a file sensibili tra cui log, file in uso dal sito web e molto altro.
Compilare pero’ il programma ogni volta per eseguire 100 comandi non è una scelta saggia, dato che i tempi di compilazione sono lunghi e potrebbe essere lasciata una traccia. La funzione execl() della libreria permette di sostituire il programma corrente con un programma specificato. Se si utilizzasse /bin/sh
come parametro per la funzione execl() e il compilatore online avesse un interfaccia per l’input, si potrebbe sviluppare un programma che relaya i commandi in input alla shell built-in.
In alcuni casi, i compilatori permettevano l’input da interfaccia web; tramite la funzione execl() è stato possibile aprire una shell via browser, senza compilare ogni qual volta si voleva “esplorare” l’ambiente sostituendo le varie istruzioni su system()
.
Una volta trovate le informazioni tramite getenv(), si poteva benissimo eseguire un qualsiasi tipo di exploit per cercare di ottenere una shell con root; inoltre, tramite la funzione fork(); e un semplice ciclo while(true) era possibile eseguire un self DoS Attack: la funzione fork continua a dividere il processo all’infinito, consumando così preziosa memoria RAM.
Seppur alcuni compilatori avessero un ambiente sandboxato e i tecnici avessero adottato delle tecniche avanzate per bloccare richieste di editing sui file, si è reso possibile iniettare inoltre un miner di cryptocurrency.
La teoria
Questa sezione documenta i comandi utilizzati per ottenere e mantenere l’accesso al compilatore online. Queste funzioni richiedono le librerie unistd.h e stdlib.h.
La funzione execl()
Dichiarazione
int execl(const char *pathname, const char *arg, ...);
Parametri
pathname - char*, variabile che indica un programma eseguibile (binario) o uno script che dovrà sostituire il processo corrente
arg - char*, argomenti passati al programma eseguibile specificato da pathname
Descrizione
La funzione execl() sostituisce il processo corrente con un nuovo processo. In realta’ le funzioni sono un’interfaccia per la funzione execve() a cui si rimanda per ulteriori approfondimenti.
system()
Dichiarazione
int system(const char* command);
Parametri
command - char* nome del comando
Descrizione
La funzione C system passa il nome del comando, specificato da command, alla shell built-in dell’host ( /bin/sh per sistemi basati su UNIX) che provvede ad eseguirlo. La funzione è basata su execl(), per cui quando system() viene chiamato si esegue:
execl(, "sh", "-c", command, (char *)0);
Return
La funzione risponde con l’output del comando, dopo che è stato eseguito; ritorna inoltre un valore numerico -1 nel caso in cui la shell abbia incontrato errori nell’esecuzione del comando.
GetEnv()
Dichiarazione
char *getenv(const char *name)
Parametri
name - const char* nome della variabile dell’ambiente; il parametro può essere case sensitive in alcuni ambienti operativi.
Descrizione
Recupera una stringa C contenente il valore della variabile di ambiente il cui nome è specificato come argomento ( name ).
Return
La funzione ritorna il contenuto della variabile d’ambiente richiesta sottoforma di stringa; in caso di errori restitiusce un pointer nullo.
Proof of Concepts
#include "stdio.h"
#include "unistd.h"
int main(){
execl("/bin/sh",NULL,NULL); // Open the shell
return 0;
}
#include "stdio.h"
#include "stdlib.h"
int main(){
system("whoami"); // Find username
system("cd / && ls"); // Lists all files and directories on /
return 0;
}
Soluzioni
Per ovviare a questi problemi bisognerebbe limitare le funzioni della macchina remota che dovrà compilare attraverso la creazione di un sand-box sicuro, limitando connessioni con l’esterno e prevenendo la lettura di file di sistema sensibili. Un’altra soluzione potrebbe essere quella di ricompilare la/e libreria/e, disabilitando e/o togliendo l’uso di particolari funzioni come system() o execl().
Screenshot


