Level 1
Task 1
在GNU/linux或服务器上使用
docker-compose在本地搭建Gitea验证标准: 在宿主机能够通过
ssh -p <port> git@localhost -T验证连接,或成功执行git clone ssh://git@localhost:<port>/...


Task 2
完成 SAST Rust 内核模块 的编译和运行
[加分项] CI/CD: 配置 GitHub Actions(或 GitLab CI),实现代码 Push 后自动构建 Docker 镜像并推送至镜像仓库 (Docker Hub / GHCR)
- [x]任务 1:找到并修复 tetris 模块中的 panic
- [x]任务 2:加载 magic.ko,用 ioctl 触发 flag <=> Task 4
- [x]任务 3:给这个仓库加上 CI/CD + 产出 OCI 镜像
- [x]任务 4:给 tetris 模块加一个 debugfs 调试入口
你可以继续改进的地方(加分项)
这些不要求必须做,但很值得做:
- 把 ioctl 命令号做成共享头文件/绑定,避免用户态和内核态各写各的魔数。
- 给
scripts/run.sh加一个“无 KVM 的降级开关”。- 做一个
make test:本地一键跑 QEMU smoke test。 ===本地没做,CI 做了 ===- 给仓库加上基本的格式化/静态检查入口(
rustfmt/clippy/clang-format)。
以下按完成顺序
自动检测 KVM
qemu64 纯软件模拟,如果没有 KVM 就不能用-cpu host
busybox 官方仓库限制历史对象访问,已切换至 GitHub 镜像以保证可复现性
panic fix
$ make build...\*\*\* Rust bindings generator 'bindgen' versions 0.66.0 and 0.66.1 may not\*\*\* work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567),\*\*\* unless patched (like Debian's).\*\*\* Your version: 0.66.1\*\*\* Please see Documentation/rust/quick-start.rst for details\*\*\* on how to set up the Rust support.BINDGEN rust/bindings/bindings_generated.rsBINDGEN rust/uapi/uapi_generated.rs...$ make run...panicked at 'called \`Result::unwrap() \` on an \` Err \` value: FromBytesWithNulError { kind: InteriorNul(4) }', /usr/share/cargo/registry/bindgen-0.66.1/codegen/mod.rs:717:71make[3]: \*\*\* [rust/Makefile:464: rust/uapi/uapi_generated.rs] Error 101make[3]: \*\*\* Deleting file 'rust/uapi/uapi_generated.rs'make[3]: \*\*\* Waiting for unfinished jobs....panicked at 'called \`Result::unwrap() \` on an \` Err \` value: FromBytesWithNulError { kind: InteriorNul(4) }', /usr/share/cargo/registry/bindgen-0.66.1/codegen/mod.rs:717:71make[3]: \*\*\* [rust/Makefile:458: rust/bindings/bindings_generated.rs] Error 101make[3]: \*\*\* Deleting file 'rust/bindings/bindings_generated.rs'make[2]: \*\*\* [/home/y11han/woc2026-hello-from-skm/linux/Makefile:1320: prepare] Error 2make[1]: \*\*\* [Makefile:248: \_\_sub-make] Error 2make[1]: Leaving directory '/home/y11han/woc2026-hello-from-skm/linux'make: \*\*\* [Makefile:31: linux/arch/x86_64/boot/bzImage] Error 1...内核强制调用了 bindgen,无法通过绕开在本地跑 bindgen,那么就指定 bindgen 版本为 0.65.1
$ cargo install bindgen-cli --version 0.65.1拷贝虚空文件是何意味
$ ls src/*.kosrc/woc2026_hello_from_skm.ko
发现华点,不存在的 magic.ko,先注释掉了
加载magic.ko,用ioctl触发flag上一步发现虚空拷贝 magic.ko 文件,
$ git status --ignored中有 deleted: src/magic.ko,说明 Task 2(magic ioctl)在当前仓库中已被移除。 magic 模块已被移除(或合并), 当前仓库中 flag 触发路径已迁移至现有模块(tetris 或其 ioctl)
![]()
s3 说有问题先跳过,别急后面又call back
加上CI/CD + 产出OCI镜像
docker pull ghcr.io/tamako0401/woc2026-hello-from-skm:latestdocker run -it --rm ghcr.io/tamako0401/woc2026-hello-from-skm:latest
oh it works
.github/workflows/ci.yml name: woc2026 CIon:push:pull_request:permissions:contents: readpackages: writejobs:build:runs-on: ubuntu-22.04steps:- name: Checkout repository with submodulesuses: actions/checkout@v4with:submodules: recursivefetch-depth: 0- name: Install system dependenciesrun: |sudo apt-get updatesudo apt-get install -y \build-essential \clang-15 \lld \llvm-15 \libelf-dev \libssl-dev \bc \flex \bison \qemu-system-x86 \cpio- name: Install Rust toolchainrun: |curl https://sh.rustup.rs -sSf | sh -s -- -ysource $HOME/.cargo/envrustup toolchain install 1.88.0 # The Cargo Bool says: Edidion 2024 has been stabilized in the 1.85 release.rustup default 1.88.0 # reference: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-2024cargo install bindgen-cli --version 0.65.1- name: Build projectrun: |source $HOME/.cargo/envexport PATH=/usr/lib/llvm-15/bin:$PATHexport LLVM=1export LLVM_IAS=1export LLVM_VERSION=15clang --versionmake setupmake build- name: Smoke test (boot kernel)run: |source $HOME/.cargo/envchmod +x scripts/run.shtimeout 30s ./scripts/run.sh -k linux -b busybox | tee qemu.log || truegrep -q "Welcome to" qemu.log- name: Upload build artifactsuses: actions/upload-artifact@v4with:name: woc2026-buildpath: |linux/arch/x86_64/boot/bzImagebusybox/rootfs.imgsrc/*.kotools/*.a- name: Log in to GitHub Container Registryif: github.event_name != 'pull_request'uses: docker/login-action@v3with:registry: ghcr.iousername: ${{ github.actor }}password: ${{ secrets.GITHUB_TOKEN }}- name: Lowercase Repository Nameid: lowercase_reporun: |echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV- name: Build and push Docker imageif: github.event_name != 'pull_request'uses: docker/build-push-action@v5with:context: .file: Dockerfilepush: truetags: ghcr.io/${{ env.REPO_LOWER }}:latest# DockerfileFROM alpine:latestRUN apk add --no-cache qemu-system-x86_64 bashWORKDIR /appRUN mkdir -p linux/arch/x86_64/boot/RUN mkdir -p busybox/# 左边是CI构建产物路径,右边是容器内路径COPY linux/arch/x86_64/boot/bzImage linux/arch/x86_64/boot/bzImageCOPY busybox/rootfs.img busybox/rootfs.imgCOPY scripts/run.sh run.shRUN chmod +x run.sh# 启动命令不带任何参数,使用默认的 ./linux 和 ./busyboxCMD ["./run.sh"]# Makefile# SPDX-License-Identifier: GPL-2.0KDIR ?= ./linuxBDIR ?= ./busyboxTDIR ?= ./toolsSUBMODULE_DEPTH ?= 1TARGET ?=NCPU ?= $(shell nproc)BZIMAGE := $(KDIR)/arch/x86_64/boot/bzImageROOTFS := $(BDIR)/rootfs.imgBUSYBOX_CONFIG := $(BDIR)/.configBUSYBOX_BIN := $(BDIR)/busyboxBUSYBOX_INSTALL := $(BDIR)/_installUSERSPACE_PROG := play_tetrisROOTFS_STAMP := .rootfs_stamp.PHONY: all run build setup clean rebuild kernel busybox rootfs module module-clean module-install tools tools-clean tools-install repack-rootfsall: runbuild: kernel busybox $(ROOTFS) module-install tools-install repack-rootfsrebuild: clean-build buildkernel: $(BZIMAGE)$(BZIMAGE):@echo "Applying custom kernel configuration..."@cp qemu-busybox-min.config $(KDIR)/.config@echo "Building linux kernel..."@cd $(KDIR) && yes "" | make LLVM=1 CLIPPY=1 oldconfig@cd $(KDIR) && make LLVM=1 CLIPPY=1 $(TARGET) -j$(NCPU) || [ $$? -eq 141 ].PHONY: busybox-configbusybox-config:@echo "Configuring busybox..."@if [ ! -f $(BDIR)/.config ]; then \make -C $(BDIR) defconfig; \sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' $(BDIR)/.config; \yes "" | make -C $(BDIR) oldconfig; \fibusybox: busybox-config $(BUSYBOX_BIN)$(BUSYBOX_BIN):@echo "Building busybox..."@cd $(BDIR) && make -j$(NCPU)@file $(BUSYBOX_BIN) | grep -q "statically linked" || (echo "Error: BusyBox is not statically linked!" && exit 1)rootfs: $(ROOTFS)$(ROOTFS): $(BUSYBOX_BIN) | $(BUSYBOX_INSTALL)@echo "Installing busybox..."@cd $(BDIR) && make install@echo "Configuring rootfs..."@scripts/config-rootfs.sh -b $(BDIR)@$(MAKE) repack-rootfs$(BUSYBOX_INSTALL):@mkdir -p $(BUSYBOX_INSTALL)MODULE_NAME := woc2026_hello_from_skmMODULE_SRC := srcMODULE_KO := $(MODULE_SRC)/$(MODULE_NAME).komodule: kernel@echo "Preparing Rust environment..."@$(MAKE) -C $(KDIR) LLVM=1 CLIPPY=1 prepare@echo "Building Rust kernel module..."$(MAKE) -C $(KDIR) M=$(PWD)/$(MODULE_SRC) LLVM=1 modulesmodule-clean:@echo "Cleaning Rust module..."$(MAKE) -C $(KDIR) M=$(PWD)/$(MODULE_SRC) cleanmodule-install: module@echo "Installing module to rootfs..."@mkdir -p $(BUSYBOX_INSTALL)/lib/modules@cp $(MODULE_KO) $(BUSYBOX_INSTALL)/lib/modules/# @cp $(MODULE_SRC)/magic.ko $(BUSYBOX_INSTALL)/lib/modules/@touch $(ROOTFS_STAMP)tools: $(TDIR)/$(USERSPACE_PROG).c@echo "Building userspace program..."@gcc -static -o $(TDIR)/$(USERSPACE_PROG).a $(TDIR)/$(USERSPACE_PROG).c -Wall -Wextratools-clean:@echo "Cleaning userspace program..."@rm -f $(TDIR)/$(USERSPACE_PROG).atools-install: tools@echo "Installing userspace tools..."@cp $(TDIR)/$(USERSPACE_PROG).a $(BUSYBOX_INSTALL)/bin/$(USERSPACE_PROG)@cp $(TDIR)/$(USERSPACE_PROG).a $(BUSYBOX_INSTALL)/usr/bin/$(USERSPACE_PROG)@touch $(ROOTFS_STAMP)repack-rootfs: $(BUSYBOX_INSTALL)@echo "Packing rootfs image..."; \ln -sf sbin/init $(BUSYBOX_INSTALL)/init; \cd $(BUSYBOX_INSTALL) && find . | cpio -o -H newc | gzip > ../rootfs.img; \touch $(ROOTFS_STAMP);run: build@echo "Starting QEMU..."scripts/run.sh -b $(BDIR) -k $(KDIR)setup:- SUBMODULE_DEPTH=$(SUBMODULE_DEPTH) scripts/setup.shclean-build:@echo "Cleaning build artifacts..."@rm -f $(BZIMAGE) $(ROOTFS) $(ROOTFS_STAMP)@rm -rf $(BUSYBOX_INSTALL)clean: clean-build module-clean tools-clean@echo "Cleaning kernel..."@$(MAKE) -C $(KDIR) clean 2>/dev/null || true@echo "Cleaning busybox..."@$(MAKE) -C $(BDIR) clean 2>/dev/null || true
给 tetris 模块加一个 debugfs 调试入口debugfs 目录:/sys/kernel/debug/tetris/
只读文件:state
内容包含:score / game_over / next_piece / current_piece / board(20x10 #/ .)实现要点:
debugfs 的 state 读取走的是 kernel::debugfs::Writer(seq_file 单次输出),只读稳定;
/dev/tetris 和 debugfs 观察的是同一份 TetrisDeviceInner(通过在注册 miscdevice 时把 Arc<TetrisDeviceInner 存到 this_device 的 drvdata,然后 open 时取回 clone),所以 debugfs 读到的状态是真实的实时状态;
模块生命周期里持有 _debugfs: TetrisDebugFs,RAII 方式卸载时会自动删 debugfs 文件/目录。运行时:
1.挂载 debugfs:
mount -t debugfs none /sys/kernel/debug
2.插入模块后读状态:
cat /sys/kernel/debug/tetris/state
3.同时用 /dev/tetris 操作,再读 debugfs:
echo a /dev/tetris(左移)
echo w /dev/tetris(旋转)
然后再cat /sys/kernel/debug/tetris/state
Level 2
Task 3
s3在臭臭的地方找到了一个香香的PostgreSQL据说里面藏了宝藏?但是好像跑不起来
name
password:123456
导入 Vmware Workstation
说明 PostgreSQL 进程根本没起来。但不要想着 systemctl start postgresql 肯定没那么简单
发现 postgresql 数据库目录属于用户 1145
确认这个数据库曾经活过,base 目录下每一个数字子目录都是一个数据库
16388 目录相对较大,藏 flag 的概率较高
初见端倪
sast@zwz /lib/postgresql/15$ sudo cat /var/lib/postgresql/15/main/base/16388/16389 | less
只有前半截,怎么会是呢?怀疑 cat 和 grep 被 \0 截断了
CCB查查表环节,十六进制不会骗人,确定字段被 TOAST
开始梳理表之间的关系
16388 # database OID | +--16389 # 主表 / 索引 | +--pg_toast_??? # flag 后半截肯定还在16388目录下走弯路,个人认为触发 TOSAST 会在同一时间修改多个文件
但实际上_vm 是可见性映射,_fsm 是空闲空间映射,这里不可能藏 flag。
转变思路,只在文件名为纯数字的文件里找 /续标识 /拜谢后半截可能在>= 16389 的 relation
doneflag{W0w_#w3lc0me_2_SAST!}
Task 4
0001在Task 2的内核放置了一个dev1ce作为小礼物并留下了一个暗号 :
0x1337你能在dmesg里找到她留下的秘密吗?
请使用
insmod /lib/modules/magic.ko
意外地发现:哎呀这不就是我们 Task2 的子任务 2 嘛
纯黑盒又不是不能做,自己把 magic.ko cp 到 busybox/_install/lib/modules/ 再重新打包
宿主机中 搓最小用户态,再 cp 进 rootfs

QEMU 中

doneflag{You_get_the_magic_of_kernel!!}
Level 3 (Advanced)
Task 5
s3 精神状态堪忧,梦游时总想执行 sudo rm -rf /workshop/PPProject/*。作为运维组的正义使者,你需要利用 eBPF 技术,在内核层拦截该操作
推荐使用:
-
Rust Aya
-
Go cilium/ebpf
附加题的附加题:
-
那如果s3把文件夹先mv走再去删除呢?
-
如何通过 eBPF 监控并阻止针对该目录的 rename 操作
也许代码层面实现会比较困难,可以在验收的时候聊聊
Task 6
此题是Task 2的附加题
在GitHub - f3rmata/woc2026-hello-from-skm 中使用DebugFS添加一个数据统计功能,并为仓库提交pr来进行验收
部分信息可能已经过时

















oh it works
