sábado, 18 de junio de 2016

Bypassing de filtros mediante archivos BMP

¡Saludos!

    Después de la prueba del PixelShop del PlaidCTF he tenido ganas de trastear un poco con ficheros políglotas ( recomiendo encareciedamente echar un vistazo a esta presentación de Ange Albertini al respecto => https://events.ccc.de/congress/2014/Fahrplan/system/attachments/2562/original/Funky_File_Formats.pdf ).

   La prueba de PixelShop se resolvía embebiendo un payload dentro de un PNG, el cual lo creabas "a mano" (en realidad podías meter todos los valores en un JSON directamente) cogiendo pixeles como si se tratase de hama beads.





  
     Al introducir los píxeles adecuados, los bytes de la imagen conformaban un zip que podía ser cargado desde un LFI y así tener una webshell desde la que obtener el flag. Hay un post muy interesante sobre embeber webshells en los IDAT de los PNGs que recoge esta misma idea => https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

    Esta mañana me he acordado que había leído hace mucho tiempo de cómo conseguir una shell desde paint, creando una imagen BMP y pintandola con unos colores concretos ( http://www.flu-project.com/2012/06/como-obtener-una-shell-con-el-paint_11.html). Si probamos a crear una imagen con esos mismos valores, veremos cómo nos spawnea una shell:


God Bless Python



La renombramos a shell.bat y ¡pum!
Imagen ampliada. 6x1 píxeles no llegan a verse :P

  Bien, parece que no nos engañaban. Por algún tipo de arte arcano maldito hemos pintado una imagen y hemos obtenido una shell interactiva. ¿Qué está pasando aquí? Veamos el contenido de la imagen:



Misterio resuelto
   Resulta que esa combinación de colores se traduce en saltos de línea y un "cmd.exe". Los archivos .bat son en realidad lotes de comandos, por lo que se ejecutan línea  a línea y da igual si la línea anterior no tiene sentido. Si se vuelve a observar la imagen vemos que intentó ejecutar un primer comando sin sentido, y despues hizo un cmd.exe, que es lo que nos ha dado el premio.
  
     En el caso del formato BMP, cada píxel es almacenado en forma de array donde (en el caso de 24bits RGB) la información de cada píxel aparece subdivida en 3 valores (entre 0 y 255) que se corresponden con la información para el rojo, verde y azul. Por lo tanto por cada píxeles vamos a tener 3 valores entre 0 y 255. O, si lo vemos desde otra perspectiva, vamos a poder guardar 3 caracteres en cada píxel.

   Ésto es lo que básicamente hacemos con el paint: pasarle valores decimales, que serán pasados a hexa y darán caracteres para formar el salto de línea (0d0a) y el cmd.exe. Pero, si prestamos atención a los valores que nos piden colocar en cada color, el orden es diferente al que despues vemos. Esto es porque en realidad se almacenan en orden "B G R".  Conociendo esto, podemos picarnos un ñapa-script que nos permita meter como píxeles cualquier valor (o archivo):

https://github.com/0verl0ad/polyglot-PoC/blob/master/polybmp.py
   Con este simple script podemos embeber texto (para introducir una webshell, por ejemplo, o hacer .bat más complejos) u otros formatos que cuyos parsers sean más laxos (por ejemplo el caso de los ZIP, que empiezan a detectarse las firmas desde el final):

Funciona con casi todos los parsers. El wrapper de PHP se resiste :(
Metiendole un par de líneas más podemos hacer que nos imprima qué colores deberíamos de usar en paint si queremos obtener el mismo fichero a mano:


Ahora bien, ¿para qué nos sirve esto? Almacenar los payloads dentro de los propios pixeles permiten tener un archivo políglota, siendo un BMP a todos los efectos. De esta forma ningún filtro puede bloquearlo, y mejor aún, si lo que intenta hacer el filtro es reconstruir la imagen pixel a pixel, la imagen resultante seguirá teniendo nuestro payload. Eso es una ventaja frente a incluirlo como un apéndice al final del fichero o en los metadatos, ya que en estos casos se perdería.


Byt3z!




5 0verl0ad Labs: Bypassing de filtros mediante archivos BMP ¡Saludos!     Después de la prueba del PixelShop del PlaidCTF he tenido ganas de trastear un poco ...

3 comentarios:

SmartGenius dijo...

Seria mejor crear los archivos desde la forma Hexadecimal, pues desde Paint no se pueden controlar los "Padding Bytes"
http://www.redinfocol.org/stegano-bmp-padding-bytes/
Saludos.

The X-C3LL dijo...

Buenas!

El problema de utilizar los padding bytes es que estás limitado a un máximo de 3 bytes por línea, segmentando totalmente el contenido. Es útil para ocultar información, pero no para por ejemplo, albergar un zip en su interior, ya que el contenido estaría fragmentado y no sería reconocido por ningún programa.

Un saludo!

SmartGenius dijo...

No me referia a eso, es una tecnica distinta, lo que queria decir es que Paint rellenara esos bytes con 0's luego seria mejor crear el BMP directamente manipulando los datos en HEXA como lo haces con el script en Python, en todo caso buena entrada y un saludo igualmente :)

< >