【实验报告NO.000001】MIT 6.858 Computer System Security - Lab 1

0x00. 一切开始之前

MIT 6.858 是面向高年级本科生与研究生开设的一门关于计算机系统安全(secure computer security)的课程,内容包括威胁模型(threat models)、危害安全的攻击(attacks that compromise security)、实现安全的技术(techniques for achieving security)

在 YouTube 上有往年的课程回放,配有英文字幕,不过作为一个并非是对安全一无所知的安全小白,笔者主要还是挑自己不熟悉的那一块跳着听(笑)

这个课程一共有五个 Lab:

  • Lab1:缓冲区溢出(buffer overflow)
  • Lab2:权限分离与服务侧沙箱(privilege separation and server-side sandboxing)
  • Lab3:符号执行(symbolic execution)
  • Lab4:浏览器安全(browser security)
  • Lab5:安全的文件系统(secure file system)

前四个 Lab 主要是基于 MIT 开发的一个叫 zookws 的 web server 完成的

PRE. 环境搭建 && 说明

这里给出三种搭建实验环境的方式

Method I.(推荐)使用 MIT 提供的 VM 镜像

参见 Lab 1

MIT 提供了一个 course VM image ,其中有着一个 Ubuntu 21.10 的系统,登录的用户名为 student,密码为 6858,下载解压后根据自身的本地环境进行对应的操作:

  • 使用 KVM 运行:直接运行 ./6.858-x86_64-v22.sh 即可
  • 使用 VMware运行:新建虚拟机→稍后安装操作系统→选择系统 Linux > Debian 9.x 64-bit →移除原有虚拟磁盘→添加新的虚拟磁盘→选择 6.858-x86_64-v22.vmdk 即可

对于非 X86 架构的处理器环境,👴的建议是别做了,在实验手册里推荐安装 qemu ,笔者就不摘抄一遍了

image.png

当然没有图形界面只有一个 tty 比较难受,所以这里还是推荐用 ssh 连上去做,因为虚拟机在本地所以直接 ip addr show dev eth0 找到 IP 后 ssh student@YOUR_IP 就行:

image.png

之后还是按惯例把代码拉到本地,并使用 make 构建一下 zookws 看有没有啥问题,没报错就🆗:

$ git clone https://web.mit.edu/6858/2022/lab.git
$ cd lab
lab$ make

其中 zookd 负责接收 HTTP 请求,其由 C 编写,HTTP 相关的代码位于 http.c 中,HTTP 协议相关资料见此处

zookd 有两种版本:

  • zookd-exstack:栈具有可执行权限
  • zookd-nxstack:栈不具有可执行权限

用以进行评分的 zookd 位于 bin.tar.gz

此外,MIT 还提供了一个用以清理环境的 clean-env.sh 脚本,用以确保每次的执行环境都是相同的,我们可以通过如下命令运行 zookd:

$ ./clean-env.sh ./zookd 8080

之后我们便能在本地的 8080 端口访问到 zookd,直接进去大概会是这个样子:

image.png

Method II. 自行配置本地实验环境

首先是配环境,除了 pwntools 是笔者个人比较喜欢的一个编写 exp 的模块以外其他都是实验环境必须的:

$ sudo atp-get install -y curl strace lxc-dev
$ sudo pip3 install sqlalchemy pwntools flask z3-solver angr bytecode lxc

之后还是按惯例把代码拉到本地,并使用 make 构建一下 zookws 看有没有啥问题,没报错就🆗:

$ git clone https://web.mit.edu/6858/2022/lab.git
$ cd lab
lab$ make

Method III.使用 docker 搭建实验环境

因为评测用的二进制文件需要用较高版本的 libc(例如笔者用的就是 Ubuntu 20.04 with 过时的 libc2.31),同时也避免污染本地环境,因此使用 Docker 来完成实验也是一个需求项

Dockerfile,注意替换上自己的公钥,如果没有从外部连接容器的需求的话这一步可以跳过

FROM ubuntu:22.04

# basic environment
RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list && \
    apt-get update && apt-get -y dist-upgrade && \
    DEBIAN_FRONTEND=noninteractive \
    apt-get install -y git python3-pip tmux vim curl openssh-server strace gdb lxc lxc-dev

