Version 4 (modified by Sam Hocevar, 16 years ago) (diff)

seed ranges, ratio ranges

This tutorial is a hands-on guide to the most important zzuf features. It starts with the working principles but goes on with very advanced uses of the tool.

Warning: this tutorial requires zzuf version 0.11 or later.

1. Basic zzuf usage

zzuf’s behaviour is configured through the command line. A comprehensive list of flags and their meaning is given in the zzuf manual page. Just run man zzuf on your system to see it.

1.1. Launching zzuf

Let’s start with a simple command that reads data from a file. We choose hd, the hexadecimal dump command, so that we get a chance to observe what exactly happens to the data.

This is how to tell hd to read 32 bytes from /dev/zero:

% hd -vn 32 /dev/zero
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

Now let’s fuzz hd’s input using zzuf. It’s completely straightforward: just prepend zzuf to the commandline.

% zzuf hd -vn 32 /dev/zero
00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

We see that two 00 values have been changed to 02s. zzuf intercepted hd's opening of /dev/zero and automatically corrupted the bits it read at random. Let’s do it again:

% zzuf hd -vn 32 /dev/zero
00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

We get exactly the same output. This is a very important property of zzuf: its behaviour is reproducible.

1.2. Invoking different programs

Let’s fuzz the cat utility instead of hd, but read the final output with hd nonetheless:

% zzuf cat /dev/zero | hd -vn 32
00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

Now instead of calling hd, let’s try od, the octal dumper:

% zzuf od -vN 32 /dev/zero
0000000 000000 000002 000000 000000 000000 000000 000000 000000
0000020 000000 000000 001000 000000 000000 000000 000000 000000
0000040
%

If you understand octal dumps as fluently as hexadecimal dumps, you noticed that the data has been fuzzed exactly like with hd.

This is another very important property of zzuf: data is fuzzed the same way regardless of the fuzzed application.

1.3. The fuzzing ratio

The fuzzing ratio is the proportion of bits that zzuf changes. It is specified with the -r flag. The default fuzzing ratio is 0.004, meaning "fuzz 0.4% of the bits". 32 bytes is 256 bits, and 0.4% of 256 bits is approximately 1. zzuf should have fuzzed 1 bit, but since it fuzzes bits at random, 2 bits is not surprising.

Let’s try fuzzing more bits, for instance 5% of the bits, using -r 0.05:

% zzuf -r 0.05 hd -vn 32 /dev/zero
00000000  00 01 00 00 00 00 44 00  04 80 00 40 21 00 0a 20  |......D....@!.. |
00000010  40 20 00 04 00 00 02 00  00 00 00 00 00 00 00 00  |@ ..............|
00000020
%

We see that 15 bits have been changed. 5% of 256 bits is 12.8, so here again the behaviour is as expected.

Now let’s fuzz fewer bits, for instance 0.1%, using -r 0.001:

% zzuf -r 0.001 hd -vn 32 /dev/zero
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

No bits have been changed, because 0.1% of 256 is 0.256, so there were few chances that the bits would be changed at all.

Very high fuzzing ratios can be specified, for instance 50%, using -r 0.5:

