Hola de nuevo Mañana comenzaremos las clases en un nuevo grupo en el curso
"Ingeniería inversa" . Tradicionalmente compartimos con usted la traducción de material útil sobre el tema. Vamos!
Es importante para algunos atacantes que el exploit sea extremadamente confiable. Siempre debe conducir a la ejecución de código cuando se inicia en un sistema con una plataforma y versión conocidas de Flash. Para crearlo, puede usar errores especialmente de alta calidad. Este artículo describe el uso de uno de estos errores, así como los factores que lo hacen particularmente adecuado para una operación confiable.
BugCVE-2015-3077 es un problema de confusión de tipos en los
configuradores de filtros de Adobe Flash
Button y
MovieClip , que le permite confundir cualquier
tipo de filtro con cualquier otro. Lo informé a principios de diciembre de 2015 y en mayo se solucionó. El error se produce porque el cracker puede sobrescribir el constructor utilizado para inicializar el objeto de filtro. A continuación se presenta un código de muestra que reproduce el problema:

Este código es algo confuso debido al uso del operador [], que es necesario para la compilación en Flash CS. El código lógicamente equivalente (que no es un hecho que compila) se da a continuación:

Este código establece el campo de filtro del objeto: Botón o MovieClip en BlurFilter, que luego se almacena directamente en Flash. El constructor ConvolutionFilter sobrescribe el constructor BlurFilter. Después de eso, se llama al captador y se crea un objeto ActionScript para almacenar el BlurFilter original. Sin embargo, el constructor ya se ha sobrescrito, por lo que se llama ConvolutionFilter. Esto produce un objeto de tipo ConvolutionFilter, respaldado por la devolución del BlueFilter original.
Finalmente, se puede acceder a los campos de ConvolutionFilter (leer y escribir) como si pertenecieran a BlurFilter. De manera similar para cualquier otro tipo de filtro. Esto abre una amplia gama de manipulaciones útiles para explotar.
El siguiente diagrama muestra la ubicación de los objetos originales en la memoria que podrían confundirse con esta vulnerabilidad en Linux de 64 bits.

En dos casos, los punteros son comparables a los enteros y los números de coma flotante que pueden manipularse. Esto significa que los punteros se pueden leer y escribir directamente. Además, dado que los campos de los objetos están ordenados y ordenados por tamaño de acuerdo con la definición de la clase, siempre están en lugares predecibles, de modo que la escritura y la lectura no fallan. Estas propiedades son importantes para garantizar la fiabilidad del exploit.
ExplotarDado que la explotación de este problema requiere ejecutar repetidamente la confusión de tipos, comencé creando una función de utilidad para la confusión de tipos,
FilterConfuse.confuse . También ordena las cosas: devuelve los constructores de filtros de ActionScript a su estado normal para llamar repetidamente a una función vulnerable sin afectar el comportamiento de ActionScript fuera de la función misma.
El primer paso fue evitar ASLR definiendo la dirección de la tabla de funciones virtuales (brevemente vtable). La forma ideal para esto es confundir un objeto con una tabla virtual con un objeto en el que hay un elemento que se superpone a la tabla virtual que se puede manipular. Pero la vtable de todos los objetos de filtro tiene el mismo desplazamiento. En cambio, utilicé el
objeto BitmapData en DisplacementMapFilter para determinar la dirección vtable.
Para determinar la ubicación en la memoria BitmapData del objeto, confundí DisplacementMapFilter con BevelFilter. Esto hizo que el puntero BitmapData almacenado en DisplacementMapFilter se alineara con las propiedades de color
BevelFilter (
shadowColor ,
shadowAlpha ,
highlightColor y
highlightAlpha ). Estas propiedades son compatibles con dos enteros de 32 bits (mostrados como scolor y hcolor arriba y abajo), y las propiedades de color acceden a 24 bits de cada entero, mientras que las propiedades alfa acceden a los 8 bits superiores. Si lee estas propiedades y las combina utilizando aritmética de bits, puede extraer la dirección inmediata BitmapData del objeto.

Luego, debe leer la vtable desde la parte superior del objeto BitmapData. Para esto, utilicé la propiedad de
matriz del objeto ConvolutionFilter. Se almacena como un puntero a una matriz de números de coma flotante, bajo la cual se asigna memoria al establecer la propiedad, y una matriz de ActionScript que contiene estos números se devuelve cuando se recibe la propiedad. Al establecer el puntero matricial en un objeto BitmapData, puede leer el contenido de este objeto de la memoria como una matriz de números de punto flotante.
Para configurar el puntero, confundí el objeto ConvolutionFilter con el objeto DisplacementMapFilter (¡no es el mismo DisplacementMapFilter utilizado anteriormente!) Y configuré la ubicación de BitmapData del objeto arriba en la propiedad
mapPoint . La propiedad mapPoint es un punto con coordenadas enteras x e y (p_x y p_y en la figura a continuación) que corresponden al puntero de matriz en ConvolutionFilter, lo que facilitó la configuración de este valor. Después de eso, se hizo posible leer la vtable del objeto BitmapData usando una matriz de matriz del objeto ConvolutionFilter (vale la pena señalar que para esto el objeto tuvo que confundirse con DisplacementBitmapFilter, y luego confundirse nuevamente con ConvolutionFilter).

