┌───────────────────────┐
                                                         ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
                                                         │ █   █ █ █ █   █       │
                                                         │ █   █ █ █ █▀▀▀▀       │
                                                         │ █   █   █ █     ▄     │
                                                         │                 ▄▄▄▄▄ │
                                                         │                 █   █ │
                                                         │                 █   █ │
                                                         │                 █▄▄▄█ │
                                                         │                 ▄   ▄ │
                                                         │                 █   █ │
                                                         │                 █   █ │
                                                         │                 █▄▄▄█ │
                                                         │                 ▄▄▄▄▄ │
Fuzz de radare2 pour trouver des 0Day en presque         │                   █   │
30 lignes de code                                        │                   █   │
~ Architect & S01den                                     └───────────────────█ ──┘

[ Traduction par @ZakCh3b ]

--- Abstrait  ---

Radare2 est un framework open-source bien connu pour la rétro-ingénierie ainsi que
l'analyse des binaires.

Ce genre d'outil est assez intéressant à analyser, à la recherche de 
vulnérabilités, car ils sont utilisés dans des domaines tels que l'analyse des 
logiciels malveillants.

Dans cet article, nous expliquerons comment nous avons découvert deux bugs 
(CVE-2020-16269 et CVE-2020-17487) à partir de zéro, en écrivant notre propre 
fuzzer stupide et en faisant un peu de rétro-ingénierie.

Dans une première partie, nous expliquerons comment nous avons fuzz radare2 et 
dans la seconde partie, nous allons voir comment nous avons utilisé les crashes 
trouvés par le fuzzing pour analyser, isoler et reproduire les bugs, en prenant 
comme exemple le bug lié à ELF (CVE-2020-16269).

--- Fuzz ---

Afin de trouver les deux vulnérabilités, nous avons appliqué un fuzzing stupide à
notre cible.

Le facteur clé pour faire du fuzzing stupide  est d'avoir un corpus diversifié en
termes de couverture de code.

Nous avons choisi d'utiliser la repo testbins de Radare2 [0].

Pendant le fuzzing, nous avons trouvé des crash dans les 30 minutes, dans 
plusieurs fichiers différents formats. Parmi les formats qui nous intéressent 
étaient PE et ELF, les deux formats executables les plus utilisés.

Sans plus attendre, voici une toute petite version de notre fuzzer.

----------------------------------- CUT-HERE -------------------------------------
import glob;import random;import subprocess;import hashlib

def harness(d):
    tf = open("wdir/tmp", "wb")
    tf.write(d)
    tf.close()
    try:
        p = subprocess.run(['r2','-qq', '-AA','wdir/tmp'], stdin=None, timeout=10)
    except:
        return
    try:
        p.check_returncode()
    except:
        print(f"Proc exited with code {p.returncode}")
        fh = hashlib.sha256(d).hexdigest()

        dump = open(f'cdir/crash_{fh}', 'wb')
        dump.write(d);dump.close()

def mutate(data):
    mutable_bytes = bytearray(data)
    for a in range(10):
        r = random.randint(0, len(mutable_bytes)-1)
        mutable_bytes[r] = random.randint(0,254)

    return mutable_bytes

if __name__ == '__main__':
    fs = glob.glob("corpus/*")
    while True:
        f = open(random.choice(fs), 'rb').read()
        harness(mutate(f))
----------------------------------------------------------------------------------

--- L'Exploitation ---

Ayant quelques exemples qui feront crash Radare2, voyons la raison derrière le 
crash.

Le premier est un ELF, une version mutée de dwarftest, un fichier d'exemple qui 
contient Informations DWARF.

==================================================================================
$ file dwarftest
---> dwarftest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically
linked, ...,with debug_info, not stripped
==================================================================================

Pour savoir quel octet déclenche le bug, nous analysons l'échantillon incriminé 
chargé avec Radare2 en utilisant un débogueur.

Alternativement, il est également viable de comparer l'échantillon original et 
muté afin trouver les octets intéressants.

Nous pouvons le faire facilement grâce à radiff2:
==================================================================================
$ radiff2 bins/src/dwarftest mutated_dwarftest
0x000010e1 00 => 01 0x000010e1
==================================================================================

Ce offset dans le fichier fait partie de la structure DWARF. Ceci n'est vrai que 
pour les binaires qui ont déjà des informations DWARF attachées, mais nous 
devrions être en mesure de créez des informations DWARF malformées et de les 
injecter dans n'importe quel ELF.

Pour comprendre pourquoi nos informations DWARF dérangent Radare2, nous pouvons 
jeter un coup d'œil avec objdump:
==================================================================================
$ objdump --dwarf=info mutated_dwarftest
...
    <4c> DW_AT_name :objdump: WARNING: the DW_FORM_strp shift is too
    large: 164 (indirect string, shift: 0x164): <shift too large>
...
==================================================================================

Eh bien, nous avons presque terminé.

Maintenant, il suffit de regarder comment nous pouvons l'exploiter. Pour ce faire,
il suffit de regarder la trace d'un crash avec gdb puis, analyser le code source 
de la fonction (radare2 étant heureusement un projet open-source) où le bug est
déclenché.

La ligne défectueuse est dans la fonction parse_typedef:
==================================================================================
name = strdup (value->string.content);
==================================================================================

Cela déclenche un déréférencement de pointeur nul lorsque la chaîne dupliquée est
NULL, et sans entrer dans les détails, nous avons compris grâce au pouvoir 
interdit du reverse engineering que c'est le cas lorsqu'un décalage dans 
DW_AT_name est trop important.

Maintenant, il est temps d'écrire un script qui peut modifier n'importe quel ELF 
pour déclencher le bug.

En annexe, vous pouvez trouver l'exploit complet, contenant l'exploitation du bug
PE (CVE-2020-17487, qui rend aussi simplement radare2 incapable de chargé le 
binaire)

--- Conclusion ---

Nous espérons que vous avez apprécié ce document.

Maintenant, vous savez qu'il n'est pas si difficile de trouver des bugs dans des
outils largement utilisés. 
Alors maintenant, essayez de les trouver vous-même (et surtout dans les outils de
rétro-ingénierie)!

Même si le bug n'est pas exploitable d'une autre manière qu'un DoS, planter un 
reverse outil d'ingénierie lors du chargement d'un binaire toujours utile ...

--- Notes et Références --- 

[0] https://github.com/radareorg/radare2-testbins

--- Appendix ---

- Exploit POC