% zzuf -r 0.5 hd -vn 32 /dev/zero  
00000000  c0 a0 20 b0 ad 40 07 c2  8a 14 30 1b 83 21 1a 69  |.. ..@....0..!.i|
00000010  11 28 05 07 30 00 70 01  43 08 62 c8 6d 45 e4 1a  |.(..0.p.C.b.mE..|
00000020
%

1.4. The random seed

zzuf’s behaviour is reproducible, but we might not be satisfied with the output. Or we may simply want to fuzz in several different ways, but still using the same fuzzing ratio. This is done by changing the random seed with the -s flag. The random seed is the initial value of zzuf’s random number generator. The default seed is 0, so let’s try with other values:

% zzuf -s 2 hd -vn 32 /dev/zero
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 80 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020
% zzuf -s 79432 hd -vn 32 /dev/zero  
00000000  00 00 00 00 00 00 00 20  00 00 00 00 00 00 00 00  |....... ........|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

As can be seen, each seed value initiates a different behaviour of the random number generator.

1.5. Creating fuzzed files

It is possible to fuzz files directly, without calling applications at all.

To do so, simply call zzuf with no application argument. It will fuzz its standard input by default:

% cat /dev/zero | zzuf | hd -vn32          
00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

zzuf can be used to create files. Again, the behaviour is entirely reproducible:

% dd if=/dev/zero bs=1 count=32 | zzuf > output.file
32+0 records in
32+0 records out
32 bytes (32 B) copied, 9.1129e-05 s, 351 kB/s
% hd -v output.file
00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
00000020
%

This may be used if a given application is not supported by zzuf, but it is especially useful to generate files that reproduce zzuf’s behaviour without requiring zzuf at all.

2. zzuf as a batch testing tool

The most useful aspect of zzuf is its use as an automated tool, testing thousands of different fuzzing combinations and analysing the fuzzed application’s behaviour in each situation.

2.1. Debug mode

Consider this invocation of zzuf with the file utility:

% zzuf file /bin/ls
/etc/magic, 4: Warning: using regular magic file `/usr/share/file/magic'
/usr/share/file/magic, 33: Warning: Printf format `d' is not valid for type `string' in description `RISC OS outline font data,>5	byte		x	varsion %d'
/usr/share/file/magic, 47: Warning: type `stri?g	\x02\x01\x13\x13\x13\x01\x0d\x10	Digital Symphony sound sample (RISC OS),' invalid
[...]

This is not the expected behaviour at all. What happens exactly? The problem is that file also opens its own configuration files to gather information about file formats, and of course zzuf fuzzes these files, since no one told it that they were special.

We may use the debug mode to learn more about what happens, using the -d flag:

% zzuf -d file /bin/ls
** zzuf debug ** libzzuf initialised for PID 29526
** zzuf debug ** fopen("/etc/magic", "r") = [3]
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = NULL
** zzuf debug ** fclose([3]) = 0
** zzuf debug ** open("/usr/share/file/magic.mgc", 0) = 3
** zzuf debug ** mmap(NULL, 1636608, 3, 2, 3, 0) = 0x2acce776e000 "\x1c\x04\x1c\xf1...
** zzuf debug ** close(3) = 0
** zzuf debug ** fopen("/usr/share/file/magic", "r") = [3]
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
[...]

We see that file opens at least /etc/magic, /usr/share/file/magic.mgc and /usr/share/file/magic. Since they are installed in trusted directories, it is useless to fuzz these files, unless of course we wish to test file’s robustness against corruption of these files.

2.2. Include and exclude patterns

One way to make zzuf ignore files is to exclude them, using the -E flag as many times as necessary. This flag specifies that files matching a given regular expression should not be fuzzed:

% zzuf -d -E /etc/ -E /usr/share/ file /bin/ls
** zzuf debug ** libzzuf initialised for PID 30541
** zzuf debug ** open("/bin/ls", 0) = 3
** zzuf debug ** read(3, 0x60a590, 98304) = 98304 "\x7fENF...
** zzuf debug ** close(3) = 0
/bin/ls: data
%

Another way to avoid the issue is to only include the files or directories we want to fuzz, using the -I flag as many times as necessary:

% zzuf -d -I /bin/ file /bin/ls
** zzuf debug ** libzzuf initialised for PID 30550
** zzuf debug ** open("/bin/ls", 0) = 3
** zzuf debug ** read(3, 0x606c20, 98304) = 98304 "\x7fENF...
** zzuf debug ** close(3) = 0
/bin/ls: data
%

Yet another way is to tell zzuf to only fuzz files that appear on the fuzzed application’s commandline, using the -c flag:

% zzuf -d -c file /bin/ls
** zzuf debug ** libzzuf initialised for PID 30555
** zzuf debug ** open("/bin/ls", 0) = 3
** zzuf debug ** read(3, 0x608de0, 98304) = 98304 "\x7fENF...
** zzuf debug ** close(3) = 0
/bin/ls: data
%

We can now properly fuzz the file application.

2.3. Seed ranges

Instead of specifying a random seed with the -s flag, one can specify a whole range by separating values with a colon. zzuf will simply run the program several times, each time with another seed in the range:

% zzuf -c -s 0:5 file /bin/ls         
/bin/ls: data
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
/bin/ls: ELF 64-bit LSB executable, x86-64, (SYSV), statically linked (uses shared libs), stripped
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8388616, statically linked (uses shared libs), corrupted section header size
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
%

As can be seen, the file analysed by file is slightly corrupted in a different way each time.

Using the -v flag for more verbosity helps understanding what is going on, especially with large seed ranges:

% zzuf -vc -s 0:5 file /bin/ls
zzuf[s=0,r=0.004]: launched file
/bin/ls: data
zzuf[s=1,r=0.004]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
zzuf[s=2,r=0.004]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, (SYSV), statically linked (uses shared libs), stripped
zzuf[s=3,r=0.004]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8388616, statically linked (uses shared libs), corrupted section header size
zzuf[s=4,r=0.004]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
%

2.4. Ratio ranges

When a seed range is being used with -s, a ratio range can be used with -r. Instead of using the same bit fuzzing ratio for each seed, zzuf will pick one at random within the specified interval:

% zzuf -vc -s 0:5 -r 0.0001:0.01 file /bin/ls
zzuf[s=0,r=0.0001:0.01]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), stripped
zzuf[s=1,r=0.0001:0.01]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
zzuf[s=2,r=0.0001:0.01]: launched file
/bin/ls: ERROR: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs)error reading
zzuf[s=3,r=0.0001:0.01]: launched file
/bin/ls: ERROR: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linkedCannot allocate memory for note (Cannot allocate memory)
zzuf[s=4,r=0.0001:0.01]: launched file
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
%