Ci sono due punti in cui puoi cercare prove di questo tipo di exploit: il syslog e i coredumps.
Registro di sistema
Immagino che tu stia parlando del record del tentativo di exploit stesso e di nulla prima (come i log di accesso remoto) e che non hai abilitato alcuna registrazione aggiuntiva che possa tracciare gli accessi ai file o la creazione di processi. Per l'exploit stesso, in genere non c'è traccia nei file di log se l'attacco ha avuto successo. L'unico modo sarebbe se avesse fallito almeno una volta e avesse attivato un errore di segmentazione, che potrebbe essere registrato nel buffer di log del kernel (mostrato tramite dmesg
), che è probabilmente registrato dalla scelta del demone syslog.
File principali
Se hai abilitato i correttivi, allora potresti essere in grado di ottenere molte più informazioni su esattamente ciò che ha causato il segfault, supponendo che tu abbia e sappia come usare gdb, e avere il file binario originale che si è bloccato. poiché i processi registreranno la loro memoria di base sul disco in seguito a un tale arresto. Ma proprio come controllare il registro di sistema, funziona solo se l'exploit ha avuto esito negativo almeno una volta e ha provocato un arresto anomalo. Inoltre, non fornisce alcuna informazione su chi sia l'attaccante, quale sia il loro vettore di sfruttamento, cosa stanno cercando o cosa hanno usato per attaccare. Ricorda inoltre che, a meno che tu non abbia una configurazione speciale, i coredumps vengono scritti sul disco con le stesse autorizzazioni del programma che si è bloccato, quindi in alcuni casi un utente malintenzionato potrebbe disporre di privilegi sufficienti per cancellarlo (ed esaminando quell'atto va nel forensics del filesystem, in cui non entrerò e non è particolarmente correlato)
Indurimento del tempo di compilazione
Per quanto riguarda ciò che faccio, compilo tutti i programmi localmente, così posso usare le funzionalità di sicurezza in fase di compilazione che tentano di provocare arresti anomali nei tentativi di sfruttamento. Alcuni esempi:
-
UBSAN (Uneined Behavior SANitizer) - Trappola vari tipi di comportamento non definito all'istruzione ud2
, che è un'istruzione intenzionalmente illegale e causa l'arresto anomalo del programma. Alcuni tipi di comportamento non definito possono essere utilizzati per sfruttare un programma.
-
SSP (Stack Smashing Protector) - Crea un canarino segreto nello stack e interrompe il programma se viene mai sovrascritto. Un utente malintenzionato che possiede solo una primitiva di scrittura arbitraria non sarà in grado di sfruttare facilmente un programma che utilizza SSP, a meno che non disponga anche di una primitiva di lettura arbitraria e possa leggere il valore del canarino (e inserirlo nel suo codice di overflow). / p>
-
FORTIFY_SOURCE - Una raccolta di file di intestazione che racchiudono determinate funzioni che prevedono una lunghezza come argomento, ad esempio strncpy()
, per aggiungere controlli di runtime per garantire che la lunghezza massima non venga superata quando è noto durante la compilazione tempo.
-
PIE (Position Independent Executable) - Aggiunge il supporto a un eseguibile per l'indirizzamento di librerie che non sono note in fase di compilazione. Ciò consente a un programma di utilizzare ASLR, che carica le librerie su indirizzi casuali per rendere più difficile lo sfruttamento dei buffer overflow.
-
RELRO (RELOCATION Read Only) - In modalità parziale, rende le sezioni ELF di sola lettura dopo che il linker ha impostato tutto. In modalità completa, inoltre, rende GOT di sola lettura.
-
BINDNOW - Fa sì che le librerie vengano risolte al tempo di caricamento dell'eseguibile, piuttosto che al primo riferimento, necessario per sfruttare tutto il potenziale di RELRO.
Ci sono più funzionalità relative alla sicurezza che possono essere fatte in fase di compilazione, come CFI e SafeStack. Quello era solo un elenco di alcuni dei più popolari. Puoi utilizzare lo script checksec aggiornato per vedere se un binario è stato compilato o meno con vari flag di rafforzamento:
$ checksec --file /bin/bash
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH Yes 13 33 /bin/bash
Esempi di voci di registro
Generalmente i log vengono creati solo quando il programma è compilato con i flag di hardening corretti (ad eccezione di segfaults che si verificherà indipendentemente da come si compila il binario). Questi flag di hardening non garantiscono che un attacker non sia in grado di sfruttare un dato binario, ma rende più probabile che un exploit fallisca e lasci probabilmente le voci nei log. Alcuni esempi:
SIGSEGV trigger di default (in questo caso, un dereferenziamento del puntatore nullo):
$ gcc <<< 'void main() { char *a = 0; *a = 5; }' -x c - 2>/dev/null
$ ./a.out
a.out[24078]: segfault at 0 ip 000000720ab0b6f4 sp 000003c8ad38d170 error 6 in a.out[720ab0b000+1000]
Segmentation fault
UBSAN che attiva SIGILL (in questo caso, un indice fuori limite):
$ gcc <<< 'void main() { char a[2]; a[-1] = 5; }' -x c - -fsanitize=undefined -fsanitize-undefined-trap-on-error 2>/dev/null
$ ./a.out
traps: a.out[24130] trap invalid opcode ip:62a7e64673 sp:3be53c5fe20 error:0 in a.out[62a7e64000+1000]
Illegal instruction
Stack Smashing Protector (scritto solo su stderr):
$ gcc <<< 'void main() { char a[2]; strcpy(a, "abcd"); }' -x c - -fstack-protector-all -include string.h 2>/dev/null
$ ./a.out
*** stack smashing detected ***: ./a.out terminated
Killed
FORTIFY_SOURCE (scritto solo per stderr):
$ gcc <<< 'void main() { char a[2]; strncpy(a, "abcd", 4); }' -x c - -O -D_FORTIFY_SOURCE=2 -include string.h 2>/dev/null
$ ./a.out
*** buffer overflow detected ***: ./a.out terminated
Killed
Ma di nuovo, e non posso sottolineare abbastanza, un exploit di successo non lascerà log come questi . Devi controllare i segni dell'intrusione originale e non fare affidamento sulla possibilità che il loro exploit fallisca.