Rick Ramgattie's InfoSec Adventures

| Posts | About |

Extracting firmware with just a UBoot Shell (eWeLink Camera)

Published Date: 2020-01-15

Embedded device (IoT) hacking often starts with running a firmware image through an extraction tool like Binwalk. Although firmware is readily available most consumer devices, it isn’t always the case that you can download it off of the manufacturers website or ask them for a copy. When neither of those options work, we tend to turn to “hardware hacking.” Unless you are immediately dropped into a full root shell on your target, you are going to need to get crafty with what you have access to in the bootloader.

In this blog I have provided a walkthrough of my experience extracting the firmware for the eWeLink FGHGF VG-IC-01 IP Camera by leveraging some of the commands available to us through UBoot. By the end of this blog you should be able to pick one of these cameras up yourself and extract the device’s firmware for your own reverse engineering adventures.

Download Files for This Walkthrough

Getting into UBoot

If you want to follow along at home, I recommend getting one of these FTDI USB To TTL Serial Converters and reading my good friend Ian Sindermann’s blog. There he goes over the basics of UART, and provides some general safety tips.

In the image bellow this paragraph there are arrows that point to the solder points you will need to get a console. These pins are on the flipside of the board after you remove the external screws and the top screws from the board. If you followed Ian’s blog, you will see that you need to connect the Camera’s RX to the FTDI’s TX, then Camera’s TX to the FTDI’s RX, and ground to ground.

eWeLink Camera

Figure 1: eWeLink FGHGF VG-IC-01 IP Camera
Arrows to Screws
Figure 2: Screws to Open Camera
Arrows to Screws Top of Board
Figure 3: Screw to Access Bottom of Board
Arrows to RX and TX
Figure 4: UART Headers

In order to find the right baud rate I just went to the list that Ian provides in his blog. Here is the command I ran to connect to the UART interface sudo screen /dev/ttyUSB0 115200, where /dev/ttyUSB0 is our FTDI converter. If you want to see the whole boot process you need to run this command before you power on the camera.

Booting the Device Up:

When we plug the device in, it is going to show us the output of the boot process. If we let the device bootup fully, it is going to prompt us for a username and password. I tried a couple of the usual suspects, but none of them seemed to work.

Welcome to root (armv6l-Linux-3.4.43-gk@/dev/ttySGK0/b) GOKE ARM Linux 3.3 to Copyright (C) 2005 @DaYunLinks root login:

Figure 5: Login Prompt:

If we scroll up to the beginning we can see that there is a 1 second window where we can hit the Enter key to interrupt the boot process and gain access to a UBoot shell. If you are trying to scroll up in screen you need to hit Ctrl-a and Esc, then you can scroll with the arrow keys. You can see this prompt at the top of screenlog.0

U-Boot 2012.10 (Dec 28 2018 - 10:59:46) for GK7102 dyzl-gk-ic-used-gc1024-v1.0 (GOKE) HAL: 20160913 DRAM: 64 MiB Flash: [W25Q64FV] USE 4X mode read and 4X mode write 8 MiB NAND: [No SPI nand] SF: 8 MiB [page:256 Bytes] [sector:64 KiB] [count:128] (W25Q64FV) In: serial Out: serial Err: serial Net: Int PHY Hit Enter key to stop autoboot: 1

Figure 6: UBoot Access Prompt

Once in the UBoot shell you are going to have access to a limited set of commands. Below you can see what we are provided with. I had a hard time understanding some of the commands. If you are also having a hard time check out this UBoot commands reference. You can see the list of commands as they were displayed in UBoot in screenlog.1.

GK7102 # ? - alias for 'help' base - print or set address offset bdinfo - print Board Info structure boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' bootelf - Boot from an ELF image in memory bootm - boot application image from memory bootp - boot image via network using BOOTP/TFTP protocol bootvx - Boot vxWorks from an ELF image bootz - boot Linux zImage image from memory cmp - memory compare coninfo - print console devices and information cp - memory copy crc32 - checksum calculation dhcp - boot image via network using DHCP/TFTP protocol echo - echo args to console editenv - edit environment variable env - environment handling commands erase - erase FLASH memory flinfo - print FLASH memory information gkgpio - set gpio_x env go - start application at address 'addr' help - print command description/usage iminfo - print header information for application image imls - list all images found in flash imxtract- extract a part of a multi-image itest - return true/false on integer compare loadb - load binary file over serial line (kermit mode) loads - load S-Record file over serial line loady - load binary file over serial line (ymodem mode) loop - infinite loop on address range md - memory display mm - memory modify (auto-incrementing address) mtest - simple RAM read/write test mw - memory write (fill) nfs - boot image via network using NFS protocol nm - memory modify (constant address) ping - send ICMP ECHO_REQUEST to network host printenv- print environment variables protect - enable or disable FLASH write protection reset - Perform RESET of the CPU run - run commands in an environment variable saveenv - save environment variables to persistent storage setenv - set environment variables sf - SPI flash sub-system sleep - delay execution for some time snand - SpiNAND sub-system source - run script from memory tftpboot- boot image via network using TFTP protocol tftpput - TFTP put command, for uploading files to a server version - print monitor, compiler and linker version

