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