【问题标题】:How can I explain the behavior of the following shellcode exploit?如何解释以下 shellcode 漏洞利用的行为?
【发布时间】:2010-11-08 18:05:33
【问题描述】:

这是一个利用bufferoverflow漏洞的shellcode。它设置setuid(0) 并使用execve() 生成一个shell。以下是我的解释方式:

xor    %ebx,%ebx       ; Xoring to make ebx value 0
lea    0x17(%ebx),%eax ; adds 23 to 0 and loads effective addr to eax. for setuid()
int    $0x80           ; interrupt
push   %ebx            ; push ebx
push   $0x68732f6e     ; push address // why this address only????
push   $0x69622f2f     ; push address // same question
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
cltd                   ; mov execve sys call into al
mov    $0xb,%al
int    $0x80           ; interrupt

谁能解释清楚整个步骤?

【问题讨论】:

    标签: assembly x86 buffer-overflow exploit shellcode


    【解决方案1】:

    int 是触发软件中断的操作码。软件中断被编号(从 0 到 255)并由内核处理。在 Linux 系统上,中断 128 (0x80) 是系统调用的常规入口点。内核期望寄存器中的系统调用参数;特别是,%eax 寄存器标识了我们正在谈论的系统调用。

    1. 将 %ebx 设置为 0
    2. 计算 %ebx+23 并将结果存储在 %eax 中(操作码为 lea 作为“加载有效地址”,但不涉及内存访问;这只是一种狡猾的加法方式)。
    3. 系统调用。 %eax 包含 23,表示系统调用为setuid。该系统调用使用一个参数(目标 UID),可以在 %ebx 中找到,该参数在该点方便地包含 0(它是在第一条指令中设置的)。注意:返回时,寄存器不会被修改,除了 %eax 包含系统调用的返回值,通常为 0(如果调用成功)。
    4. 将 %ebx 压入堆栈(仍为 0)。
    5. 将 $0x68732f6e 推入堆栈。
    6. 将 $0x69622f2f 推入堆栈。由于堆栈“向下”增长并且由于 x86 处理器使用小端编码,指令 4 到 6 的效果是 %esp(堆栈指针)现在指向 12 个字节的序列,值为 2f 2f 62 69 6e 2f 73 68 00 00 00 00(十六进制)。这就是“//bin/sh”字符串的编码(以零结尾,然后是三个额外的零)。
    7. 将 %esp 移动到 %ebx。现在 %ebx 包含一个指向上面构建的“//bin/sh”字符串的指针。
    8. 将 %eax 压入堆栈(此时 %eax 为 0,即从 setuid 返回的状态)。
    9. 将 %ebx 压入堆栈(指向“//bin/sh”的指针)。指令 8 和 9 在堆栈上构建了一个由两个指针组成的数组,第一个是指向“//bin/sh”的指针,第二个是 NULL 指针。该数组是 execve 系统调用将用作第二个参数的数组。
    10. 将 %esp 移动到 %ecx。现在 %ecx 指向使用指令 8 和 9 构建的数组。
    11. 将 %eax 符号扩展为 %edx:%eax。 cltd 是 AT&T 的语法,英特尔文档称之为 cdq。由于此时 %eax 为零,因此这也将 %edx 设置为零。
    12. 将 %al(%eax 的最低有效字节)设置为 11。由于 %eax 为零,因此 %eax 的整个值现在为 11。
    13. 系统调用。 %eax (11) 的值将系统调用标识为execveexecve 需要三个参数,在 %ebx(指向要执行的文件的字符串的指针)、%ecx(指向字符串指针数组的指针,它们是程序参数,第一个是程序名称的副本, 供被调用程序本身使用)和 %edx(指向字符串指针数组的指针,它们是环境变量;对于空环境,Linux 允许该值为 NULL)。

    所以代码首先调用setuid(0),然后调用execve("//bin/sh", x, 0),其中x指向一个由两个指针组成的数组,第一个是指向“//bin/sh”的指针,而另一个是NULL。

    这段代码非常复杂,因为它想避免零:当组装成二进制操作码时,指令序列仅使用非零字节。例如,如果第 12 条指令是 movl $0xb,%eax(将整个 %eax 设置为 11),那么该操作码的二进制表示将包含三个字节的值 0。缺少零使得该序列可用作内容一个以零结尾的 C 字符串。当然,这是为了通过缓冲区溢出攻击有缺陷的程序。

    【讨论】:

    • Pomin:实际上,代码很复杂,因为它试图尽可能小。那个是 Gera 从 Core Security 使用的一个著名的 24 字节 shellcode 的修改版本(我希望我的署名是正确的,我不知道如何在网上搜索该代码的最早出现)。跨度>
    猜你喜欢
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多