【问题标题】:shellcode: pass arguments to execve in x86_64 assemblyshellcode:将参数传递给 x86_64 程序集中的 execve
【发布时间】:2013-10-21 19:00:51
【问题描述】:

我正在尝试编写一个运行 execve 的 shellcode。等效的 c 程序如下所示:

int main ()
{

  char *argv[3] = {"/bin/sh","-i", "/dev/tty", NULL};
  execve("/bin/sh", argv, NULL);

  return 0;
}

c 程序运行良好。然后我尝试像这样编写我的测试程序(修改为push null):

#include<stdio.h>
int main(){
    __asm__(
            "xor    %rdx,%rdx\n\t"   //rdx is the third argument for execve, null in this case.
            "push   %rdx\n\t"
            "mov    -8(%rbp),%rdx\n\t"
            "mov    $0x692d,%rdi\n\t" //$0x6924 is 'i-'
            "push   %rdi\n\t"         //push '-i' to the stack
            "lea    -16(%rbp),%rax\n\t"    //now rax points to '-i'
            "mov    $0x31b7f54a83,%rdi\n\t" //the address of /bin/sh
            "push   %rdi\n\t"                //push it to the stack              
            "push   %rdx\n\t"                //end the array with null
            "mov    $0x31b7e43bb3,%rdi\n\t"  //the address of "/bin/sh"
            "push   %rdi\n\t"              //push the address of "/dev/tty to the stack
            "push   %rax\n\t"              //push the address of '-i' to the stack
            "mov    $0x31b7f54a83,%rdi\n\t"
            "push   %rdi\n\t"              //push the address of /bin/sh again to the stack
            "mov    %rsp,%rsi\n\t"         //rsi now points to the beginning of the array
            "mov    -24(%rbp),%rdi\n\t"   //rdi now points to the addresss of "/bin/sh"
            "mov    $0x3b,%rax\n\t"               // syscall number = 59
            "syscall\n\t"
    );
    }

我在这里有内存中字符串的地址,我们可以假设它们不会改变。但是我们没有字符串'-i'的地址。所以我在这里所做的是将参数推入堆栈,如下所示:


Low                  ------------------------------------------------------------------             High

|addressof"/bin/sh"(rsi points to here)|addressof"-i"|addressof"/dev/ssh"|addressof"/bin/sh"(rdi points to here)|-i|

没有用。程序编译正常,但是当我运行程序时,什么也没发生。

我不熟悉汇编,我对参数的传递方式有些担心,例如,编译器如何知道 argv 参数何时在内存中结束?

编辑

感谢 Niklas B 下面的建议,我使用 trace 查看 execve 是否实际运行。我得到了execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3, 0x31b7f54a83, 0x692d], [/* 0 vars */]) = -1 EFAULT (Bad address),这意味着第二个参数传递错误。我推入堆栈的所有内容都被视为 argv 参数的一部分!

在我将空值压入堆栈后,strace 会给出execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3], [/* 0 vars */]) = -1 EFAULT (Bad address)。仅当地址是字符串时,这才非常接近正确答案...

感谢 Brian,我现在知道问题出在哪里了。硬编码地址在另一个程序的共享库中。因此,该程序在实际输入该程序之前不应运行。谢谢大家,我会尽快更新。如果问题已解决,我会将其标记为已解决。

【问题讨论】:

  • 空终止!空终止!
  • @KerrekSB 所以我也需要将 0x00 推入堆栈?
  • (并不是说这与您的问题有关。)数组需要由空指针终止。此外,将NULL 作为参数传递是不可移植的Linux hack,不应依赖。见the manual
  • 通过strace,可以验证系统调用是否真的被触发了。
  • @Gnijuohz 你从哪里得到地址0x31b7f54a830x31b7e43bb3 指向/bin/sh/dev/tty?根据strace 输出,这些字符串似乎不在您期望的位置。这些是否应该是字符串驻留在您将 shell 代码注入的目标程序中的位置?您实际上是将代码注入目标程序,还是只是独立运行它?如果您尝试独立运行它,这些字符串可能不存在于给定地址。

标签: c assembly shellcode


【解决方案1】:

正如 Kerrek SB 和 user9000 在 cmets 中指出的那样,argv 数组必须是一个以 null 结尾的字符串数组。

一旦修复,独立运行这个程序仍然无法工作,因为字符串"/bin/sh""/dev/tty" 可能不存在于您刚刚编译的程序的那个位置,而是存在于那个位置shell 代码设计目标的程序中的位置。您需要将其实际注入到该程序中,以便它将在那里执行,这些字符串位于这些地址处。

【讨论】:

  • 非常感谢,我会尽快接受您的答复。
  • 嗨,brian,它有效...但是当我将它用作缓冲区溢出攻击时,我总是遇到总线错误,知道为什么会这样吗?
  • @Gnijuohz 我不确定。您介意发布另一个问题,其中包含有关您的新问题的更多信息吗?显示您要注入的确切代码、注入的内容、执行方式以及获得的结果。最好在 GDB 遇到您的代码之前尝试中断它,然后逐步检查它以查看您在哪里得到总线错误。这可能会帮助您找到它,或者可能会为您提供足够的信息来提出一个新问题,以便有人可以帮助您。
  • 我不知道如何使用 gdb 来做到这一点。目标程序被提供像这样cat shellcodefile -| ./targetprogram 的shellcode。目标程序有一个缓冲区并使用gets 从输入中读取。我应该像这样cat shellcodefile -| gdb ./targetprogram 使用 gdb 吗?然后使用 step 来单步执行?我对gdb真的不熟悉。
  • 嗨,Brian,我已经在此处发布了这个问题:stackoverflow.com/questions/19534658/… 你能看一下吗?
猜你喜欢
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2019-06-05
相关资源
最近更新 更多