l'errore di parsing di cmd.exe porta ad altri exploit?


Answers

Question

Prima di continuare, si noti che questo è un avviso infosec piuttosto lungo sul prompt dei comandi di Windows poiché ho trovato un bug che potrebbe essere sfruttabile utilizzando semplici file batch. Questo bug è prevalente in tutte le versioni di Windows da 2000 in su e funziona su macchine a 64 e 32 bit, ed essendo un bug di parsing di file batch, non richiede l'installazione di software aggiuntivo ( cmd.exe è una parte predefinita di Windows) e può essere avviato da qualsiasi utente con qualsiasi livello di privilegio (supponendo che possano eseguire cmd.exe e quindi analizzare i file batch). In questo riepilogo è incluso l'assemblaggio di dove si verifica l'errore (con la suddivisione del flusso del codice per mostrare perché). Questo non è un bug di livello RCE (non che io sia stato in grado di trovare ancora), solo un tipo DoS e richiederebbe che un utente lo esegua (o lo abbia come elemento di avvio), ma data la sua semplicità e l'ubiquità dei sistemi Windows, ho pensato che meritava una seconda occhiata. Si noti che non sono responsabile se si esegue uno di questi bug per abilitare i file batch e arrestare il sistema in modo anomalo (il task manager e il kill PID funzionano su uno script in fuga nel caso in cui vengano eseguiti).

tldr : un file batch con solo questa linea ^ nul<^ causerà un'enorme perdita di memoria, mentre un file batch con solo questa linea ^|^ provoca il blocco del prompt dei comandi a causa di 'ricorsione infinita'. Questi comportamenti possono portare a interessanti "hack" di batch su qualsiasi sistema Windows (Win2k +) e il motivo è un errore logico nell'elaborazione del file batch cmd.exe (vedere assembly e codice pseudo-C di seguito per ulteriori informazioni).

sfondo

Rispondendo a una domanda su SuperUser ( link ) mi sono imbattuto in un'anomalia interessante con il modo in cui l'interprete dei comandi analizza i file batch. Se il carattere di accento circonflesso ( ^ ) è l'ultimo carattere del file, può verificarsi un arresto anomalo di memoria / cmd.exe. L'accento circonflesso deve essere l'ultimo carattere del file e non può essere seguito da un \n (carattere di avanzamento riga), sebbene \r (il carattere di ritorno a capo) sia OK poiché viene rimosso prima dell'analisi del caret; nulla può trascinarlo però come farebbe in modo che il parser proceda normalmente (poiché ^\r\t diventerebbe ^\t quindi il \t è "ignorato"). Quest'ultima nota sui caratteri di ritorno a capo che vanno bene per questo bug che si verificano ancora lo rende un po 'più interessante perché "falsifica" una nuova riga nella maggior parte degli editor di testo, e nel blocco note si può essere ingannati nel pensare che alla fine ci sia una newline ( 'tecnicamente' è un ritorno a capo o una nuova linea 'vecchio Mac').

Dopo aver fatto alcune indagini veloci ho scoperto che il ^ alla fine di un file può portare a una perdita di memoria o può mandare in crash il prompt dei comandi (in particolare il programma command.com o cmd.exe), ho trovato anche file batch specifici ( e sequenze di essa) può portare ad un comportamento molto interessante. Ulteriori indagini mi portano ad altre persone che notano problemi simili; una domanda in cui un utente ha notato una perdita di memoria e un argomento della bacheca messaggi su ss64.com che ha rilevato altri comportamenti interessanti con il punto di inserimento nell'EOF. La domanda ha aiutato a confermare le sospensioni che si tratta di una situazione di tipo loop infinito, ma non ha cercato di immergersi molto più in profondità. L'argomento ss64.org per lo più ha appena discusso vari modi per bloccare il prompt dei comandi, ma non è riuscito a spiegare che tipo di arresto era o perché.