En este punto, se hace más difícil mantener la confiabilidad del exploit debido al uso de números de coma flotante. Los valores vtable_low y vtable_high se leen de la matriz ConvolutionFilter como números de punto flotante, ya que este es un tipo de matriz. Pero, desafortunadamente, no todos los valores de puntero válidos son números de coma flotante válidos. Esto significa que leer el valor devolverá NaN, o peor, un valor numérico no del todo correcto.
Idealmente, para resolver este problema, debe acceder a vtable_low y vtable_high a través de un getter, que los interpreta como enteros, pero esto no se debe a que los elementos de filtro suelen ser flotantes debido a su funcionalidad.
Afortunadamente, la máquina virtual AS2 es lo suficientemente floja como para interpretar números de coma flotante: solo convierte un valor en flotante cuando se realiza una operación en ActionScript. Las operaciones originales generalmente no requieren interpretación, excepto las especiales como la aritmética. Esto significa que al copiar un número de coma flotante de una matriz de matriz a vtable_low o vtable_high, retendrá su valor en la memoria, incluso si no es válido para flotante, mientras que la variable en la que se copió no se usa en ActionScript o para realizar operaciones aritméticas en el nativo código Por lo tanto, si el valor de una variable se confunde instantáneamente con otro tipo que admite el rango completo de valores de 32 bits, por ejemplo int, se garantiza que será el mismo que el valor original en la memoria de la matriz. Por lo tanto, para evitar la falta de fiabilidad en el exploit, es importante llevar a cabo la confusión de tipos antes de manipular flotantes en ActionScript.
Para hacer esto, escribí una clase de conversión,
FloatConverter , usando la confusión de tipos en los filtros para implementar funciones de entero a flotante y de flotante a entero. Confunde la propiedad de
matriz ColorMatrixFilter (no la confunda con la propiedad de matriz ConvolutionFilter), que es un conjunto de flotadores incorporados, con las propiedades de
color y
alfa GlowFilter que acceden a diferentes bytes int.

De esta manera, puede implementar una conversión confiable de un flotante a un int, pero, desafortunadamente, esto no funciona de manera confiable en la dirección opuesta. Para acceder a la matriz de colores en ColorMatrix en ActionScript, se copia toda la matriz, incluso si solo accede a la primera. Al copiar una matriz, cada elemento se convierte en Número, que incluye una llamada a punteros (por ejemplo, llamar al valor de un objeto). Dado que la matriz de colores es la más larga de toda la clase GlowFilter, se acumula cuando se confunde con GlowFilter. Esto significa que puede producirse la conversión de valores desconocidos de este montón, lo que provocará un bloqueo si se refieren a punteros no válidos al convertir a Número. Por lo tanto, para int-to-float, implementé un convertidor flotante usando otra confusión ConvolutionFilter y DisplacementMapFilter, que es una conversión directa y no causa valores desconocidos del montón.

Esto resuelve el problema de los bloqueos causados por el acceso a valores desconocidos desde el montón, pero, desafortunadamente, hay otro problema de confiabilidad asociado con flotantes en este exploit. Se debe a la implementación del captador de matriz ConvolutionFilter. Todos los valores numéricos en ActionScript 2 son del tipo Número, que es la unión de un número entero y un puntero en un número doble. La matriz original de ConvolutionFilter se almacena como una matriz de números de coma flotante, pero se copia a la matriz de ActionScript para preservar el acceso cuando se llama al captador de matriz, y los valores se convierten en dobles en el proceso. Luego, cuando se llama al convertidor flotante, se convierten nuevamente a números de coma flotante.
Lanzar un número de coma flotante a un número de doble precisión y viceversa generalmente guarda su valor, pero no si el valor flotante es SNaN. Según la especificación de coma flotante, hay dos tipos de NaN: NaN silencioso (QNaN) y NaN de señal (SNaN). Cuando aparece QNaN, no sucede nada, pero SNaN en algunos casos arroja una excepción de punto flotante. En x86, la conversión de doble a flotante siempre da como resultado QNaN (incluso si el doble proviene de SNaN) para evitar excepciones inesperadas.
Por lo tanto, si los bits más bajos del puntero son SNaN, se convertirá a QNaN, lo que significa que el primer bit (el primer bit mantisa, bit 22) se establecerá cuando no debería. Este problema se puede evitar al leer vtable: el tercer byte del puntero que contiene el primer bit se puede leer sin alineación para confirmar el valor presente. Por lo tanto, el código se leerá sin alineaciones (después de leer la vtable nuevamente con el puntero de mapa de bits aumentado en uno) y ajustar el valor int si el flotador resulta ser SNaN.
Usando los convertidores flotantes descritos anteriormente, la dirección vtable se puede convertir en un entero. Ahora necesita obtener el código para ejecutar usando esta dirección. Una manera fácil de mover el puntero de instrucciones es sobrescribir la vtable del objeto (o un puntero a un objeto que tenga una vtable). Esto se puede hacer confundiendo la matriz de matriz ConvolutionFilter y el BitmapData del puntero DisplacementFilter.
El final de la primera parte. La segunda parte de la traducción se publicará un poco más tarde, y ahora estamos esperando sus comentarios e invitamos a todos al curso de
ingeniería inversa de OTUS.