生成简单的 shell 二进制代码以复制到堆栈以进行堆栈溢出
Generating simple shell binary code to be copied to the stack for stack overflow
我正在尝试实施缓冲区溢出攻击,但我需要生成二进制指令代码,以便将其放入堆栈以供执行。我的问题是我现在得到的指令跳转到程序的不同部分,这变得很难放在堆栈上。所以我有一段简单的代码(不是要利用的代码),我想把它放在堆栈上以产生一个新的 shell.
#include <stdio.h>
int main( ) {
char *buf[2];
buf[0] = "/bin/bash";
buf[1] = NULL;
execve(buf[0], buf, NULL);
}
正在使用带有以下标志的 gcc 编译代码:
CFLAGS = -Wall -Wextra -g -fno-stack-protector -m32 -z execstack
LDFLAGS = -fno-stack-protector -m32 -z execstack
最后使用 objdump -d -S
,我得到以下十六进制代码(部分):
....
....
08048320 <execve@plt>:
8048320: ff 25 08 a0 04 08 jmp *0x804a008
8048326: 68 10 00 00 00 push [=13=]x10
804832b: e9 c0 ff ff ff jmp 80482f0 <_init+0x3c>
....
....
int main( ) {
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 e4 f0 and [=13=]xfffffff0,%esp
80483ea: 83 ec 20 sub [=13=]x20,%esp
char *buf[2];
buf[0] = "/bin/bash";
80483ed: c7 44 24 18 f0 84 04 movl [=13=]x80484f0,0x18(%esp)
80483f4: 08
buf[1] = NULL;
80483f5: c7 44 24 1c 00 00 00 movl [=13=]x0,0x1c(%esp)
80483fc: 00
execve(buf[0], buf, NULL);
80483fd: 8b 44 24 18 mov 0x18(%esp),%eax
8048401: c7 44 24 08 00 00 00 movl [=13=]x0,0x8(%esp)
8048408: 00
8048409: 8d 54 24 18 lea 0x18(%esp),%edx
804840d: 89 54 24 04 mov %edx,0x4(%esp)
8048411: 89 04 24 mov %eax,(%esp)
8048414: e8 07 ff ff ff call 8048320 <execve@plt>
}
8048419: c9 leave
804841a: c3 ret
804841b: 90 nop
如您所见,这段代码很难复制到堆栈上。 execve
跳转到要执行的汇编代码的不同部分。有没有办法很好地获得一个可以紧凑地放在堆栈上的程序,而不会使用太多 space 和分支?
欢迎来到 Stack Overflow(双关语)。
这是一个不寻常的请求。你想被美国国家安全局雇用吗?
显然,编译器不会以非常人性化的形式构建汇编代码。他们的优化想法可能是为了性能而不是为了紧凑。因此,您可以考虑在汇编程序中手动编码,使用编译器输出作为指导来实现您想要的效果。
你所拥有的可能不是编译器在任何情况下都可以为你的调查提供信息的最佳表现。将代码放入除 main 之外的函数中,这样您就可以获得最小的堆栈设置和必要的参数处理,并尝试使用所有不同的优化级别对其进行编译以查看它的作用。
你 可能 将它放在 main() 中会得到一些额外的设置开销,因为它是你程序的主要入口点并且必须与 libc 和 OS(只是猜测),并且可能正在为程序的一般操作上下文进行设置(您可以假设对于您插入代码的任何可执行文件都已经完成,因此它是多余的)。
如果您想要干净的汇编代码而不需要自己编写代码,请执行以下操作:
- 将您的代码移至单独的函数
- 将 -O0 编译标志传递给 gcc 以防止优化
- 只编译目标文件 - 使用
gcc [input file] -o [output file]
按照这些步骤,使用从 objdump 生成的汇编代码。
请记住,您对 execve 有外部依赖:
8048414: e8 07 ff ff ff call 8048320 <execve@plt>
所以你必须明确地包含它的实现并删除调用,或者事先知道你要攻击的进程在它的地址 space 中有这个函数,并修改调用地址以匹配进程 execve 地址。
我正在尝试实施缓冲区溢出攻击,但我需要生成二进制指令代码,以便将其放入堆栈以供执行。我的问题是我现在得到的指令跳转到程序的不同部分,这变得很难放在堆栈上。所以我有一段简单的代码(不是要利用的代码),我想把它放在堆栈上以产生一个新的 shell.
#include <stdio.h>
int main( ) {
char *buf[2];
buf[0] = "/bin/bash";
buf[1] = NULL;
execve(buf[0], buf, NULL);
}
正在使用带有以下标志的 gcc 编译代码:
CFLAGS = -Wall -Wextra -g -fno-stack-protector -m32 -z execstack
LDFLAGS = -fno-stack-protector -m32 -z execstack
最后使用 objdump -d -S
,我得到以下十六进制代码(部分):
....
....
08048320 <execve@plt>:
8048320: ff 25 08 a0 04 08 jmp *0x804a008
8048326: 68 10 00 00 00 push [=13=]x10
804832b: e9 c0 ff ff ff jmp 80482f0 <_init+0x3c>
....
....
int main( ) {
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 e4 f0 and [=13=]xfffffff0,%esp
80483ea: 83 ec 20 sub [=13=]x20,%esp
char *buf[2];
buf[0] = "/bin/bash";
80483ed: c7 44 24 18 f0 84 04 movl [=13=]x80484f0,0x18(%esp)
80483f4: 08
buf[1] = NULL;
80483f5: c7 44 24 1c 00 00 00 movl [=13=]x0,0x1c(%esp)
80483fc: 00
execve(buf[0], buf, NULL);
80483fd: 8b 44 24 18 mov 0x18(%esp),%eax
8048401: c7 44 24 08 00 00 00 movl [=13=]x0,0x8(%esp)
8048408: 00
8048409: 8d 54 24 18 lea 0x18(%esp),%edx
804840d: 89 54 24 04 mov %edx,0x4(%esp)
8048411: 89 04 24 mov %eax,(%esp)
8048414: e8 07 ff ff ff call 8048320 <execve@plt>
}
8048419: c9 leave
804841a: c3 ret
804841b: 90 nop
如您所见,这段代码很难复制到堆栈上。 execve
跳转到要执行的汇编代码的不同部分。有没有办法很好地获得一个可以紧凑地放在堆栈上的程序,而不会使用太多 space 和分支?
欢迎来到 Stack Overflow(双关语)。
这是一个不寻常的请求。你想被美国国家安全局雇用吗?
显然,编译器不会以非常人性化的形式构建汇编代码。他们的优化想法可能是为了性能而不是为了紧凑。因此,您可以考虑在汇编程序中手动编码,使用编译器输出作为指导来实现您想要的效果。
你所拥有的可能不是编译器在任何情况下都可以为你的调查提供信息的最佳表现。将代码放入除 main 之外的函数中,这样您就可以获得最小的堆栈设置和必要的参数处理,并尝试使用所有不同的优化级别对其进行编译以查看它的作用。
你 可能 将它放在 main() 中会得到一些额外的设置开销,因为它是你程序的主要入口点并且必须与 libc 和 OS(只是猜测),并且可能正在为程序的一般操作上下文进行设置(您可以假设对于您插入代码的任何可执行文件都已经完成,因此它是多余的)。
如果您想要干净的汇编代码而不需要自己编写代码,请执行以下操作:
- 将您的代码移至单独的函数
- 将 -O0 编译标志传递给 gcc 以防止优化
- 只编译目标文件 - 使用
gcc [input file] -o [output file]
按照这些步骤,使用从 objdump 生成的汇编代码。
请记住,您对 execve 有外部依赖:
8048414: e8 07 ff ff ff call 8048320 <execve@plt>
所以你必须明确地包含它的实现并删除调用,或者事先知道你要攻击的进程在它的地址 space 中有这个函数,并修改调用地址以匹配进程 execve 地址。