Figure 7: UBoot Commands

Typically you can get around the login prompt that is in our way by editing the bootargs environment variable so that init would be init=/bin/sh, however after editing and saving the device still prompts us for a username and password.

Working with UBoot Commands

After going through the list of commands provided by UBoot I saw that there are two commands that could make this work for us. The first is sf, which has a read option that provides us with the ability to read memory from one address to another. The second is md, which displays memory contents onto the screen.

sf read <destination address> <start offset> <length> md <start address> <# of objects>

Figure 8: Memory Reading and Displaying Commands

But, we need to know the offsets of the data we want to read if we want to use sf. Lucky for us, this information is provided over UART when the device boots up. If you open the screenlog.0 file from the tar for this blog you will be able to find the offsets, I have included them here as well so that you don’t have to divert your attention.

[ 0.830000] 0x000000000000-0x000000050000 : "boot" [ 0.840000] 0x000000050000-0x0000001b0000 : "linux" [ 0.840000] 0x0000001b0000-0x000000500000 : "rootfs" [ 0.850000] 0x000000500000-0x000000590000 : "user" [ 0.860000] 0x000000590000-0x000000800000 : "app"

Figure 9: Offsets in Memory

Based on these offsets, we want to display everything from 0x000000000000 to 0x000000800000. After reading the UBoot reference I linked above, I realized that I first need to run sf probe, and then you can run sf read. Here are the commands I ran to read from “disk to memory”.

sf probe 0 sf read 0xC1000000 0x0 0x800000

Figure 10: UBoot Command to Read From Disk to Memory

After I read everything into memory I ran the “memory display” command. It is important that you make sure you are recording screen’s output to a file. While in screen hit Ctrl-a and Shift-h; this will write everything from that point on.

md 0xC1000000 0x800000

Figure 11: UBoot Command to Dump the Memory to Screen

Extracting data from displayed memory

Now that we have displayed everything in memory within the bounds that we set, we need to transform the output into something that can be parsed by Binwalk. Below is a snippet of the first couple bytes, you can see the whole file by opening screenlog.2.

c1400000: ef724e57 6db23617 ccf7e027 4cbb9914 WNr..6.m'......L c1400010: ebbb85c4 5bb66613 327246c5 fb5ee132 .....f.[.Fr22.^. c1400020: 1c35c3eb cdf6f2d0 921be383 453814a8 ..5...........8E c1400030: 52b5fb55 2f85137c 24797ec3 2c3fe0df U..R|../.~y$..?,

Figure 12: Snippet of Memory Displayed

The first thing that we want to do is remove the first and last column from the output. We can do that pretty easily with awk. Below are the commands I ran to save the hex representation into a file called hex_numbers.txt.

cat screenlog.2 | awk '{print $2 $3 $4 $5}' > hex_numbers.txt

Figure 13: Save Only Memory Contents in Hex

This however does not create a contiguous stream of bytes, it is 16 bytes per line. In addition, if we try to convert each hex digit into the corresponding ASCII character we are going to see that order is [4,3,2,1] [8,7,6,5] instead of [1,2,3,4] [5,6,7,8]. The endianness is off! To solve both of these problems I wrote the Python script included below that outputs exactly what we need.

Figure 14: Python Script to Convert the Endianness

After you run this script you will be left with a file called device_memory.txt. If you run this file through Binwalk it will discover many different files, but there are two Squashfs file systems that contain all of the binaries and files used by the device (squashfs-root, and squashfs-root-0). Both directories are included in the tar for this blog. You should check peruse them yourself to see what we got.

binwalk -e device_memory.txt

Figure 15: Binwalk Command to Extract Files

Wrap Up

We were able to use our UBoot access to extract the firmware running on the device. After cleaning up the output of the memory display utility we modified it's output so that we have a stream of bytes of the right endianness so that our firmware extraction and tool (Binwalk) was able to find the files that comprise the device’s file system.

In the next blog, I will start taking a look at the device’s update functionality so that we can get a more “official” copy of it’s firmware straight from the source. In that blog we are going to go a disassembler called Ghidra and some reverse engineering basics.