The goal of the DVRF project is to simulate a real-world environment to help people learn about other CPU architectures outside of the x86_64 space. The project will also help people get into discovering new things about hardware. As of now this DVRF firmware is tailored for the Linksys E1550 Device. If you do not have one don’t worry! Ready to get a jump start on learning aspects of embedded device hacking for exploit development? If so, this project is for you.

Now that v0.1 has been released for DVRF, I wanted to make this post to help people get started with DVRF even if they don't have an E1550 in hand. For this post we'll be going over how to use DVRF with QEMU.

To get started you'll need to do the following:

-- CODE lang-shell --$ sudo apt-get install qemu-user-static

Reading package lists… Done

Building dependency tree

Reading state information… Done

The following NEW packages will be installed:

qemu-user-static

0 upgraded, 1 newly installed, 0 to remove and 25 not upgraded.

Need to get 0 B/7,795 kB of archives.

After this operation, 79.4 MB of additional disk space will be used.

Selecting previously unselected package qemu-user-static.

(Reading database ... 173955 files and directories currently installed.)

Preparing to unpack .../qemu-user-static_2.0.0+dfsg-2ubuntu1.21_amd64.deb ...

Unpacking qemu-user-static (2.0.0+dfsg-2ubuntu1.21) ...

Processing triggers for man-db (2.6.7.1-1ubuntu1) ...

Setting up qemu-user-static (2.0.0+dfsg-2ubuntu1.21) ...

Once you have qemu-user-static installed you'll next want to install Binwalk. Make sure to follow the instructions so you have all of the dependancies needed to extract the squash-fs within the DVRF binary. Once Binwalk is installed you will also want to download the uClibc Buildroot tar file. This is crucial since this is going to be your bread and butter for cross compiling and also debugging, especially if you don't have IDA. To get started do the following:

-- CODE lang-shell --$ wget https://buildroot.org/downloads/buildroot-2015.11.1.tar.gz

––2016-01-20 22:53:34–– https://buildroot.org/downloads/buildroot-2015.11.1.tar.gz

Resolving buildroot.org (buildroot.org)... 140.211.167.224

Connecting to buildroot.org (buildroot.org)|140.211.167.224|:443… connected.

HTTP request sent, awaiting response… 200 OK

Length: 5460407 (5.2M) [application/x-gzip]

Saving to: ‘buildroot-2015.11.1.tar.gz’



100%[======================================>] 5,460,407 87.5KB/s in 57s



2016-01-20 22:54:33 (92.7 KB/s) - ‘buildroot-2015.11.1.tar.gz’ saved [5460407/5460407]



$ tar xzf buildroot-2015.11.1.tar.gz

$ cd buildroot-2015.11.1/



b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ ls

arch build Config.in.legacy docs Makefile README toolchain

board CHANGES configs fs Makefile.legacy support

boot Config.in COPYING linux package system

Now you're going to type make menuconfig and when it's done you're going to see the following:

Under Target you're going to select MIPS little endian, ELF, and mips32. Soft float can be enabled since for now it doesn't matter for the exercises I have under /pwnables.

Under Toolkit you'll want to set the C Library to uClibc since the binary is compiled with this library and most devices you'll come across will be using this C library.

Also under Toolkit you'll want to enable "Build cross gdb for the host." This will create a gdb binary that will run on your host (e.g. x86_64) but will support your target Architecture (e.g. MIPS). This is helpful for debugging applications when using the -g argument in Qemu.

Make sure to save your configuration changes so that your toolkit will compile for the right Architecture we've chosen.

Now feel free to either explore what other options the toolkit can provide or exit the menu and type "make" but be warned that this process does take a while so it might be a good time to go grab a cup of coffee and also make sure you have an internet connection since this process will download tar files that are needed for compiling.

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ make menuconfig



*** End of the configuration.

*** Execute 'make' to start the build or try 'make help'.



b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ make

/usr/bin/make -j1 HOSTCC="/usr/bin/gcc" HOSTCXX="/usr/bin/g++" silentoldconfig

make[1]: Entering directory /home/b1ack0wl/DVRF/buildroot-2015.11.1'

mkdir -p /home/b1ack0wl/DVRF/buildroot-2015.11.1/output/build/buildroot-config/lxdialog

[...Truncated…]

Once the toolkit has finished compiling you'll see a new folder called output. This is where the toolkit compiled, but we'll only care about what's been compiled into the host folder within output.

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ ls

arch build Config.in.legacy dl linux output support

board CHANGES configs docs Makefile package system

boot Config.in COPYING fs Makefile.legacy README toolchain

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ cd output/

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output $ ls

