Introduction

out-of-tree is written in Go, it uses Docker for generating kernel/filesystem images and Qemu for virtualization.

Also it possible to generate kernels from the host system and use the custom one.

out-of-tree supports GNU/Linux (usually it’s tested on NixOS and latest Ubuntu LTS) and macOS. Technically all systems that supported by Go, Docker, and Qemu must work well. Create the issue if you’ll notice any issue in integration for your operating system.

All Qemu interaction is stateless.

out-of-tree is allow and require metadata (.out-of-tree.toml) for work. TOML (Tom’s Obvious, Minimal Language) is used for kernel module/exploit description.

.out-of-tree.toml is mandatory, you need to have in the current directory (usually, it’s a project of kernel module/exploit) or use the --path flag.

Files

All data is stored in ~/.out-of-tree/.

  • db.sqlite contains logs related to run with out-of-tree pew, debug mode (out-of-tree debug) is not store any data.
  • images used for filesystem images (rootfs images that used for qemu -hda ...) that can be generated with the tools/qemu-*-img/....
  • kernels stores all kernel vmlinuz/initrd/config/... files that generated previously with a some Docker magic.
  • kernels.toml contains metadata for generated kernels. It’s not supposed to be edited by hands.
  • kernels.user.toml is default path for custom kernels definition.
  • Ubuntu (or Centos/Debian/…) is the Dockerfiles tree (DistroName/DistroVersion/Dockerfile). Each Dockerfile contains a base layer and incrementally updated list of kernels that must be installed.

Overview

out-of-tree creating debugging environment based on defined kernels:

$ out-of-tree debug --kernel 'Ubuntu:4.15.0-58-generic'
[*] KASLR SMEP SMAP
[*] gdb is listening on tcp::1234
[*] build result copied to /tmp/exploit

ssh -o StrictHostKeyChecking=no -p 29308 root@127.133.45.236
gdb /usr/lib/debug/boot/vmlinux-4.15.0-58-generic -ex 'target remote tcp::1234'

out-of-tree> help
help    : print this help message
log     : print qemu log
clog    : print qemu log and cleanup buffer
cleanup : cleanup qemu log buffer
ssh     : print arguments to ssh command
quit    : quit
out-of-tree>

out-of-tree uses three stages for automated runs:

  • Build
    • Inside the docker container (default).
    • Binary version (de facto skip stage).
    • On host.
  • Run
    • Insmod for the kernel module.
    • This step is skipped for exploits.
  • Test
    • Run the test.sh script on the target machine.
    • Test script is run from root for the kernel module.
    • Test script is run from user for the kernel exploit.
    • Test script for the kernel module is fully custom (only return value is checked).
    • Test script for the kernel exploit receives two parameters:
      • Path to exploit
      • Path to file that must be created with root privileges.
    • If there’s no test.sh script then default (echo touch FILE | exploit) one is used.

Security

out-of-tree is not supposed to be used on multi-user systems or with an untrusted input.

Meanwhile, all modern hypervisors are supporting nested virtualization, which means you can use it for isolating out-of-tree if you want to work with an untrusted input (e.g. with a mass-scale testing public proofs-of-concept).