Naturalmente questo mi ha portato a chiedermi cosa stava succedendo e perché (e potrebbe essere sfruttato). Le risposte sono miste e la correzione è abbastanza semplice (almeno sembra "semplice" dall'assemblea che stavo ispezionando). Ho scoperto che ci sono alcune combinazioni di trucchi sui file batch che possono produrre una perdita di memoria, quanto veloce o lento dipende da ciò che viene inserito nel file batch (non quanti bozzi, ma sequenze di pipe e lunghezza della linea interessante [più avanti]) e indipendentemente dal crash o dalla perdita di memoria, il codice parser si trova in un ciclo stretto su un singolo thread, quindi l'utilizzo della CPU aumenta in modo significativo (CPU single core o spinto a una singola affinità, con una media del 98% di utilizzo della CPU).

L'incidente

Per bloccare il prompt dei comandi è stato abbastanza semplice, un file batch senza newline contenente solo i seguenti caratteri ^&^ (o ^|^ ), causerà il prompt dei comandi in cui il batch viene elaborato per bloccarsi con un codice di errore 0xC00000FD , che è un overflow stack / frame dovuto alla ricorsione infinita. Ciò confermava lo scenario del "ciclo infinito", ma non spiegava abbastanza la perdita di memoria (o perché, per quella questione, si stava bloccando a causa di una ricorsione infinita ??). In questa misura, ho iniziato esaminando alcuni dei modi più semplici per produrre una perdita di memoria; come risulta, un file batch di 2 byte è tutto ciò che è necessario per consumare CPU al 100% e consumare memoria (anche se ad un ritmo follemente lento, ~ 8k / 5s su un i7 da 2.2GHz).

Mangia la memoria

Il file batch che ho usato per test conteneva i seguenti byte esadecimali:

0x01 0x5E

0x5E è il carattere di 0x5E ( ^ ) e 0x01 è il codice di carattere ASCII per 'inizio dell'intestazione'. Il primo codice HEX è solo mezzo significativo nel bug, non può essere nullo ( 0x00 ), \r , | oppure i & come questi caratteri causano l'uscita del file batch tramite una terminazione normale (ad es. "comando non valido rilevato"). Ho usato il 0x01 per dimostrare che non doveva essere un comando valido (o un carattere stampabile per quella materia) per indurre il bug, un file batch di 2 byte contenente semplicemente a^ sarà anche sufficiente.

Facendo qualche altro test, ho trovato il modo più veloce per mangiare memoria (e più semplice) con un file batch è la seguente riga: ^ nul<^

... Avendo inavvertitamente eseguito questo me stesso un paio di volte, si prega di essere consapevoli che questo paralizzerà un sistema a 64 bit piuttosto rapidamente; ci sono voluti circa 20 secondi per mangiare tutti i miei restanti 14 GB di RAM (16 GB totali) sul mio quad core (HTT, quindi 8 core effettivi) i7, che ha reso inutile la mia macchina mentre tutto cercava di pagina (ho dovuto riavviare il mio macchina). L'esecuzione di questa versione "rapida" su un sistema a 32 bit ha terminato il parser del comando con un errore out of memory poiché esaurisce rapidamente il limite di 32 GB a 32 bit. Non si blocca il prompt dei comandi, ma sembra che ci sia un controllo per garantire che la memoria possa essere correttamente malloc d, e quando non può semplicemente interrompe l'elaborazione in batch.

Divertimento bug incatenato

Nota che tutti questi "batch exploit" possono essere "concatenati" insieme, quindi su un sistema a 32 bit (supponendo che abbia solo 4 GB di RAM senza PAE), uno potrebbe eseguire il seguente comando per preformare un DoS su di esso: cmd eat_mem.bat | eat_mem.bat cmd eat_mem.bat | eat_mem.bat (questo lancerà 2 parser di comando e cmd eat_mem.bat | eat_mem.bat 2 GB ciascuno).

Un'altra variante interessante consiste nel raggruppare insieme i file batch "crash"; per esempio, supponendo che ci sia un file chiamato crash.bat e che contiene il nostro 'crash exploit' dall'alto ( ^&^ ), potresti fare quanto segue: cmd crash.bat | crash.bat cmd crash.bat | crash.bat e nota alcuni comportamenti interessanti. Questo particolare fa sì che l'output di cmd crash.bat venga scritto in una pipe che si è arrestata in modo anomalo (a causa del bug del parser) e quindi fornisce una wrote to a non-existent pipe errori di wrote to a non-existent pipe quando si tenta di eseguire CTRL+C ; è abbastanza interessante anche se consente comunque di eseguire comandi, come digitare il notepad e premere Invio per avviare il blocco note. Ho esplorato questo di più per il possibile dirottamento di pipe, ma non ho ancora avuto nulla di fruttuoso (di più su "exploit" di seguito).

Buffer 8K

Come alludeva alla domanda / risposta di Overflow dello stack, più avevi su una riga, più velocemente avrebbe mangiato memoria (a parte la versione "veloce" che ho trovato). Attraverso alcuni altri esperimenti, ho scoperto che la "lunghezza della linea" può effettivamente avere anche alcuni effetti interessanti su questo bug. Se l'ultima riga del file batch ha un ^ alla fine di esso ed è lunga esattamente 8192 byte (incluso il segno di omissione), l'errore fallisce ... Eppure qualsiasi cosa al di sotto e al di sopra dei multipli di 8192 causa il bug. Maggiore è il numero di byte in una stringa, maggiore è la quantità di memoria utilizzata (fino a un multiplo di 8192). Questo numero 8192 è interessante perché la nostra perdita di memoria è di 8k (o in parti più grandi di questa).

Va notato che la dimensione del file è irrilevante per il bug e per questo motivo può essere inserito in qualsiasi file batch innocuo. Come test ho inserito la versione "rapida" ( ^ nul<^ ) alla fine di un file batch che utilizzo per compilare un sacco di codice legacy. Questo script del compilatore è poco meno di 21KB con chiamate ricorsive e funzioni multiple (per permettermi di compilare determinate cose) e mettendo la linea 'buggy' alla fine del file mi ha permesso di eseguire lo script di compilazione come normale e completo come al solito, ma quando ha colpito il "bug" ha trasformato la mia CPU e rapidamente ha mangiato la mia memoria.

Se fossi un ingegnere del software senza pretese dato uno script di compilazione 'semplice' (con una chiamata a :eof caso dentro 'forzando' il bug), non ci penserei due volte se lo script improvvisamente ha sollevato la mia CPU, e se non fossi stato Non prestando attenzione al mio task manager non vedrei quanto velocemente la mia RAM è stata mangiata e quindi devo ricominciare (non è divertente).

Scava più a fondo

Da qui ho deciso di fare alcune ispezioni di livello più alto per vedere cosa stava succedendo con il prompt dei comandi mentre questa perdita stava accadendo. Ho aperto gli strumenti Process Explorer e Procmon per verificare cosa stava accadendo nei processi (sullo stack con PE) e con il sistema (tramite Procmon). Procmon ha confermato la perdita di 8k (in particolare 8191 byte) con una chiamata a ReadFile con un buffer da 8191 byte e PE ha confermato le chiamate al kernel per ReadFile , sebbene non fossi troppo sicuro del motivo per cui il file batch veniva letto?

È interessante notare che questo bug consente anche la modifica dei file batch durante l'esecuzione e la ri-analisi (fino a 8k di "analisi", line feed e tutto). Va notato che il contenuto può essere modificato e determinati comandi verranno elaborati, ma ho notato che a meno che non ci siano molti altri comandi (più specificamente feed di riga prima della finale ^ ), i tempi possono anche avere un ruolo nel successo di un batch modificato "hack" anche se succede più spesso che non (cioè funziona la maggior parte del tempo).

Questi exploit batch mi portano a chiedermi se lo stesso potrebbe essere fatto a livello di programmazione; il mio primo tentativo è stato un semplice programma in C che aveva semplicemente un system("crash.bat"); che ha chiamato il file batch contenente ^&^ in esso. Questo ha avviato un processo separato cmd.exe che successivamente si è arrestato in modo anomalo restituendo il controllo al mio programma (tutto ciò era previsto). Poi sono passato al semplice file di perdita di memoria (contenuto solo a^ ) e ho eseguito di nuovo il programma, questa volta il file cmd.exe ha iniziato a girare (come previsto), ma quando ho premuto CTRL+C , il cmd.exe il processo è stato reso orfano e il controllo è tornato al mio programma, lasciandomi a dover terminare il processo di cmd.exe rogue tramite il task manager. Ho anche provato a usare le righe del file direttamente nel mio programma (cioè chiamando qualcosa all'effetto del system("^ nul<^"); ) ma ho ottenuto risultati validi (valido in questo caso che significa che il comando è stato considerato 'non valido' dal parser di comando). Ho provato le varianti di come collegarmi al processo o sfruttare l'errore di overflow dello stack / frame, ma a causa del fatto che il cmd.exe è lo stesso parser, alcuni degli exploit più ovvi non saranno altrettanto facili. In questo senso, ho deciso di interrompere il processo cmd.exe e di ispezionare l'assembly per verificare cosa stava perdendo e per capire meglio cosa stava succedendo e come poteva essere sfruttato (se non del tutto).

Il codice (cmd.exe)

Ho utilizzato Visual Studio 2010 e collegato a un processo di cmd.exe esecuzione, quindi utilizzando il file batch di perdita di memoria 'semplice' ( a^ ) abbiamo sospeso il processo per passare attraverso l'assembly mentre il parser si trovava nello stato di errore. Dopo aver ispezionato l'assembly e aver usato Process Explorer per verificare quale modulo ero dentro durante il debug, sono stato in grado di tracciare molto del flusso del codice e ho trovato dove il parser cercava il carattere ^ (hex 0x5E ). Quello che segue è il flusso di assemblaggio in quanto posso vedere dove si trova il problema.

Si noti che molte delle funzioni "main" e "parsing" sono state rimosse per motivi di brevità (codice rilevante pubblicato ma il dump completo di ciò che ho trovato è disponibile su richiesta [1.2 MB ASM dump with comments]):

; start cmd.exe asm code flow 

000000004A161D50 ; { start main  (more init frame/code here)
; { start loop
000000004A161FC1 3B F5                cmp         esi,ebp  
; mem leak here?? esi == #bytes, ebp == our 8191 buffer size number
000000004A161FC3 7D 29                jge         000000004A161FEE  
000000004A161FC5 0F B7 44 24 20       movzx       eax,word ptr [rsp+20h]  
000000004A161FCA 48 8D 54 24 70       lea         rdx,[rsp+70h]  
000000004A161FCF 48 8D 4C 24 20       lea         rcx,[rsp+20h]  
000000004A161FD4 66 89 03             mov         word ptr [rbx],ax  
000000004A161FD7 48 83 C3 02          add         rbx,2  
000000004A161FDB FF C6                inc         esi 
000000004A161FDD 48 89 5C 24 60       mov         qword ptr [rsp+60h],rbx  
000000004A161FE2 E8 99 04 00 00       call        000000004A162480  ; main_parser_fn
000000004A161FE7 3D 00 01 00 00       cmp         eax,100h  
000000004A161FEC 75 D3                jne         000000004A161FC1
; } end loop
000000004A162058 ; } end main?? function here

; { start main_parser_fn
000000004A162480 48 8B C4             mov         rax,rsp  
000000004A162483 48 89 58 08          mov         qword ptr [rax+8],rbx  
000000004A162487 48 89 70 10          mov         qword ptr [rax+10h],rsi  
000000004A16248B 48 89 78 18          mov         qword ptr [rax+18h],rdi  
000000004A16248F 4C 89 60 20          mov         qword ptr [rax+20h],r12  
000000004A162493 41 55                push        r13  
000000004A162495 48 83 EC 20          sub         rsp,20h  
000000004A162499 48 8B DA             mov         rbx,rdx  
000000004A16249C 48 8B F9             mov         rdi,rcx  
000000004A16249F E8 BC FB FF FF       call        000000004A162060  ; get_next_char
000000004A1624A4 33 F6                xor         esi,esi  
000000004A1624A6 66 89 07             mov         word ptr [rdi],ax  
000000004A1624A9 39 35 D1 98 03 00    cmp         dword ptr [4A19BD80h],esi  
000000004A1624AF 0F 85 F1 75 01 00    jne         000000004A179AA6  
000000004A1624B5 0F B7 17             movzx       edx,word ptr [rdi]  
000000004A1624B8 41 BD 3C 00 00 00    mov         r13d,3Ch  
000000004A1624BE 8B CA                mov         ecx,edx  
000000004A1624C0 45 8D 65 CE          lea         r12d,[r13-32h]  
000000004A1624C4 3B D6                cmp         edx,esi  
000000004A1624C6 74 98                je          000000004A162460  
000000004A1624C8 41 2B CC             sub         ecx,r12d  
000000004A1624CB 74 93                je          000000004A162460  
000000004A1624CD 83 E9 1C             sub         ecx,1Ch  
000000004A1624D0 74 91                je          000000004A162463  
000000004A1624D2 83 E9 02             sub         ecx,2  
000000004A1624D5 0F 84 61 FF FF FF    je          000000004A16243C  
000000004A1624DB 83 E9 01             sub         ecx,1  
000000004A1624DE 0F 84 6A FF FF FF    je          000000004A16244E  
000000004A1624E4 83 E9 13             sub         ecx,13h  
000000004A1624E7 0F 84 76 FF FF FF    je          000000004A162463  
000000004A1624ED 83 E9 02             sub         ecx,2  
000000004A1624F0 0F 84 6D FF FF FF    je          000000004A162463  
000000004A1624F6 83 E9 02             sub         ecx,2  
000000004A1624F9 0F 84 28 FF FF FF    je          000000004A162427  ; quote_parse_fn
000000004A1624FF 41 3B CD             cmp         ecx,r13d  ; check if it's the '<'
000000004A162502 0F 84 5B FF FF FF    je          000000004A162463  
000000004A162508 83 FA 5E             cmp         edx,5Eh  ; start the '^' parse
000000004A16250B 0F 84 86 DC 00 00    je          000000004A170197  ; caret_parse
000000004A162511 83 FA 22             cmp         edx,22h  
000000004A162514 0F 84 5E 2F 00 00    je          000000004A165478  
000000004A16251A F6 03 23             test        byte ptr [rbx],23h  
000000004A16251D 0F 84 E5 00 00 00    je          000000004A162608  
000000004A162523 0F B7 0F             movzx       ecx,word ptr [rdi]  
000000004A162526 FF 15 54 6C 02 00    call        qword ptr [4A189180h]  
000000004A16252C 3B C6                cmp         eax,esi  
000000004A16252E 0F 85 C0 10 00 00    jne         000000004A1635F4  
000000004A162534 33 C0                xor         eax,eax  
000000004A162536 48 8B 5C 24 30       mov         rbx,qword ptr [rsp+30h]  
000000004A16253B 48 8B 74 24 38       mov         rsi,qword ptr [rsp+38h]  
000000004A162540 48 8B 7C 24 40       mov         rdi,qword ptr [rsp+40h]  
000000004A162545 4C 8B 64 24 48       mov         r12,qword ptr [rsp+48h]  
000000004A16254A 48 83 C4 20          add         rsp,20h  
000000004A16254E 41 5D                pop         r13  
000000004A162550 C3                   ret  
; } end main_parser_fn

; { start get_next_char
000000004A162060 FF F3                push        rbx  
000000004A162062 48 83 EC 20          sub         rsp,20h  
000000004A162066 48 8B 05 0B C2 02 00 mov         rax,qword ptr [4A18E278h]  
000000004A16206D 8B 0D ED 9B 03 00    mov         ecx,dword ptr [4A19BC60h]  
000000004A162073 33 DB                xor         ebx,ebx  
000000004A162075 66 39 18             cmp         word ptr [rax],bx 
000000004A162078 74 29                je          000000004A1620A3  ; when bx=0 
000000004A16207A 66 83 38 0D          cmp         word ptr [rax],0Dh ; 0d = \r
000000004A16207E 0F 84 69 0E 00 00    je          000000004A162EED  
000000004A162084 3B CB                cmp         ecx,ebx  
000000004A162086 0F 85 46 7A 01 00    jne         000000004A179AD2  
000000004A16208C 0F B7 08             movzx       ecx,word ptr [rax]  
000000004A16208F 48 83 C0 02          add         rax,2  
000000004A162093 48 89 05 DE C1 02 00 mov         qword ptr [4A18E278h],rax  
000000004A16209A 66 8B C1             mov         ax,cx  
000000004A16209D 48 83 C4 20          add         rsp,20h  
000000004A1620A1 5B                   pop         rbx  
000000004A1620A2 C3                   ret  
; } end get_next_char
000000004A1620A3 E8 18 00 00 00       call        000000004A1620C0  
000000004A1620A8 48 8B 05 C9 C1 02 00 mov         rax,qword ptr [4A18E278h]  
000000004A1620AF 8B 0D AB 9B 03 00    mov         ecx,dword ptr [4A19BC60h]  
000000004A1620B5 EB C3                jmp         000000004A16207A  

000000004A1620C0  ; this starts a large chunk of code that does more parsing (as well as calls
; some CriticalSection code) it's omitted from this because the issues that are prevalent in the
; rest of the code are pertaining to the 'caret_parser' not returning properly. The 'memory leak'
; is in this section code (an 8k buffer read that's also checked in main loop).


; { start quote_parse
000000004A162463 F6 03 22             test        byte ptr [rbx],22h  
000000004A162466 0F 85 9C 00 00 00    jne         000000004A162508  
000000004A16246C B8 00 01 00 00       mov         eax,100h  
000000004A162471 E9 C0 00 00 00       jmp         000000004A162536  
; } end quote_parse

; { start caret_parse
000000004A170197 F6 03 22             test        byte ptr [rbx],22h ; check if '"' 
000000004A17019A 0F 85 71 23 FF FF    jne         000000004A162511  ; if char == '"'
000000004A1701A0 E8 BB 1E FF FF       call        000000004A162060  ; get_next_char
000000004A1701A5 66 89 07             mov         word ptr [rdi],ax  ; ax will be 0 if EOF
000000004A1701A8 66 41 3B C4          cmp         ax,r12w  ; r12w is 0x0A ('\n') here, so this is a EOL check (fail in EOF case)
000000004A1701AC 0F 85 82 23 FF FF    jne         000000004A162534  ; this is the jump back to the 'main_parser_fn' <--error
000000004A1701B2 E9 0B 99 00 00       jmp         000000004A179AC2  ; == call 000000004A162060 (get_next_char)
000000004A1701B7 33 C9                xor         ecx,ecx  
000000004A1701B9 E8 22 1B FF FF       call        000000004A161CE0  
; } end caret_parse

; end cmd.exe asm code flow 

Sulla base di questo assembly, sono stato in grado di accertarmi che il codice di analisi di cmd.exe stia facendo qualcosa del genere (codice psuedo-C):

void main_parser_fn() { 
    /* the 'some_read_condition' is based on a lot of things but
       interestingly one of them is an 8k buffer size; the ASM
       shows an 8191 byte buffer for reading/parsing, but I
       couldn't ascertain why having a buffer divisible by exactly
       8192 bytes in the line buffer was 'ok' but anything more or
       less causes the continuation (mem leak)?? */
    while (some_read_condition) {
        // allocate 8k buffer appropriately
        x = get_next_char();
        if (x == '|' || x == '&') {
            main_parser_fn();
        }
        if (x == '^') {
            get_next_char(); // error here
            // POSSIBLE FIX:
            // if (get_next_char() == 0) { abort_batch(); }
            continue;
        }
        // free buffer (never get here due to EOF error)
    }
}

Questa è (ovviamente) un'approssimazione approssimativa basata su input / output e assembly, ma sembra che il codice per ottenere il prossimo carattere dopo il punto di inserimento sia il punto in cui si trova il problema.

Spiegato l'insetto

Il bug è che quando viene rilevato un accento circonflesso, il carattere successivo viene letto dal file (per essere 'scappato'). Se il caret è l'ultimo carattere del file, ciò genera un errore logico, come quando viene effettuata una chiamata a get_next_char , il puntatore del file viene incrementato di uno; in questo caso passa l' EOF . Poiché EOF viene effettivamente ignorato quando il parser del comando continua a leggere l'input successivo, essenzialmente "ripristina" il puntatore del file a causa dell'errore EOF+1 . In questo caso, posizionando il puntatore del file su EOF+1 il puntatore si trova su un numero negativo elevato e poiché il file non può scendere sotto 0, il puntatore del file viene sostanzialmente reimpostato su 0 e l'analisi continua dall'inizio del file.

Questo spiega le perdite di memoria e il motivo per cui è 8k (un buffer di lettura di 8k 'viene riempito), e può anche spiegare il problema della ricorsione. Quando un | o & viene rilevato nel file batch, viene analizzato in modo ricorsivo e poiché esiste un bug EOF la ricorsione diventa infinita in quanto non si possono avere percorsi di ritorno.

Edit : come alcuni commenti hanno sottolineato, e ulteriori ricerche hanno dimostrato, il caret non deve essere alla fine del file per questo errore, sto attualmente indagando (e analizzando più ASM) a vedere se ci sono altri scenari e perché / come sta accadendo.

La correzione

Sembra che una semplice soluzione sarebbe quella di verificare EOF su una lettura del prossimo carattere durante l'analisi del cursore. Questo controllo (e la successiva funzionalità "abortire correttamente") risolverà il problema di perdita di memoria e la ricorsione infinita.

Exploit?

Dopo aver ispezionato di più il processo e pensato a possibili exploit, non vedo che questo sia serio come MS14-019 , ma vista la facilità del suo utilizzo / implementazione (e la relativa facilità di fissarlo), considererei questo 'medium' 'avviso di livello come la maggior parte degli' exploit 'richiederebbe all'utente di eseguire il file batch, e' ovvio 'viali come tentare di sfruttare l'errore di overflow dello stack / frame o lanciare il codice shell attraverso un file batch risulterebbe più difficile rispetto a molti altri exploit ciò produrrebbe un risultato più "fruttuoso" rispetto a questo bug innocuo. Anche se posso vedere che viene utilizzato in un attacco DoS in quanto è facile scriverne uno dato che è 7 byte ( ^ nul<^ ) e potrebbe potenzialmente essere distribuito e "configurato" piuttosto facile.

Ecco un semplice vbscript che può essere utilizzato per scrivere e avviare il file batch "killer" (e farlo in silenzio)

CreateObject("Scripting.FileSystemObject").CreateTextFile("killer.bat", True).Write("^ nul<^") & VbCr
CreateObject("WScript.Shell").Run "killer.bat", 0, False

Questo creerà un file batch chiamato killer.bat con un ^ nul<^\r in esso e poi lo eseguirà, questo potrebbe essere messo in un file .vbs ed essere eseguito all'avvio, o inserire una macro di Excel ed eseguire.

echo|set /p="^ nul<^" > killer.bat

Quella linea è la riga di comando che equivale a creare il file batch "killer" (fare un normale eco ad un file risulterebbe in \r\n alla fine del file e quindi il bug non sarà presente).

Come prova del concetto, ho creato questo vbscript (così come alcuni altri test sui file batch) e li ho inseriti nella mia cartella di Startup e nel registro. Quando ho effettuato l'accesso, sono stato accolto con un prompt dei comandi quando si utilizzavano i file batch e niente quando si utilizzava il vbscript, e in pochi secondi il sistema si fermava ed era inutilizzabile perché lo script aveva consumato tutta la mia RAM. Gli script possono essere chiusi uccidendo il processo in esecuzione cmd.exe , ma poiché funzionano così velocemente, potresti non avere nemmeno il tempo sufficiente per avviare il task manager prima di consumare tutta la RAM. La rimozione tramite la Safe Mode era la "cura" per questo, ma non la "correzione".

Potrei anche immaginare uno scenario in cui un amministratore ignaro eseguirà uno script backup.bat con questo bug infelice e che inavvertitamente abbassa il proprio server. O il divertimento che si può avere con i comandi at / schtasks.exe su un sistema non protetto.

Certo, non vedo questi " exploit " che lasciano il regno di un DoS o uno scherzo.

Sto ancora ispezionando varie strade con piping e reindirizzamento degli script "corrotti" che potrebbero portare a un RCE, in quanto il vettore di attacco più semplice è un attacco DoS con il file 'veloce'. Ho testato questo bug su Windows 98, 2000, XP, Vista, 7, 8 e le variazioni del server (per includere sapori a 32 e 64 bit). Il prompt dei comandi di Windows 98 non è influenzato da questo, ma ogni versione precedente è (per includere command.com poiché utilizza cmd.exe per analizzare i file batch). Per curiosità, l'ho testato anche su ReactOS e Wine (nessuno dei due aveva il problema).

Domande (modificate dopo ulteriori ricerche)

Come detto, non vedo questo bug essere "sfruttabile" più di un "attacco" di denial of service (o scherzo a un collega / amico), ma mi ha fatto pensare in generale a problemi di overflow e perdite di memoria, in particolare se sono sfruttabili (solo in generale).

La mia esperienza e comprensione da una prospettiva di ingegneria / hacker del software mi dice che le perdite di memoria o gli overflow di frame potrebbero essere potenzialmente sfruttati su un sistema operativo precedente (ad esempio Windows 98/2000 / XP o versioni precedenti di * nix?) Che non hanno certe protezioni in luogo (come l'uso del bit NX o ASLR) date le giuste condizioni, ma non sono stato in grado di trovare alcuna ricerca in queste aree oltre ai "normali" vettori di attacco (buffer overflow in pila) o documentazione generale su cosa queste cose sono "(cioè le discussioni sul" white paper "su cosa sia un overflow di frame o perdita di memoria e che cosa sia NX / ASLR) e non sul" perché "non sia possibile.

Ho sperimentato l'iniezione di un thread o di qualche altro metodo nel processo di esecuzione di cmd.exe per eseguire test e analizzare l'overflow del frame e la perdita di memoria che si verifica al suo interno (oltre al semplice divertimento generale che si può avere con questo bug , come usare CreateProcess e poi EmptyWorkingSet per il divertimento generale) e so che non sarò "da nessuna parte" con questo particolare bug, ma mi ha fatto pensare (o piuttosto a pensare): c'è mai stato un exploit di overflow di frame o perdita di memoria exploit in the wild o c'è qualche documentazione che potrei essere in grado di leggere che spiega perché (più specificamente / tecnicamente) non è fattibile?

Capisco il "perché", ma una maggiore specificità, come "il registro EIP è protetto perché XYZ ..." invece di "non è possibile", sarebbe utile; So che ogni architettura è diversa e potrei chiedere più dettagli di quelli che si potrebbero avere in una risposta, ma i collegamenti o i punti di discussione che potrei fare riferimento sono utili anche perché non riesco a trovare troppo in riferimento a questo.

Ho nuotato in assemblea, una prospettiva fresca aiuta sempre :)

Nota: ho inviato una email (il 24/04/2014) a Microsoft con questo bug e hanno risposto dicendo che hanno inoltrato questo al team di sviluppo e stanno indagando, non è prevista alcuna correzione in un bollettino sulla sicurezza (concorda con loro su questo come nulla ancora indica che è un difetto grave). Verrà modificato se arrivano altri aggiornamenti.