Giter Club home page Giter Club logo

like-dbg's Introduction

LIKE-DBG

Code style: black Build Status: flake8 Build Status: shellcheck Build Status: hadolint codecov License: MIT GitHub Release

LIKE-DBG (LInux-KErnel-DeBuGger) aims at automating the boring steps when trying to set up a Linux kernel debugging environment. I set out to dive into kernel exploitation research and found existing solutions not usable enough. Hence, this is an attempt at making all necessary pre-steps before one can even think about diving into research as painless and fun as possible. All steps from building a kernel, running it inside an emulated environment, and attaching a debugger are transparently done inside docker containers to keep system requirements minimal. Currently, there's a dedicated docker container for every of the following steps:

  • Building the kernel
  • Creating a root file system to use with the kernel
  • Launching the kernel + file system as the debuggee
  • Attaching to the kernel as a debugger

Caveats

As this project is in its early stages, I expect things to change rapidly, while also introducing breaking changes along the way. Major points to improve on are:

  • Getting towards true multi-architecture support beyond x86_64 and arm64
  • Extend kernel builder to not only succeed in building recent™ kernels
  • Add android kernel support
  • Add (integration) tests
  • Elevate the debugging experience even more

Features

On the upside, despite its early stages, a couple of useful features are already present:

  • General:
    • Minimal host system requirements due to dockerization of every step
    • An easy to grasp configs/user.ini config that allows highly customizable sessions
      • Or provide different configurations for different debugging setups via the command-line!
    • CTF runner that's specifically designed to handle Linux kernel exploitation challenges
      • ctf/misc that houses some nifty scripts to aid in CTFs
    • Code quality measures:
    • Operating system agnostic, meaning it should run just fine on:
      • Debian/Ubuntu
      • Arch Linux/Manjaro
      • Fedora
  • Kernel builder:
    • Multi-arch: x86_64, arm64
    • Choose between gcc and clang to build the kernel
    • Configuration modes:
      • generic-mode,
      • syzkaller-mode,
      • custom-mode, or
      • provide a usable kernel config
    • Fine-granular version control to build from:
      • Commit hash
      • Release tag (e.g.: 5.10-rc)
      • Major-Minor-Patch (e.g.: 5.10.77)
    • Ability to automatically apply patch files
    • Basic ability to add custom kernel modules
  • Root file system builder:
    • Powered by debootstrap
    • Automatic generation of file system that matches the kernels architecture
    • Ability to customize:
      • wanted packages in the file system
      • the Debian release version to base everything on
  • Debuggee:
    • Powered by QEMU
    • Customization of QEMU runtime options from within the configs/*.ini files.
  • Debugger:
    • Powered by GDB (multiarch) with either
    • Allow users to specify GDB script in io/scripts/gdb_script to allow a scenario-tailored debugging experience

Requirements

To get started, you have to ensure to have the following requirements set up in your system:

It is recommended to not run this as the root user, e.g. for testing purposes on a VPS. It may work fine but in general I highly encourage creating a dedicated non-root user to put in the docker and sudo group!

Note: If you're using a custom TMUX config, make sure that your first pane starts at 0!

Optional

This section covers tools that are not required to run LIKE-DBG but are nice to have and assist heavily when debugging or writing an exploit.

Setup

Inside like-dbg run poetry install

Configuration

Fine-tuning the kernel debugging experience is one of the goals of this project. Currently, all tunable options are exposed in the two configuration files: configs/system.ini and configs/user.ini. Some fields are recommended to not be altered as they're mainly for development reasons. However, all the ones to customize the environment to your needs should be self-explanatory as all of them are labeled with a brief comment.

Usage

Note: On first time usage run poetry install.

Once you're set with writing/adapting a configuration, the usage depends on your scenario. The easiest way to get started, which is based on the configs/user.ini configuration is the following:

tmux -f .tmux.conf
poetry shell
# This checks out a kernel, builds it, creates a root file system and starts the debugger and debuggee eventually
./start_kgdb.py

There exist 2 users for the automatically created filesystems:

  • root with no password
  • user:user

This is intended so you can develop and exploit from either perspective easily.

Extended Usage

# If you want to try a CTF challenge where you were given a (compressed) Linux Image and a root filesystem try:
./start_kgdb.py --ctf <Image> <RootFS>

# If you want to kill the current debugging session
./start_kgdb.py -k

# If you want to provide a custom 'user.ini' for a specific debugging setup
./start_kgdb.py -c <path_to_cfg> [other_args]

# If you want to test some partial functionality of LIKE-DBG
# Stage 1: Download Kernel
# Stage 2: Stage 1 & unpack Kernel
# Stage 3: Stage 2 & build Kernel
# Stage 4: Only build a root file system
# Stage 5: Stage 3+4 & start debuggee
./start_kgdb.py -p <stage_nr>

# Update all containers
./start_kgdb.py -u

Examples

The examples subdirectory houses samples on how LIKE_DBG may aid you in specific kernel debugging tasks. Each example contains a dedicated README.md as well that contains the necessary information to reproduce the examples.

Showcase

img/example.png

Hacking

The python code should be quite readable, so feel free to extend the project with your own ideas. All PRs are very much welcome :)! Otherwise, feel free to create a feature-request issue or head over to the discussions page to brainstorm some cool new features!

PS: If you want to provide a logo, feel free to do so.

like-dbg's People

Contributors

0xricksanchez avatar apaolillo avatar dependabot[bot] avatar jbergstroem avatar r3zk0n avatar saakshii12 avatar sh4d0wy avatar shresthasurav avatar sikkiladho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

like-dbg's Issues

Add non-root user

Currently, the default behavior for the QEMU kernel/rootfs is that there is only a root user.
We want a default non-root user that we can target with LPE exploits.

Rethink 're-use' prompt

Is your feature request related to a problem? Please describe.
Currently, when re-running the same kernel and file system, there's always a prompt whether one wants to re-use the existing data/container.

Describe the solution you'd like
Add a 'yes' CLI flag to skip all re-use prompts to dive right back into debugging again

Implement a custom Runner

Assuming we were given a kernel and a rootfs image, and we wanted to re-use our three panel debugging setting it would be nice to have a custom runner that allows using these instead of going the builder route.
Technical details like architecture and wanted exploit mitigations could still be specified in the config.ini, whereas everything else could be hidden in the execution logic of the custom runner to make debugging as straightforward as possible.

This could help in CTF-y or teaching scenarios

It could have the form of:

# Step 0: Insert some necessary metadata into a minimal config.ini like
#   - architecture
#   - QEMU runtime flags
#   - ...
# Step 1:
$ ./start_kgdb.py -c --vmlinux <path> --rootfs <path>
# Step 3:
# Start hacking

Add more capabilities to the debugger

Is your feature request related to a problem? Please describe.

GDB + GEF is already a massive improvement over plain GDB.
The drawback of this approach is that GEF lacks specific kernel features.
The upside is that there exists a fork of GEF that has already implemented some cool features. However they were never contributed back to the main project.
At the time of writing the fork and the main project diverged quite a bit and just merging them together seems like it's never gonna work.

Describe the solution you'd like

To extend the debugger we could just reference the fork and contribute some features back to gef while rewriting others and creating new functionalities as well. This would benefit the whole ecosystem.

Creating symbolic link is broken on debugger

Similarly to #46, merging #11 has introduced a bug in the debugger that I noticed when building a fresh x86_64 image just now:

ln: failed to create symbolic link '/io/arch/x86_64/boot/Image': File exists

Allow multiple configs

It may be easier to have multiple instances of a config at times, e.g. when dealing with different scenarios to debug. So in addition to having a main.cfg, which should always be the (default) fallback, it'd be sweet to have a -c / --config flag to supply a specific one at start up.

Add ARM support

Currently only building aarch64 kernel builds is available. Having a 32-bit ARM kernel would be a nice touch as well

Allow verbosity toggles for log output

Is your feature request related to a problem? Please describe.
Currently, any user including myself is at the mercy of myself when it comes to logging output.
The current verbosity is nice for a dev environment but should be configurable later on

Describe the solution you'd like
Implement toggles for severity (error, info, debug)

Allow uploading of files into the QEMU instance

Is your feature request related to a problem? Please describe.
Manually transferring exploits into the debuggee by unpacking/repacking the rootfs is trivial but requires re-starting like-dbg with every iteration. It would be much nicer to have an upload.py that can directly transfer files into the running QEMU guest.

Minimize and unify docker images

All docker images are pretty much based on the same image.
Minimizing those and even unifying them to a common base image would make build times quicker and save disk space.

Error reading SSH protocol banner error

Describe the bug
Building like-dbg throws error Reading SSH protocol banner halting the build of the application.

To Reproduce
Steps to reproduce the behavior:

  1. Running the start-kgdb.py script runs up to like_kbuilder_x86_64:latest (build_image:53)
  2. Then throws an error saying Error reading SSH protocol. I have tried this on a VPS and Virtual Machine
  3. Ive also used native python, venv python from 3.6 to 3.10.

Expected behavior
Python script to spawn a kernel gdb/gef session with tmux

Screenshots
image

Implement an interactive mode

I think it would be quite nice to have some kind of interactive shell mode

$ ./start_kgdb -i
$LIKE-DBG> kill  # To kill the current instance but keep the interactive mode intact
$LIKE-DBG> rerun # Rerun the same environment as the one that just ran before killing it
$LIKE-DBG> (un)pack # Syntax to be specified to (un)pack cpio archive
$LIKE-DBG> ctf kernel image  # To run a CTF instance
$LIKE-DBG> set mycfg.ini # To set mycfg.ini as the user.ini for all future runs
$LIKE-DBG> open exploit.c  # Should probably spawn a new tmux tab with the exploit opened in vim..
$LIKE-DBG> exit  # Exit interactive mode

The above syntax is just an example.
The shown commands are just examples as well.

CTF challenges only work when placed in a subdirectory within LIKE-DBG

Currently, the ctf subdirectory may be used as a suitable place to put CTF challenges (with any number of nested subdirectories). However, placing them anywhere else on disk will lead to a fault as the mounting mechanism only consider Path.cwd() as a source.
We should consider scenarios where a user provides arbitrary paths where the path to the kernel image may even differ from the one of the rootfs.

macOS case-insensitive filesystem breaks build

Despite having the whole process containerised the Linux kernel build process fails on macOS APFS systems due to the disks being case-insensitive:

make[1]: *** Documentation/Kbuild: Is a directory.  Stop.
make: *** [Makefile:1850: _clean_Documentation] Error 2
Traceback (most recent call last):
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 536, in <module>
    main()
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 517, in main
    KernelBuilder().run()
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 404, in run
    super().run()
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 302, in run
    self.run_container()
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 390, in run_container
    self._build_mrproper()
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 344, in _build_mrproper
    self._run_ssh(f"{self.cc} ARCH={self.arch} make mrproper")
  File "/Users/ck/Tools/Research/like-dbg/./start_kgdb.py", line 332, in _run_ssh
    return self.ssh_conn.run(f"cd {self.docker_mnt}/{self.kernel_root} && {cmd}").exited
  File "<decorator-gen-3>", line 2, in run
  File "/usr/local/lib/python3.9/site-packages/fabric/connection.py", line 30, in opens
    return method(self, *args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/fabric/connection.py", line 725, in run
    return self._run(self._remote_runner(), command, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/invoke/context.py", line 102, in _run
    return runner.run(command, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/fabric/runners.py", line 72, in run
    return super(Remote, self).run(command, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/invoke/runners.py", line 380, in run
    return self._run_body(command, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/invoke/runners.py", line 442, in _run_body
    return self.make_promise() if self._asynchronous else self._finish()
  File "/usr/local/lib/python3.9/site-packages/invoke/runners.py", line 509, in _finish
    raise UnexpectedExit(result)
invoke.exceptions.UnexpectedExit: Encountered a bad command exit code!

Command: 'cd /io/kernel_root && CC=gcc ARCH=arm64 make mrproper'

Make default packages for the rootfs scriptable

Would be a nice touch to have an option inside the config that allows adding more Debian packages to be installed inside the root file system.

On the root file system script side this can easily be realized with an additional script argument.

Create easy cpio(.gz) packer/unpacker script

Is your feature request related to a problem? Please describe.
In CTFs one typically has given a rootfs in the form of a .cpio or cpio.gz.
Un-/Re-packing these formats is trivial, but a convenience script could make things a lot easier and could speed up the debugging/exploitation process

Describe the solution you'd like
Place a script folder in ctf/ that houses this and future other scripts for the CTF context

Failed to run RootFSBuilder on QubesOS

Describe the bug
Building like-dbg throws the error "Failed to run RootFSBuilder"

To Reproduce
Steps to reproduce the behavior:

  1. The version is like-dbg v0.0.1
  2. Running ./start-kgdb.py with out any additional flags runs up to src.docker_runner:wait_for_container:109

Expected behavior
To actually run RootFSBuilder and extract the RootFS to build like-dbg's docker images.

Screenshots

like-dbg

Desktop (please complete the following information):
Fill me in on the specs of your environment:

  1. Operating system: Qubes OS 4.1.1, with like-dbg being run inside a debian 11 Qube
  2. Python version is 3.9.2
  3. Docker version 20.10.17, build 100c701

Additional context
Important note is that i'm running ./start-kdbg.py in a non-ctf context! without any additional flags. Docker can pull and build images just fine but the issue occurs when I run the aforementioned script.

Allow providing a user-supplied kernel config file

Is your feature request related to a problem? Please describe.
Currently, the kernel builder operates on the config flags that are being enabled/disabled in the config.ini. It may prove useful to add an option to provide a ready-made config file that is used in the build process.

Describe the solution you'd like
We could add another option in the config.ini that is called config_file that points to a path. If this field is set it's being preferred over the mode option.

Allow easy shutdown of the running debugging sessions

To exit the currently running debugging session consisting of the debuggee and debugger requires multiple steps:

  • [DBGE]: <CTRL> + A to kill QEMU
  • [DBG]: An optional <CTRL> + c to get control, followed by an exit to quit GDB
  • Tearing down the TMUX split

It likely would be quicker to have a ./start_kgdb.py --kill that does all of the above leaving the user in a single window TMUX session.

Make Kernel API docs easily accessible

Sometimes you just want to quickly look up basic kernel APIs.
Sadly, man(9) is not always available.
So, it would be nice to have a convenient way to look up kernel API functions from the terminal.

Make shell script output depend on log-level

There are two obvious ways to do so:

  • Depending on the log level do a sed to (un-)set the -x flag in both rootfs.sh and debugger.sh. However, this requires rebuilding the containers for the changes to take effect. Additionally, we should implement a 'watcher' that only rebuilds the containers upon changes.
  • Modify the entry point of both mentioned containers above and prepend a set -x. This does not require rebuilding and should work the same. However, this only seem to work for immediate commands, not a shell script, which is executed in another subshell itself... We would need to inherit the set options like so set -eu(x); . ./entrypoint.sh (argv). Doing that as an entrypoint in a container seems to not work out of the box... We probably need something like docker run .... <container> /bin/bash -c 'set -eu(x); source <entrypoint.sh>

Don't leave zombie containers alive in failed building runs

Describe the bug

When e.g. the kernel builder fails to finish properly, either due to a bug in the code or incompatible compiling options the container is not shutdown properly. This results in yet another error in a consecutive run since the now zombie container hogs resources, in particular the port binds.

Expected behavior
Properly shut down any containers on a failed run

In certain cases building the rootfs fails due to failing loop device mount

Describe the bug

Creating the rootfs can fail in unknown cases when mounting the loop device runs into an unknown problem:

mount: /mnt/rootfs: failed to setup loop device for /io/filesystem-x86_64.

This has been observed on a Manjaro and Fedora36 system.

To Reproduce

  1. It happened to me once in a freshly set up Fedora36 system after following the usage-section in the README
  2. After deleting the broken filesystem and re-running start_kgdb.py with no changes to the config.ini root file system creation worked for me again.

Expected behavior

  • A more sane error message in case of a failure, but really we want a successful rootfs build...

Allow multiple parallel kernel builds

Is your feature request related to a problem? Please describe.
Currently, we allow re-using a built kernel across runs.
However, if we were to hop between kernel version/architectures we're overwriting the at that moment built kernel as the same directory is used.

Describe the solution you'd like
It would be sweet to re-use the kernel_root directory but add subdirectories in the form of , which are defined in the config.ini.
The logic would need to be adjusted to consider these subdirectories properly
Anyhow, this could be a big win especially to debug kernel revisions side by side.

To account for side-by-side builds we need to fix the vm.pid file in the debuggee as well.
Either delete that parameter or make the naming depend on a dynamic runtime feature!

Add dmesg-/kptr-restrict options

Is your feature request related to a problem? Please describe.

Currently, there is no way to set these options:

# https://sysctl-explorer.net/kernel/dmesg_restrict/
echo 1 > /proc/sys/kernel/dmesg_restrict
https://sysctl-explorer.net/kernel/kptr_restrict/
echo 1 > /proc/sys/kernel/kptr_restrict

For example, fine-grained KASLR aka FG-KASLR can be set during compile options with -e CONFIG_FG_KASLR, which our current config.ini supports already

Note: FG-KASLR seems to be exclusive to x86_64 and can be disabled at runtime with the nokaslr or nofgkaslr

Describe the solution you'd like
I'd like a user exposed config options for these to be set in the debugged kernel

Remove GCC/make host requirements

Is your feature request related to a problem? Please describe.
the kernel unpacker does a make clean in case the requested kernel version is already present and unpacked with the assumption that if that folder exists the chances are high it has been dirtied..

Describe the solution you'd like
The kernel unpacker should just strictly unpack stuff and IFF the requested kernel is already present it should return early with an additional status like “assume_dirty”, which the kernel builder should handle..

NameError: name 'sp' is not defined

In the file src/docker_runner.py ap is used but not imported. I'm getting name 'sp' is not defined error when following the installation steps.

adding import subprocess as sp in src/docker_runner.py is solving the issue.

Allow fine-tuning of GDB runtime environment

Currently the GDB invocation on how to attach the debugger to the running kernel is hard coded in one of the shell scripts. It would be beneficial to allow users add more GDB script options like for example custom breakpoints

Split config into a „system“ and „user“ part

Analogously to #92, we should split the config I two parts. One “system” part that contains never to rarely touched fields that e sure the system works as intended. Those are only exposed for power-users or devs.

The “user” portion should contain those fields that are relevant for a user to custom-tailor the debugging experience.

The benefit here would be that the config looks less complicated while also decreasing the entry barrier even further.

Minimum python version is *probably* 3.9

I just tried with python3.8 on Ubuntu 20.04, and it fails with the following error:

AttributeError: module 'argparse' has no attribute 'BooleanOptionalAction'

Which is fixed by just using a more recent python interpreter (3.9 in my case).

Running as root on a VPS makes kernel build fail

Describe the bug
When running for example as root@VPS the kernel build will fail, since the build process inside the docker container is done as a non-root user.

To Reproduce
Basically, check #59.
The TLDR seems to be that as soon as one is on a VPS the kernel builder runs into problems

Expected behavior
In the mentioned scenario above the framework should not fail to complete all building steps.

Screenshots
Check #59

Only rebuild if custom_gdb_script contents changed across runs

Setting manual toggles for rebuilds in the config.ini that forces rebuilding (which is required) for changes in io/scripts/gdb_script to take effect inside the debugger container is tedious.
A PR for this should introduce a "watcher" that automatically rebuilds the debugger (basically only executes the COPY at the end of the respective dockerfile) IFF the contents of the aforementioned gdb script changed compared to the prior run.
If force_rebuild is toggled on for the debugger in config.ini rebuilding always takes place.

Guarantee expected behavior on other operating systems than Manjaro

Is your feature request related to a problem? Please describe.
Currently, like-dbg is only tested locally on a MANJARO machine.

Describe the solution you'd like
Hand in hand with #39 it would be nice to cover at least Debian/Ubuntu and Fedora to guarantee it works across different operating systems

Adjust terminal size

Currently, the terminal size within the booted QEMU is rather small (read narrow)
Adjusting it via:

# Example size
stty cols 128 rows 64

would make things less cluttered and more space efficient.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.