封闭系统shellcode实验(segfault)

时间:2015-06-12 20:49:25

标签: c sockets segmentation-fault shellcode experimental-design

我正在参加在线软件安全课程。我试图尝试shellcode。我编写了一个易受攻击的服务器,一个注入程序,一个(可能已损坏)shellcode,我转换为程序集,然后我用python脚本剥离。然后我使用shell脚本编译并运行所有内容。我包含了所有文件,即使我非常确定我没有正确地创建shellcode二进制文件。

vulnerable.c

#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>


int main(void) {
    int sd, sdc, addrsize, ret, i;
    struct sockaddr_in addr;
    char exec[1024], buf[128];
    void (*fn)(void);
    const short family = AF_INET;

    fn = (void (*)(void))exec;
    addrsize = sizeof(struct sockaddr_in);
    sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
    if (sd < 0) {
        perror("socket");
        return 1;
    }
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8000);
    if (bind(sd, (struct sockaddr *) &addr, 
            sizeof(addr)) < 0) {
        perror("bind");
        return 2;
    }
    listen(sd, 1);
    sdc = accept(sd, (struct sockaddr *)&addr, &addrsize);
    i = 0;
    do {
        i += ret = read(sdc, buf, 128);
        memcpy(exec + i, buf, ret);
    } while (ret > 0);
    close(sd);
    fn();
    return 0;
}

inject.c

#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int sd, fd, ret, buflen = 128;
    struct sockaddr_in addr;
    FILE *f;
    const char fname[] = "shellcode";
    char buf[buflen];
    const short family = AF_INET;
    const char host[] = "127.0.0.1";

    f = fopen(fname, "r");
    fd = fileno(f);

    sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
    if (sd < 0) {
        perror("socket");
        return 1;
    }
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = family;
    addr.sin_port = htons(8000);
    inet_pton(family, host, &(addr.sin_addr.s_addr));
    ret = connect(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr));
    if (ret < 0) {
        perror("connect");
        return 2;
    }
    do {
        ret = read(fd, buf, buflen);
        if (write(sd, buf, ret) != ret)
            perror("write");
    } while (ret > 0);
    close(fd);
    close(sd);
    return 0;
}

shellcode.c

void shellcode(void) {
    char sz[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    write(1, sz, 6);
}

stripshellcode.py

copy = False
outf = open("shellcode-stripped.s", "w")
for line in open("shellcode.s").read().split("\n"):
    if copy:
        outf.write(line + "\n")
    if "shellcode:" in line:
        copy = True
    elif "ret" in line and copy:
        copy = False
outf.close()

make.sh

gcc -S shellcode.c && \
python stripshellcode.py && \
gcc -c shellcode-stripped.s -o shellcode && \
gcc inject.c -o inject && \
gcc vulnerable.c -o vulnerable && \
./vulnerable & ./inject

输出

$ sh make.sh
make.sh: line 6: 13905 Segmentation fault      ./vulnerable

在这个实验过程中我哪里出错?

编辑:

我应该注意&#34;封闭系统&#34;我的意思是这是在虚拟机中执行(检查绑定地址),这也意味着一些变量是以依赖的方式进行硬编码的,以简洁和轻松。

2 个答案:

答案 0 :(得分:1)

这不起作用,因为shellcode文件是一个目标文件。它是一种用于链接器使用的中间文件格式。将其视为一系列指令是完全错误的。对象文件包含代码等。但是这段代码不完整。当代码引用符号(如write)时,将插入占位符而不是地址。链接器的工作是将多个目标文件和库拼接在一起,在内存中布置代码,有效地为符号分配地址,最后修补占位符。

即使生成了可执行文件,它仍然无法工作,因为现代可执行文件格式需要加载程序才能运行。基本上,加载器读取存储在可执行文件中的元数据,将文件中的几个部分映射到内存中,调整内容并最终将控制转移到由元数据定义的入口点。

我认为有几种工作方法可以制作shellcode。

  1. 手动编码装配顺序。

  2. 使用工具为您进行编码。

  3. 研究对象文件格式并提取代码,我假设objdump可以为你做。

  4. 要求链接器以不需要加载程序运行的格式生成可执行文件。

  5. 阅读其他答案我意识到故障实际上发生得更早 - exec缓冲区在堆栈上分配,堆栈内存保护属性明确拒绝执行。可以使用Linux上的execstack实用程序关闭此保护。

答案 1 :(得分:0)

据我所知,您正在尝试使用缓冲区溢出来注入shell脚本。编译器在缓冲区周围添加保护,以防止您尝试执行的操作。您应该在编译易受攻击的应用程序时禁用它们。

我做了类似的实验,我使用了这个选项:

badbuf: vulnerable.c
    $(CC) -g -Wall -fno-stack-protector -o badbuf  vulnerable.c