This is an old revision of the document!
You will spend a large part of the labs and assignments working with *binaries*; in some of the cases we will also provide you with source code. You will have to find vulnerabilities in those binaries, then (possibly) exploit them and (possibly) fix the vulnerabilities in order to illustrate various secure coding practices. To achieve this, first you need to get comfortable with at least some of the common tools that are right for the job.
In the introductory lab we'll spice things up a bit by providing some simple binaries (with no source code) for you to play with. In order to solve the lab, you'll have to perform both static analysis and dynamic analysis on said binaries.
If you're too comfortable with the x86 architecture and feel that you could use some challenge, the lab archive also contains the binaries compiled for ARM. You can try them out by running a Raspbian image on QEMU (Raspbian image, Linux kernel image).
GLaDOS' binary even-password
is asking you to provide a password:
$ ./even-password Enter password:
Unfortunately, the program isn't very well thought out, the password being hard-coded. There are a few possible approaches to this (try them all):
strings
to see if the password is hard-coded as an ASCII stringobjdump
to see if the password is hard-coded as a set of instructions (e.g. copying characters into a buffer)
Here's a short tutorial on using Radare2. We can analyze a binary using r2 [binary_name]
, where [binary_name]
is a given binary. To get online help, we can use the following commands:
$ r2 even-password [0x00001090]> ? Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ... Append '?' to any char command to get detailed help ... [0x08048400]> p? #provide help for p command Usage: p[=68abcdDfiImrstuxz] [arg|len] ...
To disassemble the file, we can use the pd
command, e.g.
[0x00001090]> pd@main ;-- main: 0x00001175 55 push rbp 0x00001176 4889e5 mov rbp, rsp 0x00001179 4883ec10 sub rsp, 0x10 0x0000117d 488d3d840e00. lea rdi, qword str.Enter_password: ; 0x2008 ; "Enter password: " 0x00001184 b800000000 mov eax, 0 0x00001189 e8b2feffff call sym.imp.printf ...
Same as the previous task, only this time the password is a non-ASCII string. The following approach should work:
main
. What functions does it call?python
or perl
to output the string.
Note: You can use Radare2 to disassemble individual functions with the pdf
command. You can also use it to output control flow graphs, using the ag
command.
Note: to output raw bytes, use the following snippets as reference:
$ # python $ python -c 'print "\x02"*20 + "\x03"' # output 0x02 20 times, followed by 0x03 and a newline $ # perl $ perl -e 'print "\x02"x20 . "\x03"' # output 0x02 20 times, followed by 0x03
For more complex strings, consider putting everything in a (Python or Perl) script.
Disassemble halting-problem
and take a look at it:
[0x08048330]> af@main [0x08048330]> pdf@main / (fcn) sym.main 64 | 0x0804842d 55 push ebp | 0x0804842e 89e5 mov ebp, esp | 0x08048430 83e4f0 and esp, 0xfffffff0 | 0x08048433 83ec10 sub esp, 0x10 | 0x08048436 c7042400850. mov dword [esp], str.BrbImouttogetcookies. | ; CODE (CALL) XREF from 0x08048306 (fcn.08048306) | ; CODE (CALL) XREF from 0x08048300 (sym.imp.puts) | ; CODE (CALL) XREF from 0x08048326 (fcn.08048326) | 0x0804843d e8befeffff call 0x108048300 ; (sym.imp.puts) | sym.imp.puts(unk) | 0x08048442 c704241d850. mov dword [esp], str.Goingtohaltanytimenow... | 0x08048449 e8b2feffff call 0x108048300 ; (sym.imp.puts) | sym.imp.puts() | 0x0804844e c70424a0860. mov dword [esp], 0x186a0 | ; CODE (CALL) XREF from 0x080482f0 (sym.imp.sleep) | 0x08048455 e896feffff call 0x1080482f0 ; (sym.imp.sleep) | sym.imp.sleep() | 0x0804845a c704243a850. mov dword [esp], str.Done | 0x08048461 e89afeffff call 0x108048300 ; (sym.imp.puts) | sym.imp.puts() | 0x08048466 b800000000 mov eax, 0x0 | 0x0804846b c9 leave \ 0x0804846c c3 ret
Notice that it calls sleep
with the value 0x186a0
:
$ rax2 0x186a0 100000
Use a hex editor of your choice (Bless, HTE etc.) to edit the value to something more convenient. If you prefer using vim
, then you can convert the current buffer to hex and back to binary. Load the executable in vim
, then use the following:
:%!xxd <edit stuff> :%!xxd -r
To find the code, you can search for the opcodes (use pd 2@addr
and px
to see the exact values).
Use only dynamic analysis to figure out what straceme
does. First strace
it:
$ strace ./straceme ...
It doesn't seem to be doing anything relevant, so let's run it in gdb
. We use layout asm
to display the current location in the assembly code. It is not necessary when peda is enabled, you will need this for ARM analysis in QEMU VM where peda is not available. stepi
/si
is used to step into individual instruction.
$ gdb ./straceme (gdb) b main (gdb) r (gdb) stepi <repeat this a few times, to observe the program's control flow>
If we run the program a couple of times, we observe that the condition for cmpl $0x2,0x8(%ebp)
fails. Let's inspect that address:
(gdb) x $ebp+0x8 0xffffd950: 0x00000001
The ebp
register holds the base pointer for the current stack frame. We notice that $ebp + 8
holds the value 1, while our program expects the value 2
. What is that value?
After figuring that out, run the program with strace
again to determine the password.
guesser
reads an unsigned int
from /dev/urandom
and asks you to guess it.
objdump
or Radare2 and examine its control flow.gdb
and place a breakpoint after the read
call.read
. If in doubt, consult the GDB documentation and the read (2) manpage.Try the above tasks using the ARM binaries. For static analysis you can use Radare2 directly on the host machine. For the other tools (gdb, strace, objdump) you can use the QEMU setup described in the introduction.
Shift PageUp
and Shift PageDown
.$ file 2015-05-05-raspbian-wheezy.img ;; From the output of the file command, take the partition 2 'startsector' ;; value an multiply by 512, and use this figure as the offset value in the mount command below. $ sudo mount 2015-05-05-raspbian-wheezy.img -o offset=62914560 /mnt ;; Add the tasks in the filesystem mounted in /mnt. $ sudo umount 2015-05-05-raspbian-wheezy.img /mnt