script example create commands batch bat c windows batch-file assembly cmd

example - ¿El error de análisis cmd.exe lleva a otros exploits?



create script windows command line (0)

Antes de continuar, tenga en cuenta que este es un aviso de información bastante largo sobre el símbolo del sistema de Windows, ya que he encontrado un error que podría ser explotable utilizando simples archivos por lotes. Este error prevalece en todas las versiones de Windows desde 2000 y funciona en máquinas de 64 y 32 bits, y dado que es un error de análisis de archivos por lotes, no requiere instalar software adicional ( cmd.exe es una parte predeterminada de Windows) y puede ser iniciado por cualquier usuario con cualquier nivel de privilegio (suponiendo que puedan ejecutar cmd.exe y, por lo tanto, analizar los archivos por lotes). Incluido en este resumen está el ensamblaje de donde ocurre el error (con el desglose del flujo del código para mostrar por qué). Este no es un error de nivel RCE (que no he podido encontrar todavía), solo un tipo DoS y requeriría que un usuario lo ejecute (o lo tenga como un elemento de inicio), pero dada la simplicidad de este y ubicuidad de los sistemas de Windows, pensé que merecía una segunda mirada. Tenga en cuenta que no soy responsable si ejecuta alguno de estos errores y habilita los archivos por lotes y bloquea su sistema (el administrador de tareas y cancela el PID funciona en un script desbocado en caso de que los ejecute).

tldr : un archivo por lotes con solo esta línea ^ nul<^ causará una fuga de memoria masiva, mientras que un archivo por lotes con solo esta línea ^|^ hará que el símbolo del sistema se bloquee debido a ''recursión infinita''. Estos comportamientos pueden dar lugar a interesantes "hacks" de lotes en cualquier sistema Windows (Win2k +) y la razón es un error lógico en el procesamiento del archivo por lotes cmd.exe (para más información, consulte el código ensamblado y pseudo-C a continuación).

Fondo

Al responder una pregunta en SuperUser ( enlace ) me encontré con una anomalía interesante con la forma en que el intérprete de comandos analiza los archivos por lotes. Si el carácter de intercalación ( ^ ) es el último carácter del archivo, puede producirse un bloqueo de memoria / cmd.exe. El símbolo de intercalación tiene que ser el último carácter del archivo y no puede ser seguido de /n (el carácter de avance de línea), aunque /r (el carácter de retorno de carro) está bien ya que se elimina antes de analizar el símbolo de intercalación. no obstante, nada puede seguirlo, ya que haría que el analizador procediera normalmente (ya que ^/r/t se convertiría en ^/t tanto, /t se "ignoraría"). Esta última nota sobre los caracteres de retorno de carro está bien para que este error suceda, lo hace un poco más interesante porque ''falsifica'' una nueva línea en la mayoría de los editores de texto, y en el bloc de notas se puede engañar al pensar que hay una nueva línea al final ( ''técnicamente'' es una línea de retorno de carro o una ''nueva Mac'').

Después de hacer algunas investigaciones rápidas, descubrí que ^ al final de un archivo puede provocar una pérdida de memoria o puede bloquear el símbolo del sistema (más específicamente el programa command.com o cmd.exe), también encontré archivos de proceso por lotes específicos ( y secuencias de los mismos) puede conducir a un comportamiento muy interesante. Las investigaciones adicionales me llevan a otras personas que notan problemas similares; una pregunta de desbordamiento de pila donde un usuario notó una fuga de memoria y un tema de tablero de mensajes en ss64.com que observó otros comportamientos interesantes con el símbolo de intercalación en el EOF . La pregunta de Stack Overflow ayudó a confirmar las suspensiones de que se trata de una situación de tipo de bucle infinito, pero no intentó bucear mucho más profundo que eso. El tema de ss64.org en su mayoría solo discutía varias formas de hacer que el comando fallara, pero no explicaba qué tipo de bloqueo era o por qué.

Naturalmente, esto me llevó a preguntar qué estaba sucediendo y por qué (y podría ser explotado). Las respuestas son mixtas y la solución es bastante simple (al menos parece "simple" del ensamblaje que estaba inspeccionando). Descubrí que hay algunas combinaciones de trucos de archivo por lotes que pueden producir una pérdida de memoria, qué tan rápido o lento depende de lo que se pone en el archivo por lotes (no cuántos carátulas, sino secuencias de tuberías y curiosamente la longitud de línea [más adelante]) e independientemente de la falla o fuga de memoria, el código del analizador está en un bucle cerrado en un solo subproceso, por lo que el uso de la CPU aumenta significativamente (CPU de un solo núcleo o empujada a una sola afinidad, produce un promedio de 98 +% de uso de CPU).

