Uno sfondo molto veloce per aiutarti a rispondere alle mie domande:
- Learning IDA Interactive Disassembler, la vecchia edizione gratuita (troppo cara per un hobbista)
- Sysadmin Linux di 15 anni e amp; Esperienza DBA
- Codificatore di hobbisti (C / ASM / Fortran /...)
- Non molto informato su Windows & Microsoft in generale
- non è un esperto di sicurezza, ma abbastanza da essere un amministratore di sistema
Dopo un sacco di disassemblaggi casuali di cose qua e là ho subito notato che hanno un sacco di codice comune. E proprio all'inizio di un sacco di eseguibili c'è qualcosa che assomiglia a questo:
lea eax, [ebp+SystemTimeAsFileTime]
push eax ; lpSystemTimeAsFileTime
call ds:GetSystemTimeAsFileTime
mov eax, [ebp+SystemTimeAsFileTime.dwHighDateTime]
xor eax, [ebp+SystemTimeAsFileTime.dwLowDateTime]
È letteralmente praticamente in ogni binario e in poco tempo si scopre che è una cosa chiamata da microsoft: "Buffer Security Check". Ed è aggiunto automaticamente dal compilatore usando il flag / GS.
È un stack canary utilizzato per rilevare l'overflow del buffer dello stack:
This method works by placing a small integer, the value of which is randomly chosen at program start, in memory just before the stack return pointer. Most buffer overflows overwrite memory from lower to higher memory addresses, so in order to overwrite the return pointer (and thus take control of the process) the canary value must also be overwritten. This value is checked to make sure it has not changed before a routine uses the return pointer on the stack
E dalla documentazione Microsoft :
On functions that the compiler recognizes as subject to buffer overrun problems, the compiler allocates space on the stack before the return address. On function entry, the allocated space is loaded with a security cookie that is computed once at module load. On function exit, and during frame unwinding on 64-bit operating systems, a helper function is called to make sure that the value of the cookie is still the same. A different value indicates that an overwrite of the stack may have occurred. If a different value is detected, the process is terminated.
Va tutto bene e tutti vivranno felici e contenti.
Tuttavia , sono confuso riguardo all'implementazione stessa. È un sacco di XOR di: System time, processId, ThreadId, uptime, più tempo (perf contatore) alla creazione del processo.
Non sto dicendo che è un'implementazione terribilmente brutta (ma a prima vista ci sto pensando) dato che è un sacco di XOR e un singolo bit sbagliato rovinerà completamente il cookie (a meno che non ci sia un attacco sono non a conoscenza di) e la forzatura bruta è prevenuta al 100% (o non lo è?) poiché il processo verrà terminato quando l'ipotesi non è corretta e un nuovo cookie generato al successivo avvio del processo.
Ora ho un sacco di domande:
- Perché una così strana implementazione di generazione pseudo-casuale? Il sistema operativo non ha una fonte di entropia affidabile? È legato alla portabilità? Alcune varianti di Windows potrebbero non avere una fonte di entropia?
- non è processId e threadId noti a tutti sul sistema comunque? quindi perché usarlo come fonte di entropia?
- È tutto relativo al tempo e avviato all'avvio del processo, non vengono avviati i servizi all'avvio (roba che richiede più protezione) garantiti per avere uptime & perfcounter e un tempo di sistema noto e quindi l'entropia più debole?
- Perché questa generazione di cookie non è una chiamata di sistema? È ora non modificabile senza ricompilazione.
Ecco il mio smontaggio commentato:
push ebp ; prolog
mov ebp, esp ; prolog
sub esp, 14h ; prolog
and [ebp+SystemTimeAsFileTime.dwLowDateTime], 0
and [ebp+SystemTimeAsFileTime.dwHighDateTime], 0
mov eax, __security_cookie
push esi
push edi
mov edi, 0BB40E64Eh ; a global constant thingy for security cookie
mov esi, 0FFFF0000h
cmp eax, edi ; compare local security cookie
; with global security cookie.
; if security_cookie == 0BB40E64Eh then it's not initialized
; and it need to be initialized
jz short generate_security_cookie
La generazione viene eseguita solo se si confronta con una costante nota a livello mondiale "0BB40E64Eh". Non c'è un potenziale vettore di attacco? non potrebbe essere valore locale per il sistema?
- Perché preoccuparsi di rendere condizionale la generazione?
- È anche una funzione di sicurezza? o solo un debug significa rilevare se qualcosa è andato storto nello stack?
Sono un sacco di domande, è il mio primo passo in questo genere di cose, ma questo è così confuso. Ma soprattutto: perché non chiamare semplicemente una fonte di entropia del SO? Sono così confuso ...
Domanda bonus: se uno ha un mezzo per modificare il file binario (un singolo bit nella costante conosciuta in tutto il mondo?) non è possibile aggirare l'intera / GS roba? e se si tratta di un servizio di rete aperto ora hai un servizio con un potenziale di overflow del buffer aperto al mondo, giusto?