C'è una ragione per cui non puoi studiare il codice? 30 linee di ASM dovrebbero essere facili da capire. Aggiungi solo commenti che spiegano cosa fa ogni linea e la capirai in pochissimo tempo. Ciò sarà ancora più semplice se si considera con quanta rapidità esattamente ciò che fa una singola istruzione.
Anche se sarei d'accordo sul fatto che è improbabile che sia in grado di fare qualcosa di pericoloso da solo con un solo syscall, non dovresti mai sottovalutare l'ingegno che alcuni sviluppatori possono avere. È perfettamente possibile progettare shellcode per ingannare un disassemblatore nel mostrare il codice che in realtà non è presente, come sottolineato da DEF CON alcuni anni fa. 30 linee di assemblaggio x86 sono sufficienti per un payload di stage 1.
È probabile che sia completamente innocuo. Non ci scommetterei la vita, comunque.
Puoi usare seccomp su Linux per isolarlo. Seccomp è una funzionalità Linux che filtra le chiamate di sistema. Esistono due modalità per seccomp, modalità 1 e modalità 2. La modalità Seccomp 1 è la modalità più rigida. Quando un programma attiva questa modalità, è limitato all'utilizzo di solo quattro syscalls codificate : read()
, write()
, exit()
e rt_sigreturn()
. La modalità 2 è più complessa e utilizza un filtro eBPF generato dallo spazio utente per specificare una whitelist personalizzata di syscall e argomenti syscall. Per un pezzo di shellcode molto semplice, avresti solo bisogno della modalità 1.
La modalità di attivazione 1 seccomp è semplice. Tratto da un'altra risposta ho scritto su un altro sito StackExchange, un programma di esempio che esegue in modo sicuro una funzione che restituisce 42 in bytecode:
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <linux/seccomp.h>
/* "mov al,42; ret" aka "return 42" */
static const unsigned char code[] = "\xb0\x2a\xc3";
void main(void)
{
int fd[2], ret;
/* spawn child process, connected by a pipe */
pipe(fd);
if (fork() == 0) {
close(fd[0]);
/* enter mode 1 seccomp and execute untrusted bytecode */
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
ret = (*(uint8_t(*)())code)();
/* send result over pipe, and exit */
write(fd[1], &ret, sizeof(ret));
syscall(SYS_exit, 0);
} else {
close(fd[1]);
/* read the result from the pipe, and print it */
read(fd[0], &ret, sizeof(ret));
printf("untrusted bytecode returned %d\n", ret);
}
}
Dovresti sostituire code[]
con lo shellcode che vuoi testare.
Hai detto che c'è un syscall in time()
. Sulla maggior parte dei sistemi Linux, questo non è un vero syscall, ma un vDSO . Se è in realtà un syscall diretto, è necessario utilizzare la modalità 2 seccomp e autorizzarla esplicitamente in whitelist. Per questo, vorresti usare libseccomp per astrarre la complessità.