El estrellarse

Bloquear el símbolo del sistema era bastante simple, un archivo por lotes sin nuevas líneas que contenga solo los siguientes caracteres ^&^ (o ^|^ ), hará que el símbolo del sistema en el que se procesa el lote se bloquee con un código de error de 0xC00000FD . que es un desbordamiento de pila / cuadro debido a la recursión infinita. Eso confirmó el escenario del ''bucle infinito'', pero no explicó la fuga de memoria (¿o por qué se estrelló debido a una recursión infinita?). En este sentido, comencé por examinar algunas de las formas más simples de producir una pérdida de memoria; como resultado, un archivo por lotes de 2 bytes es todo lo que se necesita para consumir el 100% de la CPU y comer memoria (aunque a un ritmo increíblemente lento, ~ 8k / 5s en un 2.2GHz i7).

Eat Memory

El archivo por lotes que utilicé para la prueba contenía los siguientes bytes hexadecimales:

0x01 0x5E

0x5E es el carácter de intercalación ( ^ ) y 0x01 es el código de carácter ASCII para ''inicio de encabezado''. El primer código HEX es solo medio significativo en el error, no puede ser nulo ( 0x00 ), /r , | , o los caracteres & como estos causan que el archivo por lotes salga a través de una terminación normal (es decir, "comando no válido detectado"). Utilicé el 0x01 para demostrar que no tenía que ser un comando válido (o un carácter imprimible para el caso) para inducir el error, un archivo por lotes de 2 bytes que contenga simplemente a^ será suficiente.

Haciendo algunas otras pruebas, encontré que la forma más rápida de comer memoria (y la más simple) con un archivo por lotes es la siguiente línea: ^ nul<^

... Al haber ejecutado esto inadvertidamente un par de veces, tenga en cuenta que esto paralizará un sistema de 64 bits bastante rápido; tardó aproximadamente 20 segundos en consumir los 14 GB restantes de RAM (16 GB en total) en mi núcleo cuádruple (HTT, 8 núcleos efectivos) i7, lo que hizo que mi máquina se volviera inútil mientras todo estaba intentando pasar página (tuve que reiniciar mi máquina). La ejecución de esta versión "rápida" en un sistema de 32 bits finalizó el analizador de comandos con un error de falta out of memory ya que agota rápidamente su límite de 2 GB de 32 bits. No bloquea el símbolo del sistema, en su lugar parece que hay una verificación para garantizar que la memoria no se encuentre correctamente malloc y, cuando no puede, interrumpe el procesamiento por lotes.

Diversión de errores encadenados

Sin embargo, tenga en cuenta que todos estos ''exploits de lotes'' pueden ''encadenarse'' juntos, por lo que en un sistema de 32 bits (suponiendo que solo tenía 4 GB de RAM sin PAE), se podría ejecutar el siguiente comando para preformar un DoS: cmd eat_mem.bat | eat_mem.bat cmd eat_mem.bat | eat_mem.bat (esto lanzará 2 analizadores de comandos y 2GB de escape cada uno).

Otra variación interesante es encadenar los archivos por lotes ''crash'' juntos; por ejemplo, suponiendo que hay un archivo llamado crash.bat y que contiene nuestro ''exploit crash'' desde arriba ( ^&^ ), puede hacer lo siguiente: cmd crash.bat | crash.bat cmd crash.bat | crash.bat y observe algún comportamiento interesante. Este en particular provoca que la salida de cmd crash.bat se escriba en un conducto que se ha bloqueado (debido al error del analizador) y, por lo tanto, da a wrote to a non-existent pipe errores de wrote to a non-existent pipe cuando intentas sacar CTRL+C de él; curiosamente, aunque todavía te permite ejecutar comandos, como escribir el notepad y presionar enter, se abrirá el bloc de notas. He explorado esto más para el posible secuestro de pipa pero todavía no tengo nada fructífero (más sobre ''exploits'' a continuación).

8K buffer