# sqlalchemy for lab, pwntools for my own
RUN pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip3 install sqlalchemy pwntools flask z3-solver angr bytecode lxc

# pwndbg for a better debug experience
RUN cd /root && \
    git clone https://github.com/pwndbg/pwndbg && \
    cd /root/pwndbg && \
    ./setup.sh

# I'd like to make a new user for it
RUN useradd -m student
RUN usermod -s /bin/bash student

# clone the lab
RUN cd /home/student && \
    git clone https://web.mit.edu/6858/2022/lab.git && \
    chown -R student:student ./lab

# make your ssh key authorized
RUN mkdir /home/student/.ssh && \
    echo "这里写你的ssh公钥" > /home/student/.ssh/authorized_keys

# start ssh service and keep container running continuously
RUN echo "#!/bin/bash\nservice ssh start\nsleep infinity" > /root/start.sh && \
    chmod +x /root/start.sh

CMD ["/root/start.sh"]

因为实验要关 ASLR 所以我们在启动 docker 时需要 --privileged,不过因为只是实验用的容器所以无所谓,同时为了外网能访问到所以这里配了几个端口转发:

$ sudo docker build -t "mit_6858_img" .
$ sudo docker run -d --privileged -p "8080:8080" -p "2022:22" -h "mit_6858_docker" --name="mit_6858" mit_6858_img

之后我们便能直接进到容器内部继续实验:

$ sudo docker exec -it mit_6858 /bin/bash

也可以通过 ssh 进行远程连接:

$ ssh student@your_server_ip -p 2022

image.png

EXTRA.vscode 连接

因为我们的实验环境都有 ssh,所以直接用 vscode 通过 ssh 连接是非常方便的一件事情(容器配上端口转发也可以连接)

首先在扩展里找到 ssh 插件并安装

image.png

添加 host 信息

image.png

之后直接连接上去就行了

image.png

0x01. Lab1: Buffer overflows

Part 1: Finding buffer overflows

首先给了一个资料:Smashing the stack in the 21st century,基础薄弱的同学可以仔细看看,笔者这里直接跳过,然后是 Exercise 1:

Exercise 1. Study the web server’s C code (in zookd.c and http.c), and find one example of code that allows an attacker to overwrite the return address of a function. Hint: look for buffers allocated on the stack. Write down a description of the vulnerability in the file answers.txt. For your vulnerability, describe the buffer which may overflow, how you would structure the input to the web server (i.e., the HTTP request) to overflow the buffer and overwrite the return address, and the call stack that will trigger the buffer overflow (i.e., the chain of function calls starting from process_client).

It is worth taking your time on this exercise and familiarizing yourself with the code, because your next job is to exploit the vulnerability you identified. In fact, you may want to go back and forth between this exercise and later exercises, as you work out the details and document them. That is, if you find a buffer overflow that you think can be exploited, you can use later exercises to figure out if it indeed can be exploited. It will be helpful to draw a stack diagram like the figures in Smashing the Stack in the 21st Century.

大概是阅读 zookd.chttp.c 找漏洞,提示关注在栈上分配的 buffer,并将答案写在 answers.txt 中~~(👴:❓)~~

首先看 zookd.c,源码比较简洁,核心逻辑在 run_server() 中,首先会调用 start_server() 创建一个 http 服务器,之后在 run_server() 中有一个无限循环调用 accept() 接收请求后 fork() 出子进程调用 process_client() 处理

process_client():处理单次 HTTP request

process_client() 的逻辑也比较简单,主要是调用 http_request_line() 获取请求头第一行,之后给到 env_deserialize() 解析环境变量,之后调用 http_request_headers() 解析剩下的 header,最后调用 http_serve() 处理

static void process_client(int fd)
{
   
    static char env[8192];  /* static variables are not on the stack */
    static size_t env_len = 8192;
    char reqpath[4096];
    const char *errmsg;

    /* get the request line */
    if ((errmsg = http_request_line(fd, reqpath, env, &env_len)))
        return http_err(fd, 500, "http_request_line: %s", errmsg);

    env_deserialize(env, sizeof(env));

    /* get all headers */
    if ((errmsg = http_request_headers(fd)))
      http_err(fd, 500, "http_request_headers: %s", errmsg);
    else
      http_serve(fd, getenv("REQUEST_URI"));

    close(fd);
}
http_request_line():解析 header 第一行

