Starting a User Mode Linux/Debian-OS as an unprivileged Linux User

Search for a command to run...

Deep technical analysis of bypassing eBPF-based security solutions through kernel-level hooks targeting BPF iterators, ringbuffers, and perf events

Abstract Running multiple VPN tunnels on a system has become a de-facto standard on all of my machines since 2+ decades. Historically, these types of tunnels consisted of OpenVPN IPSEC WireGuard During a recent migration effort, I was able to el...

TL;DR: Execute a binary on a Linux system when execution is not allowed (e.g. restricted PHP environment, read-only filesystem or noexec mount flag). By using only Bash and making syscall(2)’s from Bash (!) and piping the ELF binary straight from the...

TL;DR: Proton Mail generates PGP key and publishes it upon account creation using Web Key Directory (WKD) standard. The key contains account creation timestamp, with second precision, which reflects the account creation date. Proton, a privacy-orient...

Knowledge Base
15 posts
On this page
After reading this article you will be able to start a Debian-Linux (including Kernel) from any (unprivileged) Linux shell.
User Mode Linux (UML) is a modified Linux Kernel that the user starts just like any other Linux program. The UML-Kernel then "boots" a 'Guest Debian Linux' to which the user can log in as root.
This is a great way to play around on a root-shell on an isolated Linux.
Think of UML as something between Docker and a VM:
All processes are visible on the host but 'kind of' isolated.
All processes run at near host speed (~15% slower).
All capabilities and privileges are available within the Guest OS.
Host and Guest OS must be of the same architecture (e.g. both x86_64).
Does not require access to /dev/kvm.
Alternatively, read Starting a VM as an unprivileged Linux User for using a full VM instead (which will run slower but better isolated).
The instructions have been tested on Segfault's Disposable Root Servers.
[[ ! -f ~/.ssh/id_ed25519 ]] && ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
mkdir uml
cd uml
wget https://deb.debian.org/debian/pool/main/u/user-mode-linux/user-mode-linux_5.10um3+b1_amd64.deb
ar x user-mode-linux_5.10um3+b1_amd64.deb
rm user-mode-linux_5.10um3+b1_amd64.deb control.tar.xz debian-binary
tar -xf data.tar.xz
rm data.tar.xz
mv usr/bin/linux.uml .
mv usr/lib/uml/modules .
rm -r usr
[[ ! -f ~/.slirprc ]] && echo "redir tcp 2222 22" >~/.slirprc
wget -O debian.img https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.raw
truncate -s 8G debian.img
export TMPDIR=/tmp
./linux.uml \
mem=1024M \
root=/dev/ubda1 rw \
ubd0=debian.img \
systemd.unit=emergency.target
Press Enter when prompted to configure the system:
sed '/boot\/efi/d' -i /etc/fstab
echo "none /lib/modules/$(uname -r) hostfs /sec/root/uml/modules/$(uname -r) 0 2" >>/etc/fstab
mkdir -p /lib/modules/$(uname -r)
# Mount the host's /sec inside the guest OS:
echo "none /mnt/host-fs hostfs / 0 2" >>/etc/fstab
mkdir -p /mnt/host-fs
ln -s /mnt/host-fs/sec /sec # segfault.net specific
systemctl mask systemd-binfmt.service
systemctl disable getty@tty1
systemctl enable getty@tty0
ssh-keygen -A
cat > /etc/netplan/90-default.yaml <<-'EOF'
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: no
addresses: [10.0.2.15/24]
routes:
- to: default
via: 10.0.2.2
on-link: true
nameservers:
addresses: [10.0.2.3]
EOF
growpart /dev/ubda 1
resize2fs /dev/ubda1
# Add an SSH Key
systemctl daemon-reload
mount /mnt/host-fs
cp /mnt/host-fs/root/.ssh/id_ed25519.pub ~/.ssh/authorized_keys
poweroff
cat >launch.sh <<-'EOF'
#! /bin/sh
cd "$(dirname "$0")" || exit
export TMPDIR=/tmp
exec ./linux.uml mem=1024M root=/dev/ubda1 ubd0=debian.img eth0=slirp,52:54:00:00:01,/usr/bin/slirp-fullbolt
EOF
chmod +x launch.sh
./launch.sh
Log in using root without a password or use ssh -p2222 root@0 .

# UML Kernel does not come with all netfilter modules.
# Use iptables in "legacy"-mode instead:
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
# Install docker
apt update
apt install docker.io
# Start 'Alpine/Linux' inside Docker, inside UML.
docker run --rm -it alpine
# On the UML guest:
apt install telnet
# Make Linux less stupid (10.0.2.0 is indeed a valid IP):
iptables -t nat -I OUTPUT -p tcp -d 10.0.2.1 -j DNAT --to-destination 10.0.2.0
# Access the Slirp console
telnet 10.0.2.1
Shoutz to Matthew (🫵🧠👍).