Como se ha aludido a la pregunta / respuesta de Desbordamiento de pila, cuanto más haya en una línea, más rápido se comerá la memoria (aparte de la versión ''rápida'' que encontré). A través de algunos experimentos más, descubrí que la "longitud de línea" también puede tener algunos efectos interesantes en este error. Si la última línea del archivo por lotes tiene un ^ al final del mismo y tiene exactamente 8192 bytes de longitud (incluido el símbolo de intercalación), el error falla ... Sin embargo, cualquier múltiplo inferior o superior de 8192 causa el error. Cuantos más bytes haya en una cadena, se consumirá la memoria más rápida (hasta un múltiplo de 8192). Este número 8192 es interesante ya que nuestra pérdida de memoria es de 8k (o en trozos más grandes).

Se debe tener en cuenta que el tamaño del archivo es irrelevante para el error y, debido a esto, se puede colocar en casi cualquier archivo por lotes inocuo. Como prueba coloco la versión ''rápida'' ( ^ nul<^ ) al final de un archivo por lotes que utilizo para compilar una gran cantidad de código heredado. Esta secuencia de comandos del compilador tiene poco menos de 21 KB con llamadas recursivas y funciones múltiples (para permitirme compilar ciertas cosas) y poner la línea "con errores" al final del archivo me permitió ejecutar el script de compilación como normal y completo como siempre, pero cuando golpeó el ''error'', mi CPU se activó y rápidamente se comió mi memoria.

Si fuera un ingeniero de software sin pretensiones con un script de compilación ''simple'' (con una llamada a :eof aleatoriamente allí ''forzando'' el error), no lo pensaría dos veces si el script de repente pateara mi CPU, y si no fuera así. Al prestar atención a mi administrador de tareas, no veo cuán rápido se comió mi memoria RAM y luego tengo que reiniciar (no es divertido).

Excavar más hondo

Desde aquí, decidí hacer algunas inspecciones de nivel superior para ver qué estaba sucediendo con el símbolo del sistema mientras ocurría esta filtración. Abrí las herramientas Process Explorer y Procmon para inspeccionar lo que estaba sucediendo en los procesos (en la pila con PE) y con el sistema (a través de Procmon). Procmon confirmó la fuga de 8k (más específicamente 8191 bytes) con una llamada a ReadFile con un búfer de 8191 bytes y PE confirmó las llamadas al kernel para ReadFile , aunque no estaba muy seguro de por qué se estaba leyendo el archivo por lotes.

Curiosamente, esta falla también permite que los archivos por lotes se modifiquen mientras se ejecutan y se vuelven a analizar (hasta 8k de ''análisis sintáctico'', alimentaciones de línea y todo). Cabe señalar que el contenido se puede modificar y se procesarán ciertos comandos, pero he notado que a menos que haya muchos otros comandos (más específicamente alimentaciones de línea antes del final ^ ), el tiempo también puede jugar un papel en el éxito de un lote modificado ''hackeo'' aunque sucede más a menudo que no (es decir, funciona la mayor parte del tiempo).

Estos exploits de lotes me llevan a preguntarme si lo mismo podría hacerse programáticamente; mi primer intento fue un simple programa C que simplemente tenía un system("crash.bat"); que llamó al archivo por lotes que contiene ^&^ en él. Esto lanzó un proceso separado de cmd.exe que posteriormente colapsó devolviendo el control a mi programa (todo esto era esperado). Luego cambié al archivo de fuga de memoria simple (contenía solo a^ ) y volví a ejecutar el programa, esta vez el cmd.exe ejecutó y comenzó a girar (como se esperaba), pero cuando presioné CTRL+C , el cmd.exe El proceso fue huérfano y el control regresó a mi programa, dejándome a mí para tener que finalizar el proceso rogue cmd.exe través del administrador de tareas. También intenté usar las líneas del archivo directamente en mi programa (es decir, llamar algo al efecto del system("^ nul<^"); ) pero obtuve resultados válidos (válido en este caso, lo que significa que el comando se consideró "inválido") por el analizador de comandos). Probé variaciones sobre cómo engancharme al proceso o aprovechar el error de desbordamiento de pila / marco, pero debido a que el cmd.exe es el analizador en sí, algunos de los exploits más obvios no serán tan fáciles. En este sentido, decidí abrir el proceso cmd.exe e inspeccionar el ensamblaje para verificar qué se filtraba y para comprender mejor qué estaba sucediendo y cómo podría explotarse (si es que lo hacía).

