├── README.md ├── setup-kernel-debugging └── setup-kernel-debugging.gif /README.md: -------------------------------------------------------------------------------- 1 | # vulndev-tools 2 | 3 | Just a repository for random tools that can be helpful during vulnerability 4 | research and exploit development. For now, it only contains a script to set up 5 | a kernel debugging environment. 6 | 7 | ![setup-kernel-debugging](setup-kernel-debugging.gif) 8 | 9 | The tool works as-is for setting up kernel debugging environments for (at 10 | least) Ubuntu 14.04, 16.04, 18.04 and 20.04 kernels right now, and would be 11 | easy to adapt to support non-Ubuntu-based Linux distributions as well (would 12 | need some adaptations for each dist). 13 | 14 | Dependencies: Multipass (https://multipass.run), QEMU, GDB and tmux. 15 | 16 | To install dependencies under Ubuntu: 17 | ```bash 18 | sudo snap install multipass 19 | sudo apt-get -y install qemu-system-x86 gdb tmux 20 | ``` 21 | 22 | Pull requests are welcome. Examples of features to add: 23 | 24 | - Add getopts-based command line argument handling. 25 | - Add option for making system update-step optional. 26 | - Add option for specifying a specific kernel to install. 27 | - Add support for non-Ubuntu-based guests. For instance, CentOS: 28 | https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.2.2004-20200611.2.x86_64.qcow2 29 | - Add check for each of the dependencies, and for supported hosts, check for 30 | sudo-access and automatically install the required dependencies. 31 | - Add option for normal boot instead of using init=/bin/bash when starting the 32 | emulator. Need to provide QEMU command line options for using the built-in 33 | DHCP server etc as well in that case. 34 | - Determine the path to multipass instance data more reliably, rather than 35 | use a hardcoded path based on where it's installed by default when using 36 | "snap install multipass". 37 | - Add option and/or environment variable for the GDB server port to use, rather 38 | than the default 1234 (to allow for parallell kernel debugging environments 39 | running). 40 | - Feed customized cloud-init configuration to multipass launch, to set a 41 | password etc (comes in handy if we boot interactively in QEMU for a 42 | kernel-debugging session, rather than just use init=/bin/bash) 43 | 44 | Example usage: 45 | 46 | ```bash 47 | # Set up an Ubuntu 20.04-based VM and start a kernel source debugging session 48 | ./setup-kernel-debugging 20.04 dev 49 | 50 | # The same as above, but with a specific "cloud image" URL 51 | ./setup-kernel-debugging \ 52 | https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img \ 53 | dev 54 | ``` 55 | 56 | The second argument (i.e. "dev" in the examples above) is just the name to use 57 | for the VM, and the directory where the files for the VM, as well as the scripts 58 | to run it, will be placed. 59 | 60 | Read the source. 61 | -------------------------------------------------------------------------------- /setup-kernel-debugging: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) Joel Eriksson 2020 4 | # 5 | # Helper script for automated Linux kernel debugging environment setup. 6 | # 7 | # This script uses multipass (https://multipass.run/) to set up the initial VM. 8 | # 9 | # It will assume that you have installed multipass using "snap install multipass", 10 | # and that /var/snap/multipass/common/data/multipassd/vault/instances is the path 11 | # where instances are stored. Otherwise, change the "base_path" variable below. 12 | # 13 | # It also depends on QEMU (specifically, qemu-system-x86_64), GDB and tmux being 14 | # available on the host system. 15 | # 16 | # Multipass uses QEMU in the backend by default, which is what we use to set up 17 | # kernel debugging later, and it would be possible to eliminate the multipass 18 | # dependency with some work. We would need to manually create the cloud-init 19 | # configuration ISO, and either use QEMUs built-in DHCP server functionality or 20 | # run a separate DHCP server on the side (like multipass does). 21 | # 22 | # For now, this is adapted for setting up Ubuntu based VMs, but it would be 23 | # possible to make versions of this script (or add command line flags) to allow 24 | # it to be used for setting up kernel-debugging environments for other Linux 25 | # distributions as well, as long as there are cloud-init based images available. 26 | # 27 | # Note that the multipass VM currently keep running in the background after 28 | # this script has finished executing, feel free to stop and delete it in case it 29 | # is not needed though. In that case, run: 30 | # 31 | # multipass stop && multipass delete && multipass purge 32 | # 33 | # If you make changes to the multipass VM, and want to update the image that is 34 | # used for debugging, you can simply copy the image from //... 35 | # to /qemu.img after you have made the changes you need. 36 | # 37 | # Note that right now the default GDB server port (1234) is used. If we want to 38 | # run multiple kernel debugging sessions in parallell, we need to make this 39 | # adjustable (i.e. change "-s" in the qemu command line to "-gdb tcp::PORT", 40 | # and change "target remote :1234" in the gdb command line to "target remote 41 | # :PORT", in the scripts that are generated). 42 | 43 | # The path where Multipass instance data is stored. The below is the default 44 | # path used after installing multipass via Snap on Ubuntu, so you might need 45 | # to change this for your system. 46 | # 47 | # Alternatively, we could just automatically extract the path from the 48 | # ps-output when multipass is running... 49 | base_path=/var/snap/multipass/common/data/multipassd/vault/instances 50 | 51 | # Exit script immediately if any command fails 52 | set -e 53 | 54 | # IMAGE may be the name of one of the built-in images, or an URL to an image 55 | # NAME is the name of the VM to create, and is optional 56 | if [ $# -lt 1 ]; then 57 | echo "Usage: $0 IMAGE [NAME]" >&2 58 | exit 1 59 | fi 60 | 61 | image="$1" 62 | 63 | # Default number of cores, RAM and disk space 64 | cores=1 65 | memory=1G 66 | 67 | # Since we download the Linux kernel source we need some extra space. 68 | # This is probably more than necessary... But, better safe than sorry. 69 | disk=15G 70 | 71 | if [ $# -ge 2 ]; then 72 | vmname="$2" 73 | else 74 | vmname="vm$$" 75 | fi 76 | 77 | ############################################################################# 78 | # Launch VM 79 | 80 | multipass_args=( 81 | launch 82 | -n "$vmname" 83 | -c "$cores" 84 | -m "$memory" 85 | -d "$disk" 86 | "$image" 87 | ) 88 | 89 | echo "[+] Launching VM..." >&2 90 | multipass "${multipass_args[@]}" 91 | 92 | mkdir "$vmname" 93 | vmpath="$base_path/$vmname" 94 | 95 | # Find the name of the image 96 | vmfile=$(find "$vmpath" -type f ! -name cloud-init-config.iso) 97 | 98 | ############################################################################# 99 | # Update system 100 | 101 | echo "[+] Updating system..." >&2 102 | multipass exec "$vmname" -- bash -c ' 103 | sudo apt -y update && \ 104 | sudo apt -y upgrade && \ 105 | sudo apt -y dist-upgrade 106 | ' 107 | 108 | ############################################################################# 109 | # Reboot system 110 | 111 | echo "[+] Rebooting..." >&2 112 | multipass restart "$vmname" 113 | 114 | # A sleep was needed for Ubuntu 14.04, but not for 16.04, 18.04 and 20.04 115 | # Need a better way to determine if the VM is available again or not... 116 | sleep 10 117 | 118 | ############################################################################# 119 | # Copy the QEMU image now, after the target kernel has been installed 120 | 121 | cp "$vmfile" "$vmname"/qemu.img 122 | 123 | ############################################################################# 124 | # Get vmlinux with debug symbols & current kernel source 125 | 126 | echo "[+] Install debug symbols repository..." >&2 127 | multipass exec "$vmname" -- bash -c ' 128 | components="main restricted universe multiverse" 129 | repo="http://ddebs.ubuntu.com" 130 | keyid="C8CAB6595FDFF622" 131 | ( 132 | echo "deb $repo $(lsb_release -cs)-updates $components" 133 | echo "deb $repo $(lsb_release -cs)-proposed $components" 134 | ) | sudo tee -a /etc/apt/sources.list.d/ddebs.list 135 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys "$keyid" 136 | sudo perl -i -pne "s/^# deb-src/deb-src/" /etc/apt/sources.list 137 | sudo apt-get -y update 138 | sudo apt-get -y install linux-image-$(uname -r)-dbgsym 139 | sudo apt-get -y install dpkg-dev 140 | mkdir src 141 | cd src 142 | echo "[+] Retreiving kernel source..." >&2 143 | apt-get -qq source linux-image-unsigned-$(uname -r) 144 | ' 145 | 146 | ############################################################################# 147 | # Copy vmlinuz, vmlinux and initrd 148 | 149 | echo "[+] Copying vmlinuz, vmlinux and initrd..." >&2 150 | 151 | multipass exec "$vmname" -- \ 152 | sudo bash -c 'cat /boot/vmlinuz-$(uname -r)' \ 153 | > "$vmname/vmlinuz" 154 | 155 | multipass exec "$vmname" -- \ 156 | sudo bash -c 'cat /usr/lib/debug/boot/vmlinux-$(uname -r)' \ 157 | > "$vmname/vmlinux" 158 | 159 | multipass exec "$vmname" -- \ 160 | sudo bash -c 'cat /boot/init*-$(uname -r){,.img} 2>/dev/null || true' \ 161 | > "$vmname/initrd" 162 | 163 | ############################################################################# 164 | # Copying kernel source 165 | 166 | echo "[+] Copying kernel source from VM to host..." >&2 167 | 168 | multipass exec "$vmname" -- \ 169 | tar cf - src | tar -C "$vmname" -xf - 170 | 171 | ############################################################################# 172 | # Extract boot parameters from GRUB configuration 173 | 174 | echo "[+] Extracting boot parameters from GRUB configuration..." >&2 175 | 176 | args=$( 177 | multipass exec "$vmname" -- \ 178 | sudo bash -c ' 179 | boot_args="$( 180 | grep /boot/vmlinuz-$(uname -r) /boot/grub/grub.cfg \ 181 | | head -n1 | awk "{\$1=\$2=\"\"; print \$0}" | tr -s " " 182 | )" 183 | args=${boot_args%% } 184 | args=${boot_args## } 185 | echo "$args" 186 | ' 187 | ) 188 | 189 | ############################################################################# 190 | # Creating emu script 191 | 192 | echo "[+] Creating script to start VM..." >&2 193 | 194 | cat<"$vmname/emu" 195 | #!/bin/bash 196 | 197 | basedir="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd -P)" 198 | 199 | opts=( 200 | --enable-kvm 201 | 202 | -s 203 | 204 | -smp 4 205 | -m 2048M 206 | -cpu host 207 | -nographic 208 | 209 | -drive file="\$basedir/qemu.img",if=none,format=qcow2,discard=unmap,id=hda 210 | -device virtio-scsi-pci,id=scsi0 211 | -device scsi-hd,drive=hda,bus=scsi0.0 212 | 213 | -kernel "\$basedir/vmlinuz" 214 | -initrd "\$basedir/initrd" 215 | -append "$args nokaslr rw init=/bin/bash" 216 | ) 217 | 218 | exec qemu-system-x86_64 "\${opts[@]}" 219 | EOF 220 | 221 | chmod 755 "$vmname/emu" 222 | 223 | ############################################################################# 224 | # Creating dbg script 225 | 226 | echo "[+] Creating script to start kernel debugger..." >&2 227 | 228 | cat<<'EOF'>"$vmname/dbg" 229 | #!/bin/bash 230 | 231 | cd "$(dirname "${BASH_SOURCE[0]}")" 232 | 233 | subst_path="$( 234 | strings vmlinux \ 235 | | grep ^/build/linux- | head -n1 | cut -d/ -f1-4 236 | )" 237 | src_path=$(echo $(pwd)/src/linux-*) 238 | 239 | exec gdb -q vmlinux \ 240 | -ex "set substitute-path $subst_path $src_path" \ 241 | -ex 'target remote :1234' 242 | EOF 243 | 244 | chmod 755 "$vmname/dbg" 245 | 246 | ############################################################################# 247 | # Creating run script 248 | 249 | echo "[+] Creating script to run VM and kernel debugger in tmux..." >&2 250 | 251 | cat<<'EOF'>"$vmname/run" 252 | #!/bin/bash 253 | 254 | cd "$(dirname "${BASH_SOURCE[0]}")" 255 | 256 | exec tmux new-session \; \ 257 | send-keys ./emu Enter \; \ 258 | split-window -v \; \ 259 | send-keys \ 260 | "sleep 1" Enter \ 261 | ./dbg Enter 262 | EOF 263 | 264 | chmod 755 "$vmname/run" 265 | 266 | echo "[+] Done!" >&2 267 | ls -l "$vmname" 268 | 269 | echo "Starting $vmname/run..." >&2 270 | sleep 5 271 | 272 | exec "$vmname/run" 273 | -------------------------------------------------------------------------------- /setup-kernel-debugging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clevcode/vulndev-tools/94bcd3eff6f8059c482093920bab7c1e0fc8f59e/setup-kernel-debugging.gif --------------------------------------------------------------------------------