build host images staging target

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output $ cd host/usr/

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output/host/usr $ ls

bin include lib libexec mipsel-buildroot-linux-uclibc share x86_64-unknown-linux-gnu

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output/host/usr $ cd bin/

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output/host/usr/bin $ ls *-build*

mipsel-buildroot-linux-uclibc-addr2line mipsel-buildroot-linux-uclibc-gcov

mipsel-buildroot-linux-uclibc-ar mipsel-buildroot-linux-uclibc-gdb

mipsel-buildroot-linux-uclibc-as mipsel-buildroot-linux-uclibc-gprof

mipsel-buildroot-linux-uclibc-cc mipsel-buildroot-linux-uclibc-ld

mipsel-buildroot-linux-uclibc-cc.br_real mipsel-buildroot-linux-uclibc-ld.bfd

mipsel-buildroot-linux-uclibc-c++filt mipsel-buildroot-linux-uclibc-ldconfig

mipsel-buildroot-linux-uclibc-cpp mipsel-buildroot-linux-uclibc-ldd

mipsel-buildroot-linux-uclibc-cpp.br_real mipsel-buildroot-linux-uclibc-nm

mipsel-buildroot-linux-uclibc-elfedit mipsel-buildroot-linux-uclibc-objcopy

mipsel-buildroot-linux-uclibc-gcc mipsel-buildroot-linux-uclibc-objdump

mipsel-buildroot-linux-uclibc-gcc-4.9.3 mipsel-buildroot-linux-uclibc-ranlib

mipsel-buildroot-linux-uclibc-gcc-4.9.3.br_real mipsel-buildroot-linux-uclibc-readelf

mipsel-buildroot-linux-uclibc-gcc-ar mipsel-buildroot-linux-uclibc-size

mipsel-buildroot-linux-uclibc-gcc.br_real mipsel-buildroot-linux-uclibc-strings

mipsel-buildroot-linux-uclibc-gcc-nm mipsel-buildroot-linux-uclibc-strip

mipsel-buildroot-linux-uclibc-gcc-ranlib

You can see that we have cross compilers and an instance of gdb. We will use this for crafting our exploits. Now that we have binwalk, buildroot, and qemu-user-static installed we can get started on the first pwnable within the Intro folder. First we need to extract the contents within the binary file. We will use binwalk to help us extract the binary with options -e for Extract and -M for Matryoshka which will extract recursively for up to 8 layers deep.

-- CODE lang-shell --$ binwalk -eM ./DVRF_v01.bin



Scan Time: 2016-01-21 19:44:52

Target File: /home/b1ack0wl/DVRF/DVRF_v01.bin

MD5 Checksum: 34dced9038b2d1e205b6c0f68991ccfe

Signatures: 343



DECIMAL HEXADECIMAL DESCRIPTION

––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

0 0x0 BIN-Header, board ID: 1550, hardware version: 4702, firmware version: 1.0.0, build date: 2012-02-08

32 0x20 TRX firmware header, little endian, image size: 7753728 bytes, CRC32: 0x97096BA6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x192704, rootfs offset: 0x0

60 0x3C gzip compressed data, maximum compression, has original file name: "piggy", from Unix, last modified: 2015-12-31 10:44:22

1648420 0x192724 Squashfs filesystem, little endian, non-standard signature, version 3.0, size: 6099526 bytes, 447 inodes, blocksize: 65536 bytes, created: 2016-01-19 01:47:20

[...Truncated…]

You will now have a folder that should start with _DVRF which contains all of the necessary files for these exercises. So go ahead and change directory to DVRFv01.bin.extracted/squashfs-root/ and perform the following.

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root $ cp `which qemu-mipsel-static` ./

b1ack0wl@b1ack0wl-VM ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root $ ls

bin etc media proc qemu-mipsel-static sys usr www

dev lib mnt pwnable sbin tmp var

b1ack0wl@b1ack0wl-VM ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root $

We need to have the statically built Qemu instance on our squash-fs root directory since we are going to chroot the environment when emulating the binaries. So we're pretty much ready to get started! Let's go ahead and test out our environment by performing the following command: sudo chroot <current directory> <qemu-mipsel-static> <path to binary to emulate> argv[1]

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root $ sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 test123

Welcome to the first BoF exercise!



You entered test123

Try Again

Awesome!! We can execute the binary without any issues! Now for the last step we need to debug the application and we will use qemu again but we will feed it the -g argument which will attach a gdbserver instance to it but won't execute the binary until an attached gdb instance initiates the continue instruction.