El código (cmd.exe)

Usé Visual Studio 2010 y lo adjunté a un proceso cmd.exe ejecución; luego, al usar el archivo ''sencillo'' de batch de pérdida de memoria ( a^ ) pausé el proceso para recorrer el ensamblado mientras el analizador estaba en el estado de error. Después de inspeccionar el ensamblaje y usar Process Explorer para verificar en qué módulo estaba durante la depuración, pude rastrear una gran cantidad del flujo de código y encontré donde el analizador buscaba el carácter ^ (hex 0x5E ). El siguiente es el flujo de ensamblaje, ya que puedo ver dónde está el problema.

Tenga en cuenta que gran parte del ensamblaje de la función ''main'' y ''analizando'' ha sido eliminado por brevities sake (código relevante publicado pero el volcado completo de lo que he encontrado está disponible bajo petición [1.2 MB de volcado de ASM con comentarios]):

; 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

En base a este ensamblaje, pude determinar que el código de análisis cmd.exe está haciendo algo como esto (código 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) } }

Esto es (por supuesto) una aproximación aproximada basada en la entrada / salida y el ensamblaje, pero parece que el código para obtener el siguiente carácter después del símbolo de intercalación es donde reside el problema.

El error explicado

El error es que cuando se detecta una intercalación, el siguiente carácter se lee del archivo (para ser ''escapado''). Si el símbolo de intercalación es el último carácter del archivo, se produce un error lógico, ya que cuando se realiza una llamada a get_next_char , el puntero del archivo se incrementa en uno; en este caso, eso lo hace pasar el EOF . Como el EOF se ignora efectivamente cuando el analizador de comandos continúa leyendo la siguiente entrada, esencialmente ''restablece'' su puntero de archivo debido al error EOF+1 . En este caso, al colocar el puntero del archivo en EOF+1 , el puntero estará en un número negativo grande, y como el archivo no puede ir por debajo de 0, básicamente el puntero del archivo se restablece a 0 y el análisis continúa desde el principio del archivo.

Esto explica las pérdidas de memoria y por qué es 8k (se está llenando un ''buffer de lectura'' de 8k), y también puede explicar el problema de la recursión. Cuando a | o & se detecta en el archivo de proceso por lotes, es analizado recursivamente, y dado que hay un error EOF la recursión se vuelve infinita ya que no se pueden tener rutas de retorno.

Editar : Como algunos comentarios han señalado, y la investigación adicional ha demostrado, el símbolo de intercalación no tiene que estar al final del archivo para que ocurra este error, actualmente estoy investigando (y desglosando más de los ASM) en ver si hay otros escenarios y por qué / cómo está sucediendo.

La solución

Parece que una solución simple sería verificar EOF en una lectura del siguiente caracter al analizar el cursor. Esta comprobación (y la subsiguiente funcionalidad ''aborto por lotes apropiado'') arreglaría el problema de pérdida de memoria así como la recursión infinita.

¿Exploits?

Después de inspeccionar más el proceso y pensar en posibles exploits, no veo que esto sea tan serio como MS14-019 , pero dada la facilidad de su uso / implementación (y la relativa facilidad de solucionarlo), consideraría este ''medio ''alerta de nivel ya que la mayoría de'' exploits ''requeriría que el usuario ejecute el archivo por lotes, y avenidas'' obvias ''como tratar de explotar el error de desbordamiento de pila / trama o lanzar código de shell a través de un archivo por lotes resultaría más difícil que otros muchos exploits eso produciría un resultado más ''fructífero'' frente a este inocuo error de lote. Aunque puedo ver que se usa en un ataque DoS, ya que es fácil escribir uno, dado que tiene 7 bytes ( ^ nul<^ ) y podría distribuirse y ''configurarse'' bastante fácil.

Aquí hay un vbscript simple que podría usarse para escribir y ejecutar el archivo por lotes ''asesino'' (y hacerlo todo en silencio)

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

Eso creará un archivo por lotes llamado killer.bat con un ^ nul<^/r en él y luego ejecutarlo, esto podría colocarse en un archivo .vbs y ejecutarse al inicio, o colocarse en una macro de Excel y ejecutarse.

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

Esa línea es la línea de comando equivalente para crear el archivo por lotes ''asesino'' (hacer un eco normal a un archivo daría como resultado un /r/n al final del archivo y, por lo tanto, el error no estará presente).

