【问题标题】:GDB - Assembly program returns /bin/sh: 0: Can't open �GDB - 汇编程序返回 /bin/sh: 0: 无法打开 �
【发布时间】:2017-04-09 04:38:57
【问题描述】:

我目前正在通过相关的 Pentester Academy 课程学习 64 位汇编语言。我正在处理的代码在 GDB 中运行时会产生以下错误:

/bin/sh: 0: 无法打开 � [Inferior 1(进程 4049)退出,代码 0177]

我用谷歌搜索了错误和退出代码,但没有发现任何有用的信息。我尝试一遍又一遍地分析 GDB 中的代码,但所有正确的值似乎都在正确的寄存器中。我似乎找不到问题所在。

您可以在下面找到代码。我的目标只是使用 jump-call-pop 技术调用 execve 系统调用。

global _start
section .text

_start:

jmp bash

code:

xor rax, rax
pop rdi
mov [rdi +7], al    

push rdi
mov rsi, rsp
push rax
mov rdx, rsp
mov al, 59
syscall 

bash:

call code 
string:     db      '/bin/shABBBBBBBBCCCCCCCC' 

编辑:

这是我构建程序的方式:

nasm -f elf64 -o execve_stack_jcp.o execve_stack_jcp.asm 
ld -o execve_stack_jcp execve_stack_jcp.o

然后我使用objdump -M intel -d execve_stack_jcp 输出反汇编,然后输入到这个 c 程序中:

#include <stdio.h>
#include <string.h>

unsigned char code[] = \
"\xeb\x13\x48\x31\xc0\x5f\x88\x47\x07\x57\x48\x89\xe6\x50\x48\x89\xe2\xb0\x3b\x0f\x05\xe8\xe8\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x41\x42\x42\x42\x42\x42\x42\x42\x42\x43\x43\x43\x43\x43\x43\x43\x43";

int main(void) {

printf("Shellcode length: %d\n", (int)strlen(code));

int (*ret)() = (int(*)())code;

ret();

return 0;
}

最后,我使用以下代码编译 c 程序:

gcc -fno-stack-protector -z execstack -o shellcode shellcode.c

【问题讨论】:

  • 你是如何构建这段代码的?
  • 当然,如果您使用 RiP(相对)寻址,则在 64 位代码中不需要 JMP/CALL/POP 方法。
  • 如果您展示了如何构建和执行程序,将会有所帮助。但一个观察结果是,execve argvargp 需要以 NULL 结尾的字符串列表,但您只能以 null 终止 argp(通过首先推送 rax)。您也需要 NULL 终止 argv。所以之前 push rdi你也应该做push rax
  • 我看到你更新了你的问题。你看到我关于 null 终止字符串数组 argv 的评论了吗?
  • 您好@MichaelPetch,感谢您的回答!无法理解我是如何错过的。附带说明一下,我知道 RIP 相对寻址技术,该程序仅用于了解 jump-call-pop 的工作原理;-)

标签: linux gcc assembly x86-64 shellcode


【解决方案1】:

execve 在 Linux 中是这样定义的:

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

[剪辑]

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

如果您通过strace ./shellcode 运行程序,您可能会看到与此类似的内容:

execve("/bin/sh", ["/bin/sh", "\270", "\1", "\353\23H1\300_\210G\7WH\211\346PH\211\342\ 260;\17\5\350\350\377\377\377/bin/s"...], [/* 0 vars */]) = 0

您会注意到第二个参数argv 在数组中有一堆额外的条目。这是因为您没有 NULL 终止 argv 数组。要纠正这个问题,您可以通过将 0(通过 RAX)推送到堆栈上来修改代码,如下所示:

xor rax, rax 
pop rdi
mov [rdi +7], al

push rax      ; NULL terminates the `argv` array
push rdi
mov rsi, rsp
push rax
mov rdx, rsp

如果您再次通过 strace 运行此更改,您会看到如下内容:

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

这应该是一个成功的execve 调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 2012-01-20
    相关资源
    最近更新 更多