First get two terminals open and in one terminal type in the following command: sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stackbof01 test123 Remember -g 1234 means that gdbserver is going to start listening on port 1234. Now in the other terminal window you'll want to use the crossed compiled gdb that's located within the buildroot output folder.

You should now be at this step:

Just for fun you can even disassemble the file using the objdump we compiled with option -D

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1/output/host/usr/bin $ ./mipsel-buildroot-linux-uclibc-objdump -D ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root/pwnable/Intro/stack_bof_01 | more



/home/b1ack0wl/DVRF/_DVRF_v01.bin.extracted/squashfs-root/pwnable/Intro/stack_bof_01: file f

ormat elf32-tradlittlemips





Disassembly of section .interp:



004000f4 <.interp>:

4000f4: 62696c2f 0x62696c2f

4000f8: 2d646c2f sltiu a0,t3,27695

4000fc: 696c4375 0x696c4375

400100: 732e6362 0x732e6362

400104: 00302e6f 0x302e6f



Disassembly of section .reginfo:



00400108 <.reginfo>:

400108: b20001f6 0xb20001f6

...

40011c: 00448ce0 0x448ce0



Disassembly of section .dynamic:



00400120 <_DYNAMIC>:

400120: 00000001 movf zero,zero,$fcc0

400124: 00000083 sra zero,zero,0x2

400128: 00000001 movf zero,zero,$fcc0

40012c: 000000ac 0xac

400130: 0000000c syscall

400134: 0040059c 0x40059c

[...Truncated…]



004007e0 <main>:

4007e0: 3c1c0005 lui gp,0x5

4007e4: 279c8500 addiu gp,gp,-31488

4007e8: 0399e021 addu gp,gp,t9

4007ec: 27bdff18 addiu sp,sp,-232

4007f0: afbf00e4 sw ra,228(sp)

4007f4: afbe00e0 sw s8,224(sp)

4007f8: 03a0f021 move s8,sp

4007fc: afbc0010 sw gp,16(sp)

400800: afc400e8 sw a0,232(s8)

400804: afc500ec sw a1,236(s8)

400808: 8f82801c lw v0,-32740(gp)

40080c: 00000000 nop

400810: 94420b98 lhu v0,2968(v0)

400814: 00000000 nop

400818: a7c20018 sh v0,24(s8)

40081c: 27c2001a addiu v0,s8,26

400820: 240300c6 li v1,198

400824: 00402021 move a0,v0

400828: 00002821 move a1,zero

40082c: 00603021 move a2,v1

400830: 8f998040 lw t9,-32704(gp)

400834: 00000000 nop

400838: 0320f809 jalr t9

40083c: 00000000 nop

400840: 8fdc0010 lw gp,16(s8)

400844: 8fc200e8 lw v0,232(s8)

[...Truncated…]



00400950 <dat_shell>:

400950: 3c1c0005 lui gp,0x5

400954: 279c8390 addiu gp,gp,-31856

400958: 0399e021 addu gp,gp,t9

40095c: 27bdffe0 addiu sp,sp,-32

400960: afbf001c sw ra,28(sp)

400964: afbe0018 sw s8,24(sp)

400968: 03a0f021 move s8,sp

40096c: afbc0010 sw gp,16(sp)

400970: 8f82801c lw v0,-32740(gp)

400974: 00000000 nop

400978: 24440c60 addiu a0,v0,3168

40097c: 8f998050 lw t9,-32688(gp)

400980: 00000000 nop

400984: 0320f809 jalr t9

400988: 00000000 nop

40098c: 8fdc0010 lw gp,16(s8)

400990: 00000000 nop

400994: 8f82801c lw v0,-32740(gp)

400998: 00000000 nop

40099c: 24440c94 addiu a0,v0,3220

[...Truncated…]

So all we need to do to solve this is change the return pointer to function <dat_shell> which is located at 0x00400950 remember this is little endian and we cannot use NULL bytes but once you get the picture you should just about have the following:

-- CODE lang-shell --b1ack0wl@b1ack0wl-VM ~/DVRF/_DVRF_v01.bin.extracted/squashfs-root $ sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "[REDACTED]"

Welcome to the first BoF exercise!



You entered [REDACTED]

Try Again

Congrats! I will now execute /bin/sh

- b1ack0wl

qemu: uncaught target signal 11 (Segmentation fault) - core dumped

You can see the Segmentation Fault this is due to a pointer within the stack being corrupted during the overflow. Your goal is to make this program not segfault so use the tools I provided and make sure to use breakpoints! To get you started here is a proof of concept:

I hope this has helped you get started into your journey into embedded device exploitation. If you have any questions feel free to find me on twitter at @b1ack0wl

DVRF v0.1 has been released on GitHub!!

