Ottenuta shell

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

Eseguito ls
Altro esempio
Altro esempio parte 2