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:

$ 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:
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 ( ...
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:

$ wget
--2016-01-20 22:53:34--
Resolving (
Connecting to (||: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  docs   Makefile         README   toolchain
board  CHANGES    configs           fs     Makefile.legacy  support
boot  COPYING           linux  package          system

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

make menuconfig

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.

CPU Architecture

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.

uClibc 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.

GDB Support

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.

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

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.

b1ack0wl@b1ack0wl-VM ~/DVRF/buildroot-2015.11.1 $ ls
arch   build  dl    linux            output   support
board  CHANGES    configs           docs  Makefile         package  system
boot  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

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.

$ 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

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

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.

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]

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

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

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)

  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

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:

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!!


Your World, Secured.

Tech Puzzles

Try our Puzzles

Test your problem solving skills. Do you have what it takes?

Try puzzles »