Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
2056 字
10 分钟
WriteUp
2026-03-01
无标签
统计加载中...

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.rs
BINDGEN 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:71
make[3]: \*\*\* [rust/Makefile:464: rust/uapi/uapi_generated.rs] Error 101
make[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:71
make[3]: \*\*\* [rust/Makefile:458: rust/bindings/bindings_generated.rs] Error 101
make[3]: \*\*\* Deleting file 'rust/bindings/bindings_generated.rs'
make[2]: \*\*\* [/home/y11han/woc2026-hello-from-skm/linux/Makefile:1320: prepare] Error 2
make[1]: \*\*\* [Makefile:248: \_\_sub-make] Error 2
make[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/*.ko
src/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:latest
docker run -it --rm ghcr.io/tamako0401/woc2026-hello-from-skm:latest

oh it works

.github/workflows/ci.yml
name: woc2026 CI
on:
push:
pull_request:
permissions:
contents: read
packages: write
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository with submodules
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Install system dependencies
run: |
sudo apt-get update
sudo 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 toolchain
run: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
source $HOME/.cargo/env
rustup 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-2024
cargo install bindgen-cli --version 0.65.1
- name: Build project
run: |
source $HOME/.cargo/env
export PATH=/usr/lib/llvm-15/bin:$PATH
export LLVM=1
export LLVM_IAS=1
export LLVM_VERSION=15
clang --version
make setup
make build
- name: Smoke test (boot kernel)
run: |
source $HOME/.cargo/env
chmod +x scripts/run.sh
timeout 30s ./scripts/run.sh -k linux -b busybox | tee qemu.log || true
grep -q "Welcome to" qemu.log
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: woc2026-build
path: |
linux/arch/x86_64/boot/bzImage
busybox/rootfs.img
src/*.ko
tools/*.a
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Lowercase Repository Name
id: lowercase_repo
run: |
echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Build and push Docker image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
push: true
tags: ghcr.io/${{ env.REPO_LOWER }}:latest
# Dockerfile
FROM alpine:latest
RUN apk add --no-cache qemu-system-x86_64 bash
WORKDIR /app
RUN mkdir -p linux/arch/x86_64/boot/
RUN mkdir -p busybox/
# 左边是CI构建产物路径,右边是容器内路径
COPY linux/arch/x86_64/boot/bzImage linux/arch/x86_64/boot/bzImage
COPY busybox/rootfs.img busybox/rootfs.img
COPY scripts/run.sh run.sh
RUN chmod +x run.sh
# 启动命令不带任何参数,使用默认的 ./linux 和 ./busybox
CMD ["./run.sh"]
# Makefile
# SPDX-License-Identifier: GPL-2.0
KDIR ?= ./linux
BDIR ?= ./busybox
TDIR ?= ./tools
SUBMODULE_DEPTH ?= 1
TARGET ?=
NCPU ?= $(shell nproc)
BZIMAGE := $(KDIR)/arch/x86_64/boot/bzImage
ROOTFS := $(BDIR)/rootfs.img
BUSYBOX_CONFIG := $(BDIR)/.config
BUSYBOX_BIN := $(BDIR)/busybox
BUSYBOX_INSTALL := $(BDIR)/_install
USERSPACE_PROG := play_tetris
ROOTFS_STAMP := .rootfs_stamp
.PHONY: all run build setup clean rebuild kernel busybox rootfs module module-clean module-install tools tools-clean tools-install repack-rootfs
all: run
build: kernel busybox $(ROOTFS) module-install tools-install repack-rootfs
rebuild: clean-build build
kernel: $(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-config
busybox-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; \
fi
busybox: 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_skm
MODULE_SRC := src
MODULE_KO := $(MODULE_SRC)/$(MODULE_NAME).ko
module: 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 modules
module-clean:
@echo "Cleaning Rust module..."
$(MAKE) -C $(KDIR) M=$(PWD)/$(MODULE_SRC) clean
module-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 -Wextra
tools-clean:
@echo "Cleaning userspace program..."
@rm -f $(TDIR)/$(USERSPACE_PROG).a
tools-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.sh
clean-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 只有前半截,怎么会是呢?怀疑 catgrep 被 \0 截断了

CCB查查表环节,十六进制不会骗人,确定字段被 TOAST

开始梳理表之间的关系

16388 # database OID
|
+--16389 # 主表 / 索引
|
+--pg_toast_??? # flag 后半截肯定还在16388目录下
走弯路,个人认为触发 TOSAST 会在同一时间修改多个文件

但实际上_vm 是可见性映射,_fsm 是空闲空间映射,这里不可能藏 flag。
转变思路,只在文件名为纯数字的文件里找 /续标识 /拜谢

后半截可能在>= 16389 的 relation

done

flag{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 中

done

flag{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来进行验收

WriteUp
https://blog.y11han.icu/posts/writeup/
作者
Y11Han
发布于
2026-03-01
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时