【问题标题】:Assembly works, but shellcode does not [closed]汇编有效,但 shellcode 不[关闭]
【发布时间】:2018-02-26 05:42:57
【问题描述】:

我有一个 x64 处理器,我正在研究 shellcode。
我有以下代码:

section .text
  global _start

_start:
   push rax
   mov rbx, 0x68732f6e69622f2f
   shr rbx, 0x8
   push rbx
   mov rdi, rsp
   ;mov rdi, com

   mov al, 59
   syscall

用傻逼命令编译时:

nasm -g -f elf64 execve.asm  

并与:

ld execve.o -o execve

运行良好。它打开一个外壳。如果我从中得到 shellcode:

"\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

并使用这个 C 程序:

int main(void)
{
    const char shellcode[] = "\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05";

    (*(void (*)()) shellcode)();

    return 0;

} 编译它:

gcc -fno-stack-protector -z execstack -o ex2 ex.c

如果运行它会返回一个分段错误,但它应该执行一个 shell。为什么? 帮助表示赞赏!

【问题讨论】:

  • 您是否检查过shellcode 数组及其内容实际上已放入代码段,使其可执行?
  • 我猜是因为内存没有执行权限。
  • 感谢您的回复。我猜它有执行它的权限,因为它是用 gcc -fno-stack-protector -z execstack -o ex2 ex.c 编译的
  • @Ervin 尝试将shellcode 设为static const 变量。
  • 有什么理由用“//bin/sh”加载rbx然后右移,丢弃多余的前导'/'?

标签: c gcc assembly nasm shellcode


【解决方案1】:

您的独立程序集依赖于寄存器rsirdx 被归零。 (从http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/可以看出 sys_execve 通过寄存器rdirsirdx 接受三个参数,如果rdi 是正确的文件名并且rsirdx 为零,Linux 也会接受它。

程序启动时可能会出现这种情况,但在您从 程序中间。

因此,如果 rsirdx 中有垃圾,系统调用将失败,指令流 将继续执行它会在 syscall 指令之后找到的垃圾字节,最终导致崩溃(这确实是您的情况,如果您通过 gdb 运行程序可以看到)

使系统调用成功的最简单方法是将第二个和第三个参数置零:

section .text
  global _start

_start:
   xor rax, rax
   xor rsi, rsi ; zero 2nd argument
   xor rdx, rdx ; zero 3rd argument
   push rax
   mov rbx, 0x68732f6e69622f2f
   shr rbx, 0x8
   push rbx
   mov rdi, rsp

   mov al, 59
   syscall

对应的C代码:

int main(void)
{
 char shellcode[] =

"\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
;
    ((void (*)()) shellcode)();
    return 0;
}

【讨论】:

  • 感谢您的帮助!我将深入研究它以找出我的代码存在的问题。
  • @PSk,看起来这段代码假设 rax 为 0? (用于推送 argv 的空终止符。)
  • @prl 是的,确实如此。不过我改了。现在我将它显式归零,并将第二个和第三个参数归零到 execve,同时保持其余代码相同。这应该复制进程开始时的条件,这导致独立示例成功,不像嵌入它的 C 示例。
  • @PSkocik 这是一个非常好的解释。我喜欢。再次感谢您的帮助。
【解决方案2】:

你漏掉了\x6e

这会导致 segv,因为 exec 失败并且在 syscall 之后没有返回。

【讨论】:

  • 添加缺少的 6e 并不能解决问题。
  • 是的,我刚刚报告了我发现的第一个错误。还有其他人不足为奇。
  • 感谢您的帮助。我不知道我应该在末尾添加 6e,但令人惊讶的是它失败了,并出现了同样的错误。看起来问题出在 execve 调用中,这导致了错误,而不是指令结束。
  • 有3个问题:1)路径“/bin/sh”是“/bi/sh”; 2) rsi 和 rdx 在 syscall 之前没有被初始化; 3)系统调用后没有返回(所以当execv失败时会导致segv)。
  • @prl 路径正确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多