more ctf stuff
This commit is contained in:
23
2025/google/misc-bpfbox/Dockerfile
Normal file
23
2025/google/misc-bpfbox/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM nixos/nix AS build
|
||||
|
||||
RUN mkdir -p /build
|
||||
WORKDIR /build
|
||||
|
||||
COPY flag.txt flake.nix flake.lock /build/
|
||||
COPY ./init /build/init/
|
||||
RUN nix --extra-experimental-features nix-command --extra-experimental-features flakes build
|
||||
|
||||
FROM gcr.io/kctf-docker/challenge@sha256:9f15314c26bd681a043557c9f136e7823414e9e662c08dde54d14a6bfd0b619f
|
||||
|
||||
RUN apt-get update && apt-get install -y qemu-system-x86
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=build /build/result/bzImage /build/result/initrd.gz /
|
||||
COPY run_qemu /
|
||||
CMD kctf_setup && \
|
||||
chmod 0777 /dev/kvm && \
|
||||
chmod 0777 /dev/vhost-vsock && \
|
||||
kctf_drop_privs \
|
||||
socat \
|
||||
TCP-LISTEN:1337,reuseaddr,fork \
|
||||
EXEC:"kctf_pow /run_qemu"
|
||||
1
2025/google/misc-bpfbox/flag.txt
Normal file
1
2025/google/misc-bpfbox/flag.txt
Normal file
@@ -0,0 +1 @@
|
||||
CTF{this isn't a flag}
|
||||
26
2025/google/misc-bpfbox/flake.lock
generated
Normal file
26
2025/google/misc-bpfbox/flake.lock
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749857119,
|
||||
"narHash": "sha256-tG5xUn3hFaPpAHYIvr2F88b+ovcIO5k1HqajFy7ZFPM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f4f306bea96741f1588ea4f450b2a2e29f42b98",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-25.05",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
51
2025/google/misc-bpfbox/flake.nix
Normal file
51
2025/google/misc-bpfbox/flake.nix
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
description = "bpfbox";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-25.05";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
let
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||
lib = pkgs.lib;
|
||||
init = pkgs.buildGoModule {
|
||||
name = "init";
|
||||
|
||||
vendorHash = null;
|
||||
|
||||
src = ./init;
|
||||
};
|
||||
initrdEnv = pkgs.buildEnv {
|
||||
name = "initrd-env";
|
||||
paths = with pkgs; [
|
||||
pkgsStatic.busybox
|
||||
bpftrace
|
||||
init
|
||||
];
|
||||
pathsToLink = [
|
||||
"/bin"
|
||||
];
|
||||
};
|
||||
kernel = pkgs.linuxPackages.kernel;
|
||||
initrd = pkgs.makeInitrdNG {
|
||||
name = "initramfs";
|
||||
contents = [
|
||||
{ source = "${initrdEnv}/bin"; target = "/bin"; }
|
||||
{ source = ./flag.txt; target = "/flag.txt"; }
|
||||
{ source = "${initrdEnv}/bin/init"; target = "/init"; }
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.x86_64-linux.default = pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "bpfbox";
|
||||
phases = [ "installPhase" ];
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp ${initrd}/initrd.gz $out/
|
||||
cp ${kernel}/bzImage $out/
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
3
2025/google/misc-bpfbox/init/go.mod
Normal file
3
2025/google/misc-bpfbox/init/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module init
|
||||
|
||||
go 1.24.2
|
||||
177
2025/google/misc-bpfbox/init/main.go
Normal file
177
2025/google/misc-bpfbox/init/main.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const probeText = `
|
||||
BEGIN {
|
||||
printf("ready\n")
|
||||
}
|
||||
|
||||
fentry:vmlinux:security_create_user_ns {
|
||||
signal(KILL);
|
||||
}
|
||||
|
||||
fentry:vmlinux:security_file_open {
|
||||
$inode = args->file->f_inode;
|
||||
$d = $inode->i_sb->s_dev;
|
||||
$i = $inode->i_ino;
|
||||
|
||||
if ($d == $1 && $i == $2) {
|
||||
signal(KILL);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func getProbeParams(filename string) (uint64, uint64, error) {
|
||||
info, err := os.Stat("/flag.txt")
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return 0, 0, fmt.Errorf("expected Stat_t, but was: %s", info.Sys())
|
||||
}
|
||||
|
||||
return stat.Dev, stat.Ino, nil
|
||||
}
|
||||
|
||||
func runTracer(ctx context.Context, dev, ino uint64, rdy chan struct{}, errs chan error) {
|
||||
cmd := exec.CommandContext(ctx, "/bin/bpftrace", "--unsafe", "-e", probeText, strconv.FormatUint(dev, 10), strconv.FormatUint(ino, 10))
|
||||
// cmd.Wait will close the reader automatically
|
||||
reader, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
// wait for the probe to be ready
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
if strings.Contains(scanner.Text(), "ready") {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
close(rdy)
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func mountFilesystems() error {
|
||||
if err := syscall.Mount("devtmpfs", "/dev", "devtmpfs", 0, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /dev: %s", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir("/proc", 0555); err != nil {
|
||||
return fmt.Errorf("error creating /proc: %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Mount("proc", "/proc", "proc", 0, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /proc: %s", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir("/sys", 0555); err != nil {
|
||||
return fmt.Errorf("error creating /sys: %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /sys: %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Mount("tracefs", "/sys/kernel/tracing", "tracefs", 0, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /sys/kernel/tracing: %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Mount("debugfs", "/sys/kernel/debug", "debugfs", 0, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /sys/kernel/debug: %s", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir("/tmp", 0555); err != nil {
|
||||
return fmt.Errorf("error creating /tmp: %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Mount("tmpfs", "/tmp", "tmpfs", syscall.MS_NOEXEC|syscall.MS_NODEV|syscall.MS_NOSUID, ""); err != nil {
|
||||
return fmt.Errorf("error mounting /tmp: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func shutdown() error {
|
||||
return syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
|
||||
}
|
||||
|
||||
func spawnShell(ctx context.Context) error {
|
||||
withTimeout, cancel := context.WithTimeout(ctx, time.Minute)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(withTimeout, "/bin/sh")
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Credential: &syscall.Credential{Uid: 99999, Gid: 99999},
|
||||
Setpgid: true,
|
||||
Pdeathsig: syscall.SIGKILL,
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
fmt.Println("command failed:", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := mountFilesystems(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dev, ino, err := getProbeParams("/flag.txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
rdy := make(chan struct{})
|
||||
errs := make(chan error)
|
||||
go runTracer(ctx, dev, ino, rdy, errs)
|
||||
|
||||
select {
|
||||
case err = <-errs:
|
||||
panic(err)
|
||||
case <-rdy:
|
||||
}
|
||||
|
||||
if err := spawnShell(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := shutdown(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
2
2025/google/misc-bpfbox/run_qemu
Normal file
2
2025/google/misc-bpfbox/run_qemu
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
exec qemu-system-x86_64 -serial mon:stdio -nographic -cpu host -m 1024 -accel kvm -kernel /bzImage -initrd /initrd.gz -append "console=ttyS0 quiet"
|
||||
Reference in New Issue
Block a user