现在来看 http_request_line(),其首先调用了一个函数 http_read_line() 从 TCP 连接中读取一整行(read() 一个字节一个字节地读,一直读到 \n 并返回读取的字节数,对于 \r 自动跳过,失败则返回 -1,代码就不贴了)

const char *http_request_line(int fd, char *reqpath, char *env, size_t *env_len)
{
   
    static char buf[8192];      /* static variables are not on the stack */
    char *sp1, *sp2, *qp, *envp = env;

    /* For lab 2: don't remove this line. */
    touch("http_request_line");

    if (http_read_line(fd, buf, sizeof(buf)) < 0)
        return "Socket IO error";

之后解析路径与请求类型,主要就是用 strchr() 进行分隔后判断,并将结果写到 env

    /* Parse request like "GET /foo.html HTTP/1.0" */
    sp1 = strchr(buf, ' ');
    if (!sp1)
        return "Cannot parse HTTP request (1)";
    *sp1 = '\0';
    sp1++;
    if (*sp1 != '/')
        return "Bad request path";

    sp2 = strchr(sp1, ' ');
    if (!sp2)
        return "Cannot parse HTTP request (2)";
    *sp2 = '\0';
    sp2++;

    /* We only support GET and POST requests */
    if (strcmp
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验概述 本次实验是MIT 6.828操作系统课程的第一次实验,主要内容是编写一个简单的操作系统内核,并在QEMU虚拟机上运行。本次实验共有9个练习,其中练习9要求实现一个简单的用户程序并运行。 练习9要求我们实现一个简单的用户程序,该程序能够在屏幕上输出一些信息,并等待用户输入,输入结束后将输入内容输出到屏幕上。用户程序的具体要求如下: - 输出一些信息,例如“Hello World!”。 - 等待用户输入,可以使用getchar()函数实现。 - 将用户输入内容输出到屏幕上。 实验过程 1. 编写用户程序 我们首先在lab1目录下创建一个user文件夹,用于存放用户程序。然后创建一个名为“test.c”的文件,编写用户程序的代码如下: ``` #include <stdio.h> int main() { printf("Hello World!\n"); char c = getchar(); printf("You entered: %c\n", c); return 0; } ``` 这段代码的功能是输出“Hello World!”并等待用户输入,输入结束后将输入内容输出到屏幕上。 2. 修改Makefile文件 为了能够编译用户程序,我们需要修改Makefile文件。具体修改如下: ``` UPROGS=\ _cat\ _echo\ _forktest\ _grep\ _init\ _kill\ _ln\ _ls\ _mkdir\ _rm\ _sh\ _stressfs\ _usertests\ _wc\ _test\ # 添加用户程序的名称 $(OBJDIR)/_test: $(OBJDIR)/test.o $(LIBDIR)/ulib.o | $(OBJDIR) $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ $(OBJDIR)/test.o: test.c | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< ``` 在UPROGS变量中添加上刚刚编写的用户程序的名称“_test”,然后在Makefile文件的末尾添加如上代码。 3. 编译内核和用户程序 在终端运行命令“make”,编译内核和用户程序。 4. 运行QEMU虚拟机 在终端运行命令“make qemu”,启动QEMU虚拟机。 5. 运行用户程序 在QEMU虚拟机中,输入“test”,即可运行刚刚编写的用户程序。运行结果如下: ``` Hello World! This is a test. You entered: T ``` 可以看到,程序首先输出了“Hello World!”这个信息,然后等待用户输入。我们输入了“This is a test.”这个字符串,然后按下回车键,程序将输入内容输出到了屏幕上。 实验总结 本次实验要求我们实现一个简单的用户程序并运行。通过编写代码、修改Makefile文件、编译内核和用户程序、启动虚拟机以及运行用户程序等步骤,我们成功地完成了本次实验,并学会了如何在操作系统内核中运行用户程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值