mirror of
https://github.com/fuzzdb-project/fuzzdb.git
synced 2024-11-30 06:50:20 +00:00
776 lines
26 KiB
HTML
776 lines
26 KiB
HTML
<html>
|
|
<head>
|
|
<title>Fuzzing for Fun and Profit</title>
|
|
<pre>
|
|
KL0209LIT_fffap.txt
|
|
02.11.2009
|
|
Krakow Labs Literature [www.krakowlabs.com]
|
|
Fuzzing for Fun and Profit
|
|
http://www.krakowlabs.com/res/lit/KL0209LIT_fffap.txt
|
|
rush@KL (Jeremy Brown) [rush@krakowlabs.com]
|
|
KL0209LIT_fffap.txt
|
|
|
|
Krakow Labs Literature
|
|
"Fuzzing for Fun and Profit"
|
|
rush@KL (Jeremy Brown) [rush@krakowlabs.com]
|
|
|
|
============================================================================================================================
|
|
|
|
1) Introduction
|
|
1.1) Fuzzer Specifications
|
|
|
|
2) Local Fuzzing
|
|
2.1) Information Gathering
|
|
2.2) Writing the Fuzzer (mbsefuzz.c)
|
|
2.3) Fuzzing the Target
|
|
|
|
3) Remote Fuzzing
|
|
3.1) Information Gathering
|
|
3.2) Writing the Fuzzer (sftpfuzz.pl)
|
|
3.3) Fuzzing the Target
|
|
|
|
4) Conclusion
|
|
4.1) Disclaimer
|
|
|
|
============================================================================================================================
|
|
|
|
1) Introduction
|
|
|
|
Many different resources define fuzzing many different ways. I believe this definition is more suiting than most:
|
|
|
|
"Fuzzing is targeting input and delivering data that is handled by a target with the intent of identifying bugs."
|
|
|
|
Fuzzing can occur theoretically where ever input is possible.
|
|
|
|
There are two kinds of fuzzing: "dumb" and "smart". Dumb fuzzing is fuzzing without regard for any guidelines that may be
|
|
required for input. Smart fuzzing is just the opposite. While dumb fuzzers are easy to write and easy to use, smart fuzzers
|
|
are almost always preferred. Smart fuzzers actually know what how the handle the target's specifications for data. what input
|
|
it can fuzz, and how to fuzz it. When we refer to fuzzers in this literature, the reader should assume we are elaborating on
|
|
smart fuzzers.
|
|
|
|
Fuzzing can be done locally or remote. Some examples of local fuzzing is through command line, manipulating file formats, user
|
|
interface input, and more. Remote fuzzing is usually fuzzing protocols, servers, etc.
|
|
|
|
The data you use to fuzz with, called the fuzzing oracle, is essential to being successful at fuzzing. The fuzzing oracle
|
|
can be random data, or data that is not random at all but still provides reliable angles to fuzz which have proved successful
|
|
in triggering bugs in the past. This article focuses on the latter technique. Linux is also the host operating system that
|
|
our fuzzing examples will work on best and/or without modification.
|
|
|
|
The following table is information on what a fuzzing oracle should at least have to possibly trigger vulnerabilities.
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------
|
|
Buffer Overflows
|
|
The ability to overflow buffers in the stack or heap; often exploitable to execute code unless data is uncontrollably corrupted.
|
|
|
|
EXAMPLE: sprintf(buf, "%s", input); [we control 'input']
|
|
-------------------------------------------------------------------------------------------------------------------------------
|
|
Format Strings
|
|
The ability to control a function's format string; often exploitable to execute code unless writing data isn't possible, then
|
|
information disclosure may be achieved.
|
|
|
|
EXAMPLE: syslog(priority, input); [we control 'input']
|
|
-------------------------------------------------------------------------------------------------------------------------------
|
|
Integer Overflows
|
|
The ability to overflow an integer; often non-exploitable unless integer can be overflowed to affect size calculation of a buffer
|
|
where we control input.
|
|
|
|
EXAMPLE: if(len > 512) { return -1; } memcpy(buf, input, len); [we control 'input' and 'len']
|
|
-------------------------------------------------------------------------------------------------------------------------------
|
|
Out-of-Bounds Breakage
|
|
The ability to exploit unsafe functions; often exploitable to read, write, or execute files unless integrity checks are placed
|
|
in passing functions.
|
|
|
|
EXAMPLE: system(input); [we control 'input' and it is not sanitized]
|
|
-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
Too much data, your fuzzer shows characteristics of a stress test. Not enough data and you may miss something. Finding that
|
|
balance shouldn't be a main goal, nor should it be completely defined: there is no line to cross in fuzzing. You either
|
|
fuzz, or you don't, and there is no standard, just structure; find your niche and develop beauty in code and command line.
|
|
|
|
Fuzzing includes a lot of testing. You could spend hours and hours modifying and compiling and running the same but slightly
|
|
different code over and over just to get the better results. Planning, preparation, and testing are a part of fuzzing, and
|
|
laboring hours on end for the humble task of perfection, stability, and reproduceability can thankfully be very rewarding.
|
|
|
|
Fuzzing is useful because...
|
|
|
|
1) Fuzzing can find bugs in firmware/software that aren't open source, therefore restricting classical auditing by the public.
|
|
2) Fuzzing can be a fast and reliable bug finding solution, making source code auditing look so hard and fuzzing seem easy.
|
|
3) Fuzzing can also be used as a stress tester and memory management problem detector. It is, as concepted, a bug finding art.
|
|
|
|
============================================================================================================================
|
|
|
|
1.1 Fuzzer Specifications
|
|
|
|
Fuzzing is not usually done by hand, so people write fuzzers. There are three key elements each fuzzer should include:
|
|
|
|
1) A robust fuzzing oracle
|
|
2) A specific data format to prepare for fuzzing
|
|
3) A way of communicating with the target
|
|
|
|
Fuzzers should be semi-automatic or automatic as they fuzz and may provide features to create a quality atmosphere when
|
|
fuzzing. Some fuzzer include debuggers, event notification such as alerts and logging, and sometimes even automatic exploit
|
|
generation. Fuzzing features, in most situations, are only limited to the imagination.
|
|
|
|
A typical fuzzer could be outlined something like this (this example is in no particular programming or scripting language):
|
|
|
|
(BEGIN FUZZER)
|
|
|
|
FUZZORACLE = "A" x 550, "A" x 1100, "A" x 2100, "%n%n%n%n%n", "-1", "32767", "test|id > /tmp/fuzzed|test";
|
|
|
|
.....
|
|
|
|
OPTIONS = "FILE", "DIRECTORY", "SEND", "STORE", "RENAME";
|
|
|
|
.....
|
|
|
|
loop(run-through-fuzz-data) { send(option[count], fuzzoracle[count], target); }
|
|
|
|
(END FUZZER)
|
|
|
|
============================================================================================================================
|
|
|
|
2. Local Fuzzing
|
|
|
|
Local fuzzing deals with fuzzing applications locally or hosted on the target system. This can include, but isn't limited to:
|
|
|
|
Command Line Fuzzing - Fuzzing applications via the command line and/or environmental variables
|
|
File Format Fuzzing - Fuzzing applications that read files in a specific format or format(s)
|
|
Kernel Fuzzing - Fuzzing core kernel features, kernel modules, and system calls
|
|
|
|
As said previously, if a target takes input, it can probably be fuzzed.
|
|
|
|
============================================================================================================================
|
|
|
|
2.1 Information Gathering
|
|
|
|
As the first step in many technical projects, information gathering is vital. Knowing exactly what input your fuzzing and how
|
|
your target works is very important when writing a fuzzer. Information sources include RFCs, API specifications, other
|
|
technical documentation, sniffing, and reverse engineering.
|
|
|
|
For this example of local fuzzing, we will be exploring MBSE BBS (http://www.mbse.eu/mbse/mbsebbs/index.html) which had a
|
|
local buffer overflow in its suid "mbuseradd" program. Writing a fuzzer shouldn't be very hard for this application.
|
|
|
|
linux:/home/fuzz/mbsebbs-0.70.0/unix# make install
|
|
install -c -s -o root -g root -m 6711 mbuseradd /opt/mbse/bin
|
|
install -c -s -o root -g root -m 6711 mbpasswd /opt/mbse/bin
|
|
install -c -s -o root -g root -m 0755 mblogin /opt/mbse/bin
|
|
linux:/home/fuzz/mbsebbs-0.70.0/unix# exit
|
|
exit
|
|
fuzz@linux:~$
|
|
|
|
First, lets see exactly what we can fuzz.
|
|
|
|
fuzz@linux:~$ /opt/mbse/bin/mbuseradd
|
|
|
|
mbuseradd commandline:
|
|
|
|
mbuseradd [gid] [name] [comment] [usersdir]
|
|
fuzz@linux:~$
|
|
|
|
Seems we have 4 different arguments we can fuzz. Now lets check out the source and look for any environmental variables
|
|
that it might take as input.
|
|
|
|
fuzz@linux:~$ grep getenv audit/mbse*/*/mbuseradd.c
|
|
sprintf(shell, "%s/bin/mbsebbs", getenv("MBSE_ROOT"));
|
|
fuzz@linux:~$
|
|
|
|
Alright, we can fuzz MBSE_ROOT too.
|
|
|
|
============================================================================================================================
|
|
|
|
2.2 Writing the Fuzzer
|
|
|
|
Fuzzers can be written in probably any programming or scripting language but this example will be written in C.
|
|
|
|
When writing a fuzzer, keep in mind the principles we discussed earlier in section 1.1.
|
|
|
|
[mbsefuzz.c]
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/wait.h>
|
|
|
|
#define MBUSERADD "/opt/mbse/bin/mbuseradd"
|
|
#define LOGFILE "mbsefuzz.log"
|
|
|
|
#define FZORCTOTAL 20-1
|
|
#define ENVTOTAL 1-1
|
|
|
|
#define GID "1"
|
|
#define NAME "mbsefuzz"
|
|
#define COMMENT "fuzzing"
|
|
#define USERSDIR "/tmp"
|
|
|
|
void fuzz(char *bin, char *desc, char *src, char *a, char *b, char *c, char *d);
|
|
|
|
struct
|
|
{
|
|
|
|
char *data;
|
|
char *desc;
|
|
|
|
}
|
|
|
|
fzorc[] = // fuzzing oracle
|
|
{
|
|
|
|
{"", "A x 550"},
|
|
{"", "A x 1100"},
|
|
{"", "A x 2100"},
|
|
{"", "A x 4200"},
|
|
{"", "A x 8400"},
|
|
|
|
{"%n%n%n%n%n", "%n x 5"},
|
|
{"%%20n", "%%20n"},
|
|
{"%n%p%s%d%x", "%n%p%s%d%x"},
|
|
{"%.1024d", "%.1024d"},
|
|
{"%.2049d", "%.2049d"},
|
|
|
|
{"-1", "-1"},
|
|
{"32767", "32767"},
|
|
{"65535", "65535"},
|
|
{"-2147483647", "-2147483647"},
|
|
{"0xffffffff", "0xffffffff"},
|
|
|
|
{"a|id > /tmp/FZ|b", "a|id > /tmp/FZ|b"},
|
|
{"a`id > /tmp/FZ`b", "a`id > /tmp/FZ`b"},
|
|
{"a'id > /tmp/FZ'b", "a'id > /tmp/FZ'b"},
|
|
{"a;id > /tmp/FZ;b", "a;id > /tmp/FZ;b"},
|
|
{"a&&id > /tmp/FZ&&b", "a&&id > /tmp/FZ&&b"},
|
|
|
|
};
|
|
|
|
struct
|
|
{
|
|
|
|
char *data;
|
|
|
|
}
|
|
|
|
envvar[] = // options example, usually more than one in there
|
|
{
|
|
|
|
{"MBSE_ROOT"},
|
|
|
|
};
|
|
|
|
void fuzz(char *bin, char *desc, char *src, char *a, char *b, char *c, char *d)
|
|
{
|
|
|
|
FILE *fd;
|
|
|
|
if(fork() == 0)
|
|
{
|
|
|
|
execl(bin, bin, a, b, c, d, 0);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
int pid, signal, status;
|
|
|
|
pid = wait(&status);
|
|
|
|
if(WIFSIGNALED(status))
|
|
{
|
|
|
|
signal = WTERMSIG(status);
|
|
printf("***** SIG%d CAUGHT [%s + %s] *****\n", signal, src, desc);
|
|
|
|
fd = fopen(LOGFILE, "a+");
|
|
fprintf(fd, "[%s]->SIG%d [%s + %s]\n", bin, signal, src, desc);
|
|
fclose(fd);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
|
|
char of1[550], of2[1100], of3[2100], of4[4200], of5[8400], *src, source[32];
|
|
int i;
|
|
|
|
memset(of5, 'A', sizeof(of5));
|
|
of5[8400] = 0;
|
|
fzorc[4].data = of5;
|
|
|
|
memset(of4, 'A', sizeof(of4));
|
|
of4[4200] = 0;
|
|
fzorc[3].data = of4;
|
|
|
|
memset(of3, 'A', sizeof(of3));
|
|
of3[2100] = 0;
|
|
fzorc[2].data = of3;
|
|
|
|
memset(of2, 'A', sizeof(of2));
|
|
of2[1100] = 0;
|
|
fzorc[1].data = of2;
|
|
|
|
memset(of1, 'A', sizeof(of1));
|
|
of1[550] = 0;
|
|
fzorc[0].data = of1;
|
|
|
|
src = "CL: GID";
|
|
for(i = 0; i <= FZORCTOTAL; i++) // loops
|
|
{
|
|
|
|
fuzz(MBUSERADD, fzorc[i].desc, src, fzorc[i].data, NAME, COMMENT, USERSDIR);
|
|
|
|
}
|
|
|
|
src = "CL: NAME";
|
|
for(i = 0; i <= FZORCTOTAL; i++)
|
|
{
|
|
|
|
fuzz(MBUSERADD, fzorc[i].desc, src, GID, fzorc[i].data, COMMENT, USERSDIR);
|
|
|
|
}
|
|
|
|
src = "CL: COMMENT";
|
|
for(i = 0; i <= FZORCTOTAL; i++)
|
|
{
|
|
|
|
fuzz(MBUSERADD, fzorc[i].desc, src, GID, NAME, fzorc[i].data, USERSDIR);
|
|
|
|
}
|
|
|
|
src = "CL: USERSDIR";
|
|
for(i = 0; i <= FZORCTOTAL; i++)
|
|
{
|
|
|
|
fuzz(MBUSERADD, fzorc[i].desc, src, GID, NAME, COMMENT, fzorc[i].data);
|
|
|
|
}
|
|
|
|
src = "ENV: ";
|
|
for(i = 0; i <= ENVTOTAL; i++)
|
|
{
|
|
|
|
char *env = envvar[i].data;
|
|
|
|
snprintf(source, sizeof(source), "%s%s", src, env);
|
|
|
|
for(i = 0; i <= FZORCTOTAL; i++)
|
|
{
|
|
|
|
setenv(env, fzorc[i].data, 1);
|
|
fuzz(MBUSERADD, fzorc[i].desc, source, GID, NAME, COMMENT, USERSDIR);
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
[mbsefuzz.c]
|
|
|
|
We now have a simple, local fuzzer with command line and environmental fuzzing capabilities, as well as fault detection.
|
|
|
|
============================================================================================================================
|
|
|
|
2.3 Fuzzing the Target
|
|
|
|
Since we have written the fuzzer, we can compile and run it against our target.
|
|
|
|
Note: Some of the fuzz data is valid for mbse and may add some accounts to your system, clean out /etc/passwd after use.
|
|
|
|
fuzz@linux:~$ gcc -o mbsefuzz mbsefuzz.c
|
|
|
|
fuzz@linux:~$ ./mbsefuzz
|
|
mbuseradd: Argument 1 is too long
|
|
mbuseradd: Argument 1 is too long
|
|
mbuseradd: Argument 1 is too long
|
|
mbuseradd: Argument 1 is too long
|
|
mbuseradd: Argument 1 is too long
|
|
useradd: unknown group %n%n%n%n%n
|
|
useradd: unknown group %%20n
|
|
useradd: unknown group %n%p%s%d%x
|
|
useradd: unknown group %.1024d
|
|
useradd: unknown group %.2049d
|
|
useradd: unknown group -1
|
|
.....
|
|
useradd: invalid shell `AAAAA...../bin/mbsebbs'
|
|
useradd: invalid shell `AAAAA...../bin/mbsebbs'
|
|
useradd: invalid shell `AAAAA...../bin/mbsebbs'
|
|
***** SIG11 CAUGHT [ENV: MBSE_ROOT + A x 4200] *****
|
|
***** SIG11 CAUGHT [ENV: MBSE_ROOT + A x 8400] *****
|
|
useradd: invalid shell `%n%n%n%n%n/bin/mbsebbs'
|
|
useradd: invalid shell `%%20n/bin/mbsebbs'
|
|
useradd: invalid shell `%n%p%s%d%x/bin/mbsebbs'
|
|
useradd: invalid shell `%.1024d/bin/mbsebbs'
|
|
useradd: invalid shell `%.2049d/bin/mbsebbs'
|
|
.....
|
|
useradd: invalid shell `a'id > /tmp/FZ'b/bin/mbsebbs'
|
|
useradd: invalid shell `a;id > /tmp/FZ;b/bin/mbsebbs'
|
|
useradd: invalid shell `a&&id > /tmp/FZ&&b/bin/mbsebbs'
|
|
fuzz@linux:~$
|
|
|
|
fuzz@linux:~$ cat mbsefuzz.log
|
|
[/opt/mbse/bin/mbuseradd]->SIG11 [ENV: MBSE_ROOT + A x 4200]
|
|
[/opt/mbse/bin/mbuseradd]->SIG11 [ENV: MBSE_ROOT + A x 8400]
|
|
fuzz@linux:~$
|
|
|
|
Looks like we did catch a bug or two. Lets also quickly check /tmp for OBB.
|
|
|
|
fuzz@linux:~$ ls /tmp/FZ*
|
|
ls: /tmp/FZ*: No such file or directory
|
|
fuzz@linux:~$
|
|
|
|
Nope, no out-of-bounds breakage here. Let us now further explore what we did find.
|
|
|
|
fuzz@linux:~$ cat mbsefuzz.log
|
|
[/opt/mbse/bin/mbuseradd]->SIG11 [ENV: MBSE_ROOT + A x 4200]
|
|
[/opt/mbse/bin/mbuseradd]->SIG11 [ENV: MBSE_ROOT + A x 8400] (same bug as previous)
|
|
fuzz@linux:~$
|
|
|
|
fuzz@linux:~$ export MBSE_ROOT=`perl -e 'print "A" x 4200'`
|
|
fuzz@linux:~$ /opt/mbse/bin/mbuseradd
|
|
|
|
mbuseradd commandline:
|
|
|
|
mbuseradd [gid] [name] [comment] [usersdir]
|
|
fuzz@linux:~$ /opt/mbse/bin/mbuseradd a b c d
|
|
Segmentation fault
|
|
fuzz@linux:~$
|
|
|
|
fuzz@linux:~$ su
|
|
Password:
|
|
linux:/home/fuzz# gdb /opt/mbse/bin/mbuseradd
|
|
GNU gdb 6.3
|
|
Copyright 2004 Free Software Foundation, Inc.
|
|
GDB is free software, covered by the GNU General Public License, and you are
|
|
welcome to change it and/or distribute copies of it under certain conditions.
|
|
Type "show copying" to see the conditions.
|
|
There is absolutely no warranty for GDB. Type "show warranty" for details.
|
|
This GDB was configured as "i386-linux"...(no debugging symbols found)
|
|
Using host libthread_db library "/lib/libthread_db.so.1".
|
|
|
|
(gdb) r a b c d
|
|
Starting program: /opt/mbse/bin/mbuseradd a b c d
|
|
(no debugging symbols found)
|
|
(no debugging symbols found)
|
|
(no debugging symbols found)
|
|
(no debugging symbols found)
|
|
[Thread debugging using libthread_db enabled]
|
|
[New Thread 16384 (LWP 11571)]
|
|
(no debugging symbols found)
|
|
(no debugging symbols found)
|
|
|
|
Program received signal SIGSEGV, Segmentation fault.
|
|
[Switching to Thread 16384 (LWP 11571)]
|
|
0x41414141 in ?? ()
|
|
(gdb) i r
|
|
eax 0x0 0
|
|
ecx 0xbfffd994 -1073751660
|
|
edx 0x0 0
|
|
ebx 0x41414141 1094795585
|
|
esp 0xbfffe9d0 0xbfffe9d0
|
|
ebp 0x41414141 0x41414141
|
|
esi 0x41414141 1094795585
|
|
edi 0x41414141 1094795585
|
|
eip 0x41414141 0x41414141
|
|
eflags 0x10246 66118
|
|
cs 0x23 35
|
|
ss 0x2b 43
|
|
ds 0x2b 43
|
|
es 0x2b 43
|
|
fs 0x0 0
|
|
gs 0x0 0
|
|
(gdb) bt
|
|
#0 0x41414141 in ?? ()
|
|
#1 0x41414141 in ?? ()
|
|
#2 0x41414141 in ?? ()
|
|
#3 0x41414141 in ?? ()
|
|
#4 0x64414141 in ?? ()
|
|
#5 0x6220622f in ?? ()
|
|
#6 0xbfffeb00 in ?? ()
|
|
#7 0x40016ed8 in _r_debug ()
|
|
#8 0xbfffeac4 in ?? ()
|
|
#9 0xbfffea24 in ?? ()
|
|
#10 0x400c630c in ?? () from /lib/libc.so.6
|
|
#11 0x40069270 in ?? ()
|
|
#12 0x40073f7e in __pthread_alt_unlock () from /lib/libpthread.so.0
|
|
Previous frame inner to this frame (corrupt stack?)
|
|
(gdb) q
|
|
The program is running. Exit anyway? (y or n) y
|
|
linux:/home/fuzz# exit
|
|
exit
|
|
fuzz@linux:~$
|
|
|
|
The instruction pointer (EIP) is overwritten along with many other registers with our fuzzing data.
|
|
|
|
VULNERABLE CODE:
|
|
|
|
[mbsebbs-0.70.0/unix/mbuseradd.c]
|
|
|
|
shell = calloc(PATH_MAX, sizeof(char));
|
|
|
|
.....
|
|
|
|
sprintf(shell, "%s/bin/mbsebbs", getenv("MBSE_ROOT"));
|
|
|
|
[mbsebbs-0.70.0/unix/mbuseradd.c]
|
|
|
|
Conclusion: Our target is suid root and contains an exploitable stack-based buffer overflow.
|
|
|
|
Our fuzzer was able to detect it for us :)
|
|
|
|
GNU/Linux MBSE-BBS 0.70.0 & Below Stack Overflow Exploit
|
|
http://www.milw0rm.com/exploits/3154
|
|
|
|
============================================================================================================================
|
|
|
|
3. Remote Fuzzing
|
|
|
|
Remote fuzzing deals with fuzzing a target remotely or a the network. This can include, but isn't limited to:
|
|
|
|
Network Protocol Fuzzing - Fuzzing applications or even a kernel that implements a specific protocol
|
|
Database Fuzzing - Fuzzing database modules and/or database input sanitation policies
|
|
Web Application Fuzzing - Fuzzing input vectors of web applications hosted on a web server
|
|
|
|
============================================================================================================================
|
|
|
|
3.1 Information Gathering
|
|
|
|
For this example of remote fuzzing, we will be exploring GoodTech SSH Server (http://www.goodtechsys.com/sshdnt2000.asp)
|
|
which was vulnerable to a remote buffer overflow vulnerability in its SFTP server part. We need to figure out the protocol
|
|
standards and get information on how to communicate with the SSH/SFTP server in order to fuzz it.
|
|
|
|
PERL extensions that can be installed through CPAN can be extremely helpful in writing an efficient fuzzer. There is actually
|
|
a PERL extension that will allow us to communicate through SSH2 with SFTP servers making fuzzing a breeze, it is called
|
|
Net::SSH2::SFTP (http://search.cpan.org/~dbrobins/Net-SSH2-0.18/lib/Net/SSH2/SFTP.pm). You will need to install libssh2
|
|
(http://www.libssh2.org/wiki/index.php/Main_Page) first in order for Net::SSH2 to install correctly. After that, you can
|
|
install Net::SSH2 by running "cpan" from your shell (as root, usually) and doing a "install Net::SSH2". After you have
|
|
installed the library and extension, we can use it for our perl-based SFTP fuzzer and it allows us to work with the SSH2
|
|
protocol fairly easily.
|
|
|
|
By looking at the documentation for Net::SSH2, it will allow us to fuzz the following parameters (for SFTP):
|
|
|
|
open -> Open or create a file
|
|
opendir -> Open a directory
|
|
unlink -> Delete a file
|
|
rename -> Rename a file or directory
|
|
mkdir -> Create a directory
|
|
rmdir -> Delete a directory
|
|
stat -> Get file attributes
|
|
setstat -> Set file attributes
|
|
symlink -> Create a symbolic link
|
|
readlink -> Return the target of a link
|
|
realpath -> Resolve a file's path
|
|
|
|
These functions are called by each method provided, and we will fuzz their parameters (being our input), on the SFTP server.
|
|
|
|
============================================================================================================================
|
|
|
|
3.2 Writing the Fuzzer
|
|
|
|
This example for SFTP fuzzing will be written in PERL and will be using libssh2/Net::SSH2 (this is not the only way to use
|
|
and fuzz SFTP, other libaries and extensions that may be more extensive and/or low-level are available).
|
|
|
|
[sftpfuzz.pl]
|
|
|
|
#!/usr/bin/perl
|
|
|
|
use Net::SSH2;
|
|
|
|
@fzorc = ("A" x 550, "A" x 1100, "A" x 2100, "A" x 4200, "A" x 8400, # overflow
|
|
"\%n\%n\%n\%n\%n", "\%\%20n", "\%n\%p\%s\%d\%x", "%.1024d", "%.2049d", # format string
|
|
"-1", "32767", "65535", "-2147483647", "0xffffffff", # numbers
|
|
"a|id > /tmp/FZ|b", "a`id > /tmp/FZ`b", "a'id > /tmp/FZ'b", # out-of-bounds breakage
|
|
"a;id > /tmp/FZ;b", "a&&id > /tmp/FZ&&b");
|
|
|
|
@fzdesc = ("A x 550", "A x 1100", "A x 2100", "A x 4200", "A x 8400",
|
|
"\%n\%n\%n\%n\%n", "\%\%20n", "\%n\%p\%s\%d\%x", "%.1024d", "%.2049d",
|
|
"-1", "32767", "65535", "-2147483647", "0xffffffff",
|
|
"a|id > /tmp/FZ|b", "a`id > /tmp/FZ`b", "a'id > /tmp/FZ'b",
|
|
"a;id > /tmp/FZ;b", "a&&id > /tmp/FZ&&b");
|
|
|
|
@funcs1 = ("open", "opendir", "unlink", "mkdir", "rmdir", "stat", "setstat", "readlink", "realpath"); # 1 arg
|
|
@funcs2 = ("rename", "symlink"); # 2 args
|
|
|
|
$server = "1.2.3.4";
|
|
$user = "sftp";
|
|
$pass = "fuzz";
|
|
$logfile = "sftpfuzz.log";
|
|
|
|
$| = 1;
|
|
|
|
$ssh2 = Net::SSH2->new();
|
|
$ssh2->connect($server);
|
|
$ssh2->disconnect();
|
|
|
|
$i = 0;
|
|
for($z = 0; $z < 9; $z++)
|
|
{
|
|
|
|
foreach(@fzorc)
|
|
{
|
|
|
|
$func = $funcs1[$z];
|
|
$arg = 1;
|
|
$fuzz = $_;
|
|
|
|
sftpfuzz($func, $fuzz, $arg, $i);
|
|
|
|
if($i == 19) { $i = -1; }
|
|
$i++;
|
|
|
|
}
|
|
}
|
|
|
|
$i = 0;
|
|
for($z = 0; $z < 2; $z++)
|
|
{
|
|
|
|
foreach(@fzorc)
|
|
{
|
|
|
|
$func = $funcs2[$z];
|
|
$arg = 2;
|
|
$fuzz = $_;
|
|
|
|
sftpfuzz($func, $fuzz, $arg, $i);
|
|
|
|
if($i == 19) { $i = -1; }
|
|
$i++;
|
|
|
|
}
|
|
}
|
|
|
|
sub sftpfuzz
|
|
{
|
|
|
|
$func = $_[0];
|
|
$fuzz = $_[1];
|
|
$arg = $_[2];
|
|
$i = $_[3];
|
|
|
|
$desc = $fzdesc[$i];
|
|
|
|
$ssh2 = Net::SSH2->new();
|
|
$ssh2->connect($server) or logit($func, $i);
|
|
|
|
print "sftpfuzz fuzzing [sftp + $func + $desc]\n";
|
|
|
|
if($ssh2->auth_password($user, $pass))
|
|
{
|
|
|
|
$sftp = $ssh2->sftp();
|
|
|
|
if($arg == 1)
|
|
{
|
|
|
|
$fuzr = $sftp->$func($fuzz);
|
|
|
|
}
|
|
|
|
if($arg == 2)
|
|
{
|
|
|
|
$fuzr = $sftp->$func($fuzz, $fuzz);
|
|
|
|
}
|
|
}
|
|
|
|
else { die "ERROR: auth_password($user/$pass)\n"; }
|
|
|
|
$ssh2->disconnect();
|
|
|
|
}
|
|
|
|
sub logit
|
|
{
|
|
|
|
$fuzz = $_[0];
|
|
$i = $_[1];
|
|
|
|
$desc = $fzdesc[$i-1];
|
|
|
|
open(FD, ">>$logfile");
|
|
print FD $server . " -> [sftp + $func + $desc]\n";
|
|
close(FD);
|
|
|
|
die "$server down -> check $logfile\n";
|
|
|
|
}
|
|
|
|
[sftpfuzz.pl]
|
|
|
|
Now we have a simple, remote SFTP fuzzer that can somewhat reliably tell us at least if we find any faults in the server.
|
|
|
|
============================================================================================================================
|
|
|
|
3.3 Fuzzing the Target
|
|
|
|
Work time is over-- play time is upon us. Lets run the fuzzer against our target.
|
|
|
|
fuzz@linux:~$ perl sftpfuzz.pl
|
|
sftpfuzz fuzzing [sftp + open + A x 550]
|
|
1.2.3.4 down -> check sftpfuzz.log
|
|
fuzz@linux:~$
|
|
|
|
Looks like we've got something...
|
|
|
|
fuzz@linux:~$ cat sftpfuzz.log
|
|
1.2.3.4 -> [sftp + open + A x 550]
|
|
fuzz@linux:~$
|
|
|
|
The server went down right after we hit "open" with a 550 byte request. Lets now check out the target process on our machine.
|
|
|
|
EAX 00000001
|
|
ECX 41414141
|
|
EDX 00890608
|
|
EBX 00000000
|
|
ESP 01448968 ASCII "AAAAA....."
|
|
EBP 41414141
|
|
ESI 0000014F
|
|
EDI 0144E7E0
|
|
EIP 41414141
|
|
|
|
The instruction pointer (EIP) and other registers are overwritten with our fuzzing data.
|
|
|
|
Conclusion: Our target contains a remotely exploitable stack-based buffer overflow.
|
|
|
|
Source code auditing wasn't available here because our target seems to be closed source. Once again, our fuzzer was able
|
|
to detect the vulnerability for us :)
|
|
|
|
GoodTech SSH Remote Buffer Overflow Exploit
|
|
http://www.milw0rm.com/exploits/6804
|
|
|
|
============================================================================================================================
|
|
|
|
4. Conclusion
|
|
|
|
Fuzzing is a developing art. As we progress in computer security, fuzzing will grow stronger as well. Nonpublished code
|
|
will sit on the most remote boxes, possibly thanking fuzzing for leading the way in its R&D. One might guess millions
|
|
will be made from the marketing of fuzzing technologies. Many things will come from the vulnerabilities they discover.
|
|
|
|
Fuzzers are code-- code programmed by human beings. They can be as perfect and flawless as we are. The age of fuzzing has
|
|
made its debut some years ago, was silently studied, and reawoken to fuel vulnerability discovery like never before.
|
|
|
|
Enjoy the game, fuzz some code.
|
|
|
|
============================================================================================================================
|
|
|
|
4.1 Disclaimer
|
|
|
|
Krakow Labs assumes no liability for the use or misuse of any or all information contained in this document or information
|
|
available at or referring to this document. Any or all information contained in this document or available at or referring to
|
|
this document is not misleading and all information provided by Krakow Labs in this document is accurate to the best knowledge
|
|
of Krakow Labs. This document can be published and/or reproduced as long as the document's data is left unchanged. Krakow Labs
|
|
may be accessed via krakowlabs.com for more information, personal reference, or other agendas supporting Krakow Labs.
|
|
|
|
KL0209LIT_fffap.txt
|
|
02.11.2009
|
|
Krakow Labs Literature [www.krakowlabs.com]
|
|
Fuzzing for Fun and Profit
|
|
http://www.krakowlabs.com/res/lit/KL0209LIT_fffap.txt
|
|
rush@KL (Jeremy Brown) [rush@krakowlabs.com]
|
|
KL0209LIT_fffap.txt
|
|
|
|
# milw0rm.com [2009-02-11]</pre>
|
|
</html>
|