Como una prueba de concepto, creé este vbscript (así como algunas otras pruebas de archivos por lotes), y también los puse en mi carpeta de Startup y registro. Cuando entré, me saludaron con un símbolo del sistema cuando usaba los archivos por lotes y nada al usar el vbscript, y en unos pocos segundos mi sistema se detuvo y no se pudo usar porque el script había consumido toda mi memoria RAM. Los scripts pueden finalizarse matando el proceso cmd.exe ejecución, pero debido a que funcionan tan rápido, es posible que no tenga tiempo suficiente para iniciar el administrador de tareas antes de que consuma toda la memoria RAM. La eliminación a través del Safe Mode fue la "cura" para esto, pero no la "solución".

También podría imaginar un escenario en el que un administrador desprevenido ejecutará una backup.bat comandos backup.bat con este desafortunado error e inadvertidamente haciendo caer su servidor. O la diversión que podría tener con los comandos at / schtasks.exe en un sistema no schtasks.exe .

De acuerdo, no veo estos '' exploits '' dejando el reino de un DoS o una broma.

Todavía estoy inspeccionando varias avenidas con la canalización y la redirección de los guiones "rotos" que podrían conducir a un RCE, dado que el vector de ataque más simple es un ataque DoS con el archivo "rápido". He probado este error en Windows 98, 2000, XP, Vista, 7, 8 y las variaciones del servidor (para incluir sabores de 32 y 64 bits). El símbolo del sistema de Windows 98 no se ve afectado por esto, pero todas las versiones anteriores (para incluir command.com ya que usa cmd.exe para analizar los archivos por lotes). Por curiosidad también probé esto en ReactOS y Wine (ninguno de los cuales tenía el problema).

Preguntas (editadas después de más investigaciones)

Como dije, no creo que este error sea "explotable" más que un "ataque" de negación de servicio (o broma a un compañero de trabajo / amigo), pero me hizo pensar en general sobre el desbordamiento de marcos y pérdidas de memoria, más específicamente si son explotables (solo en general).

Mi experiencia y comprensión desde una perspectiva de ingeniería de software / pirata informático me dice que las fugas de memoria o el desbordamiento de marcos podrían explotarse potencialmente en un sistema operativo anterior (digamos Windows 98/2000 / XP o versiones anteriores de * nix?) Que no tienen ciertas protecciones en su lugar (como el uso del bit NX o ASLR) dadas las condiciones adecuadas, pero no he podido encontrar ninguna investigación en estas áreas aparte de los vectores de ataque "normales" (desbordamientos de búfer basados ​​en pila) o documentación general sobre qué estas cosas ''son'' (es decir, las discusiones del ''libro blanco'' sobre lo que es un desbordamiento de cuadro o pérdida de memoria y lo que son NX / ASLR) y no sobre ''por qué'' no se puede.

He estado experimentando con la inyección de un hilo o algún otro método en el proceso de ejecutar cmd.exe para ejecutar pruebas y analizar el desbordamiento del marco y la pérdida de memoria que se produce dentro de él (así como la diversión general que se puede tener con este error , como usar CreateProcess y EmptyWorkingSet para una diversión general) y sé que no voy a ''llegar a ninguna parte'' con este error en particular, pero me hizo pensar (o pensar más bien): ha habido alguna vez un exploit overflow exploit o fuga de memoria explotar en la naturaleza o hay alguna documentación que pueda leer que explique por qué (más específicamente / técnicamente) no es factible?

Entiendo el ''por qué'' pero sería más útil especificar más, como ''el registro de EIP está protegido porque XYZ ...'' en oposición a simplemente ''no, no es posible''; Sé que cada arquitectura es diferente y que podría estar pidiendo más detalles de los que podría tener en una respuesta, pero los enlaces o puntos de discusión que podría hacer referencia también son útiles, ya que no puedo encontrar demasiado en referencia a esto.

He estado nadando en asamblea, una nueva perspectiva siempre ayuda :)

Nota: Envié un correo electrónico (04/25/2014) a Microsoft con este error y han respondido diciendo que han reenviado esto al equipo de desarrollo y están investigando, no se ha planificado un boletín de seguridad (acéptelos en este como nada aún indica que es un defecto serio). Se editará si llegan más actualizaciones.