Changes between Version 5 and Version 6 of zzuf/tutorial


Ignore:
Timestamp:
05/18/2008 12:16:21 PM (16 years ago)
Author:
Sam Hocevar
Comment:

nuke zzuf/tutorial but keep history

Legend:

Unmodified
Added
Removed
Modified
  • zzuf/tutorial

    v5 v6  
    1 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.
    2 
    3 Warning: this tutorial requires `zzuf` version 0.11 or later.
    4 
    5 = 1. Basic `zzuf` usage =
    6 
    7 `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.
    8 
    9 == 1.1. Launching `zzuf` ==
    10 
    11 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.
    12 
    13 This is how to tell `hd` to read 32 bytes from `/dev/zero`:
    14 
    15 {{{
    16 % hd -vn 32 /dev/zero
    17 00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    18 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    19 00000020
    20 %
    21 }}}
    22 
    23 Now let’s fuzz `hd`’s input using `zzuf`. It’s completely straightforward: just prepend `zzuf` to the commandline.
    24 
    25 {{{
    26 % zzuf hd -vn 32 /dev/zero
    27 00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    28 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    29 00000020
    30 %
    31 }}}
    32 
    33 We see that two `00` values have been changed to `02`s. `zzuf` '''intercepted''' `hd`'s opening of `/dev/zero` and automatically '''corrupted''' the bits it read at random. Let’s do it again:
    34 
    35 {{{
    36 % zzuf hd -vn 32 /dev/zero
    37 00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    38 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    39 00000020
    40 %
    41 }}}
    42 
    43 We get exactly the same output. This is a very important property of `zzuf`: its behaviour is '''reproducible'''.
    44 
    45 == 1.2. Invoking different programs ==
    46 
    47 Let’s fuzz the `cat` utility instead of `hd`, but read the final output with `hd` nonetheless:
    48 
    49 {{{
    50 % zzuf cat /dev/zero | hd -vn 32
    51 00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    52 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    53 00000020
    54 %
    55 }}}
    56 
    57 Now instead of calling `hd`, let’s try `od`, the octal dumper:
    58 {{{
    59 % zzuf od -vN 32 /dev/zero
    60 0000000 000000 000002 000000 000000 000000 000000 000000 000000
    61 0000020 000000 000000 001000 000000 000000 000000 000000 000000
    62 0000040
    63 %
    64 }}}
    65 
    66 If you understand octal dumps as fluently as hexadecimal dumps, you noticed that the data has been fuzzed exactly like with `hd`.
    67 
    68 This is another very important property of `zzuf`: '''data is fuzzed the same way regardless of the fuzzed application'''.
    69 
    70 == 1.3. The fuzzing ratio ==
    71 
    72 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.
    73 
    74 Let’s try fuzzing more bits, for instance 5% of the bits, using '''`-r` 0.05''':
    75 
    76 {{{
    77 % zzuf -r 0.05 hd -vn 32 /dev/zero
    78 00000000  00 01 00 00 00 00 44 00  04 80 00 40 21 00 0a 20  |......D....@!.. |
    79 00000010  40 20 00 04 00 00 02 00  00 00 00 00 00 00 00 00  |@ ..............|
    80 00000020
    81 %
    82 }}}
    83 
    84 We see that 15 bits have been changed. 5% of 256 bits is 12.8, so here again the behaviour is as expected.
    85 
    86 Now let’s fuzz fewer bits, for instance 0.1%, using '''`-r` 0.001''':
    87 
    88 {{{
    89 % zzuf -r 0.001 hd -vn 32 /dev/zero
    90 00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    91 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    92 00000020
    93 %
    94 }}}
    95 
    96 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.
    97 
    98 Very high fuzzing ratios can be specified, for instance 50%, using '''`-r` 0.5''':
    99 
    100 {{{
    101 % zzuf -r 0.5 hd -vn 32 /dev/zero 
    102 00000000  c0 a0 20 b0 ad 40 07 c2  8a 14 30 1b 83 21 1a 69  |.. ..@....0..!.i|
    103 00000010  11 28 05 07 30 00 70 01  43 08 62 c8 6d 45 e4 1a  |.(..0.p.C.b.mE..|
    104 00000020
    105 %
    106 }}}
    107 
    108 == 1.4. The random seed ==
    109 
    110 `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:
    111 
    112 {{{
    113 % zzuf -s 2 hd -vn 32 /dev/zero
    114 00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    115 00000010  00 00 00 00 80 00 00 00  00 00 00 00 00 00 00 00  |................|
    116 00000020
    117 % zzuf -s 79432 hd -vn 32 /dev/zero 
    118 00000000  00 00 00 00 00 00 00 20  00 00 00 00 00 00 00 00  |....... ........|
    119 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    120 00000020
    121 %
    122 }}}
    123 
    124 As can be seen, each seed value initiates a different behaviour of the random number generator.
    125 
    126 == 1.5. Creating fuzzed files ==
    127 
    128 It is possible to fuzz files directly, without calling applications at all.
    129 
    130 To do so, simply call `zzuf` with no application argument. It will fuzz its standard input by default:
    131 
    132 {{{
    133 % cat /dev/zero | zzuf | hd -vn32         
    134 00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    135 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    136 00000020
    137 %
    138 }}}
    139 
    140 `zzuf` can be used to create files. Again, the behaviour is entirely reproducible:
    141 
    142 {{{
    143 % dd if=/dev/zero bs=1 count=32 | zzuf > output.file
    144 32+0 records in
    145 32+0 records out
    146 32 bytes (32 B) copied, 9.1129e-05 s, 351 kB/s
    147 % hd -v output.file
    148 00000000  00 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    149 00000010  00 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |................|
    150 00000020
    151 %
    152 }}}
    153 
    154 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.
    155 
    156 = 2. `zzuf` as a batch testing tool =
    157 
    158 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.
    159 
    160 == 2.1. Debug mode ==
    161 
    162 Consider this invocation of `zzuf` with the `file` utility:
    163 
    164 {{{
    165 % zzuf file /bin/ls
    166 /etc/magic, 4: Warning: using regular magic file `/usr/share/file/magic'
    167 /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'
    168 /usr/share/file/magic, 47: Warning: type `stri?g        \x02\x01\x13\x13\x13\x01\x0d\x10        Digital Symphony sound sample (RISC OS),' invalid
    169 [...]
    170 }}}
    171 
    172 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.
    173 
    174 We may run `zzuf` in '''debug mode''' to learn more about what happens, using the '''`-d` flag''':
    175 
    176 {{{
    177 % zzuf -d file /bin/ls
    178 ** zzuf debug ** libzzuf initialised for PID 29526
    179 ** zzuf debug ** fopen("/etc/magic", "r") = [3]
    180 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    181 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    182 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    183 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = NULL
    184 ** zzuf debug ** fclose([3]) = 0
    185 ** zzuf debug ** open("/usr/share/file/magic.mgc", 0) = 3
    186 ** zzuf debug ** mmap(NULL, 1636608, 3, 2, 3, 0) = 0x2acce776e000 "\x1c\x04\x1c\xf1...
    187 ** zzuf debug ** close(3) = 0
    188 ** zzuf debug ** fopen("/usr/share/file/magic", "r") = [3]
    189 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    190 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    191 ** zzuf debug ** fgets(0x7fffc46e04b0, 8192, [3]) = 0x7fffc46e04b0
    192 [...]
    193 }}}
    194 
    195 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.
    196 
    197 == 2.2. Include and exclude patterns ==
    198 
    199 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:
    200 
    201 {{{
    202 % zzuf -d -E /etc/ -E /usr/share/ file /bin/ls
    203 ** zzuf debug ** libzzuf initialised for PID 30541
    204 ** zzuf debug ** open("/bin/ls", 0) = 3
    205 ** zzuf debug ** read(3, 0x60a590, 98304) = 98304 "\x7fENF...
    206 ** zzuf debug ** close(3) = 0
    207 /bin/ls: data
    208 %
    209 }}}
    210 
    211 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:
    212 
    213 {{{
    214 % zzuf -d -I /bin/ file /bin/ls
    215 ** zzuf debug ** libzzuf initialised for PID 30550
    216 ** zzuf debug ** open("/bin/ls", 0) = 3
    217 ** zzuf debug ** read(3, 0x606c20, 98304) = 98304 "\x7fENF...
    218 ** zzuf debug ** close(3) = 0
    219 /bin/ls: data
    220 %
    221 }}}
    222 
    223 Yet another way is to tell `zzuf` to only fuzz files that appear on the fuzzed application’s commandline, using the '''`-c` flag''':
    224 
    225 {{{
    226 % zzuf -d -c file /bin/ls
    227 ** zzuf debug ** libzzuf initialised for PID 30555
    228 ** zzuf debug ** open("/bin/ls", 0) = 3
    229 ** zzuf debug ** read(3, 0x608de0, 98304) = 98304 "\x7fENF...
    230 ** zzuf debug ** close(3) = 0
    231 /bin/ls: data
    232 %
    233 }}}
    234 
    235 We can now properly fuzz the `file` application.
    236 
    237 == 2.3. Seed ranges ==
    238 
    239 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:
    240 
    241 {{{
    242 % zzuf -c -s 0:5 file /bin/ls         
    243 /bin/ls: data
    244 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
    245 /bin/ls: ELF 64-bit LSB executable, x86-64, (SYSV), statically linked (uses shared libs), stripped
    246 /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
    247 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
    248 %
    249 }}}
    250 
    251 As can be seen, the file analysed by `file` is slightly corrupted in a different way each time.
    252 
    253 Using the '''`-v` flag''' for more verbosity helps understanding what is going on, especially with large seed ranges:
    254 
    255 {{{
    256 % zzuf -vc -s 0:5 file /bin/ls
    257 zzuf[s=0,r=0.004]: launched `file'
    258 /bin/ls: data
    259 zzuf[s=1,r=0.004]: launched `file'
    260 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
    261 zzuf[s=2,r=0.004]: launched `file'
    262 /bin/ls: ELF 64-bit LSB executable, x86-64, (SYSV), statically linked (uses shared libs), stripped
    263 zzuf[s=3,r=0.004]: launched `file'
    264 /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
    265 zzuf[s=4,r=0.004]: launched `file'
    266 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
    267 %
    268 }}}
    269 
    270 == 2.4. Ratio ranges ==
    271 
    272 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:
    273 
    274 {{{
    275 % zzuf -vc -s 0:5 -r 0.0001:0.01 file /bin/ls
    276 zzuf[s=0,r=0.0001:0.01]: launched `file'
    277 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), stripped
    278 zzuf[s=1,r=0.0001:0.01]: launched `file'
    279 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked (uses shared libs), stripped
    280 zzuf[s=2,r=0.0001:0.01]: launched `file'
    281 /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
    282 zzuf[s=3,r=0.0001:0.01]: launched `file'
    283 /bin/ls: ERROR: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linkedCannot allocate memory for note (Cannot allocate memory)
    284 zzuf[s=4,r=0.0001:0.01]: launched `file'
    285 /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
    286 %
    287 }}}
    288 
    289 To generate a file that reproduces a given behaviour, the corresponding `-s` flag and the exact same `-r` flag need to be used:
    290 
    291 {{{
    292 % zzuf -s 4 -r 0.0001:0.01 < /bin/ls > output.file
    293 % file output.file
    294 output.file: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
    295 %
    296 }}}