Per aggiungere all'eccellente risposta di Thomas Pornin, in genere le vulnerabilità zero-day vengono rilevate tramite controllo del codice sorgente, reverse engineering e fuzzing (o test fuzz).
La scelta della tecnica di solito dipende dalle informazioni disponibili. Ad esempio, se il software è open source, passare al setaccio il codice sorgente e cercare le vulnerabilità è il modo preferito. Le vulnerabilità rilevate tramite il controllo del codice sorgente sono solitamente più facili da sfruttare poiché è possibile esaminare e comprendere tutti i rami di esecuzione osservando il codice sorgente. Il processo di audit del codice sorgente può essere semplice come grep-ing per chiamate di funzioni pericolose come strcpy o può essere complesso come un test di copertura del codice automatizzato alla ricerca di ogni esecuzione e analisi di ogni branch code.
Se il codice sorgente non è disponibile, l'opzione successiva per il ricercatore di vulnerabilità è di decodificare l'applicazione e analizzare il codice di basso livello. Quando un'applicazione viene analizzata tramite un debugger o, più preferibilmente, tramite un decompilatore come IDA, i blocchi di codice e gli assembly mnemonics vengono mappati su strutture di routine linguistiche di livello relativamente alto che sono facili da analizzare. Il ricercatore di vulnerabilità può quindi seguire il flusso di esecuzione e analizzare il comportamento in modo statico o dinamico per trovare diversi bug di sicurezza. Ad esempio, l'allocazione di un buffer di dimensioni fisse e l'immissione di un input controllato dall'utente nel buffer assegnato di solito significa che può essere sfruttato tramite un exploit di buffer overflow.
Il metodo finale per trovare nuove vulnerabilità nel software è attraverso test fuzz. Questo può anche essere considerato come una ricerca di bug attraverso la bruteforcing poiché l'input casuale viene generato e fornito a tutte le interfacce di input disponibili dell'applicazione nella speranza che una stringa appositamente predisposta (come una stringa troppo lunga o una stringa con caratteri speciali) possa causare software in crash. Una volta che il software si è arrestato, il test fuzz si interrompe e consente al ricercatore di vulnerabilità di analizzare l'input su cui si è verificato l'arresto anomalo dell'applicazione. Se l'arresto anomalo può essere attivato in modo affidabile (ad esempio, ogni volta che un determinato insieme di byte fornito all'applicazione provoca un arresto anomalo) e il flusso di esecuzione può essere trasferito ai dati controllati dall'utente in una memoria eseguibile, il bug viene classificato come remoto bug di esecuzione del codice. Altrimenti, se il crash è un bug affidabile, non può essere convertito nell'esecuzione del codice, quindi viene classificato come un errore Denial of Service.