Skip to content

Commit 57637ba

Browse files
committed
removed overlooked post_lib references, added post_lib examples to examples/custom_mutators
1 parent d536ddc commit 57637ba

File tree

10 files changed

+339
-13
lines changed

10 files changed

+339
-13
lines changed

docs/Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ sending a mail to <[email protected]>.
1414
- -S slaves now only sync from the master to increase performance,
1515
the -M master stilly syncs from everyone. Added checks that exactly
1616
one master is present
17+
- added former post_library examples to examples/custom_mutators/
1718

1819

1920
### Version ++2.65c (release):

docs/QuickStartGuide.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ how to hit the ground running:
1010
If testing a network service, modify it to run in the foreground and read
1111
from stdin. When fuzzing a format that uses checksums, comment out the
1212
checksum verification code, too.
13-
If this is not possible (e.g. in -Q(emu) mode) then use AFL_POST_LIBRARY
14-
to calculate the values with your own library.
13+
14+
If this is not possible (e.g. in -Q(emu) mode) then use
15+
AFL_CUSTOM_MUTATOR_LIBRARY to calculate the values with your own library.
1516

1617
The program must crash properly when a fault is encountered. Watch out for
1718
custom SIGSEGV or SIGABRT handlers and background processes. For tips on

docs/life_pro_tips.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ You can find a simple solution in examples/argv_fuzzing.
8282

8383
## Attacking a format that uses checksums?
8484

85-
Remove the checksum-checking code or
86-
use a postprocessor! See examples/post_library/ for more.
85+
Remove the checksum-checking code or use a postprocessor!
86+
See examples/custom_mutators/ for more.
8787

8888
## Dealing with a very slow target or hoping for instant results?
8989

examples/README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22

33
Here's a quick overview of the stuff you can find in this directory:
44

5-
- custom_mutators - example custom mutators in python an c
5+
- afl_network_proxy - fuzz a target over the network: afl-fuzz on
6+
a host, target on an embedded system.
7+
8+
- afl_proxy - skeleton file example to show how to fuzz
9+
something where you gather coverage data via
10+
different means, e.g. hw debugger
11+
12+
- afl_untracer - fuzz binary-only libraries much faster but with
13+
less coverage than qemu_mode
614

715
- argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed
816
(e.g., to test setuid programs).
@@ -23,6 +31,9 @@ Here's a quick overview of the stuff you can find in this directory:
2331
- crash_triage - a very rudimentary example of how to annotate crashes
2432
with additional gdb metadata.
2533

34+
- custom_mutators - examples for the afl++ custom mutator interface in
35+
C and Python
36+
2637
- distributed_fuzzing - a sample script for synchronizing fuzzer instances
2738
across multiple machines (see parallel_fuzzing.md).
2839

@@ -31,8 +42,6 @@ Here's a quick overview of the stuff you can find in this directory:
3142
- persistent_demo - an example of how to use the LLVM persistent process
3243
mode to speed up certain fuzzing jobs.
3344

34-
- post_library - an example of how to build postprocessors for AFL.
35-
3645
- socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
3746
for fuzzing access with afl++
3847

examples/custom_mutators/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ example.c - this is a simple example written in C and should be compiled to a
1515
example.py - this is the template you can use, the functions are there but they
1616
are empty
1717

18+
post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF
19+
20+
post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG
21+
1822
simple-chunk-replace.py - this is a simple example where chunks are replaced
1923

2024
common.py - this can be used for common functions and helpers.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
american fuzzy lop++ - postprocessor library example
3+
--------------------------------------------------
4+
5+
Originally written by Michal Zalewski
6+
Edited by Dominik Maier, 2020
7+
8+
Copyright 2015 Google Inc. All rights reserved.
9+
10+
Licensed under the Apache License, Version 2.0 (the "License");
11+
you may not use this file except in compliance with the License.
12+
You may obtain a copy of the License at:
13+
14+
http://www.apache.org/licenses/LICENSE-2.0
15+
16+
Postprocessor libraries can be passed to afl-fuzz to perform final cleanup
17+
of any mutated test cases - for example, to fix up checksums in PNG files.
18+
19+
Please heed the following warnings:
20+
21+
1) In almost all cases, it is more productive to comment out checksum logic
22+
in the targeted binary (as shown in ../libpng_no_checksum/). One possible
23+
exception is the process of fuzzing binary-only software in QEMU mode.
24+
25+
2) The use of postprocessors for anything other than checksums is
26+
questionable and may cause more harm than good. AFL is normally pretty good
27+
about dealing with length fields, magic values, etc.
28+
29+
3) Postprocessors that do anything non-trivial must be extremely robust to
30+
gracefully handle malformed data and other error conditions - otherwise,
31+
they will crash and take afl-fuzz down with them. Be wary of reading past
32+
*len and of integer overflows when calculating file offsets.
33+
34+
In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really,
35+
honestly know what you're doing =)
36+
37+
With that out of the way: the postprocessor library is passed to afl-fuzz
38+
via AFL_POST_LIBRARY. The library must be compiled with:
39+
40+
gcc -shared -Wall -O3 post_library.so.c -o post_library.so
41+
42+
AFL will call the afl_custom_post_process() function for every mutated output
43+
buffer. From there, you have three choices:
44+
45+
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
46+
and return the original `len`.
47+
48+
2) If you want to skip this test case altogether and have AFL generate a
49+
new one, return 0 or set `*out_buf = NULL`.
50+
Use this sparingly - it's faster than running the target program
51+
with patently useless inputs, but still wastes CPU time.
52+
53+
3) If you want to modify the test case, allocate an appropriately-sized
54+
buffer, move the data into that buffer, make the necessary changes, and
55+
then return the new pointer as out_buf. Return an appropriate len
56+
afterwards.
57+
58+
Note that the buffer will *not* be freed for you. To avoid memory leaks,
59+
you need to free it or reuse it on subsequent calls (as shown below).
60+
61+
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
62+
63+
Aight. The example below shows a simple postprocessor that tries to make
64+
sure that all input files start with "GIF89a".
65+
66+
PS. If you don't like C, you can try out the unix-based wrapper from
67+
Ben Nagy instead: https://github.com/bnagy/aflfix
68+
69+
*/
70+
71+
#include <stdio.h>
72+
#include <stdlib.h>
73+
#include <string.h>
74+
75+
/* Header that must be present at the beginning of every test case: */
76+
77+
#define HEADER "GIF89a"
78+
79+
typedef struct post_state {
80+
81+
unsigned char *buf;
82+
size_t size;
83+
84+
} post_state_t;
85+
86+
void *afl afl_custom_init(void *afl) {
87+
88+
post_state_t *state = malloc(sizeof(post_state_t));
89+
if (!state) {
90+
91+
perror("malloc");
92+
return NULL;
93+
94+
}
95+
96+
state->buf = calloc(sizeof(unsigned char), 4096);
97+
if (!state->buf) { return NULL; }
98+
99+
return state;
100+
101+
}
102+
103+
/* The actual postprocessor routine called by afl-fuzz: */
104+
105+
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
106+
unsigned int len, unsigned char **out_buf) {
107+
108+
/* Skip execution altogether for buffers shorter than 6 bytes (just to
109+
show how it's done). We can trust len to be sane. */
110+
111+
if (len < strlen(HEADER)) return 0;
112+
113+
/* Do nothing for buffers that already start with the expected header. */
114+
115+
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
116+
117+
*out_buf = in_buf;
118+
return len;
119+
120+
}
121+
122+
/* Allocate memory for new buffer, reusing previous allocation if
123+
possible. */
124+
125+
*out_buf = realloc(data->buf, len);
126+
127+
/* If we're out of memory, the most graceful thing to do is to return the
128+
original buffer and give up on modifying it. Let AFL handle OOM on its
129+
own later on. */
130+
131+
if (!*out_buf) {
132+
133+
*out_buf = in_buf;
134+
return len;
135+
136+
}
137+
138+
/* Copy the original data to the new location. */
139+
140+
memcpy(*out_buf, in_buf, len);
141+
142+
/* Insert the new header. */
143+
144+
memcpy(*out_buf, HEADER, strlen(HEADER));
145+
146+
/* Return the new len. It hasn't changed, so it's just len. */
147+
148+
return len;
149+
150+
}
151+
152+
/* Gets called afterwards */
153+
void afl_custom_deinit(post_state_t *data) {
154+
155+
free(data->buf);
156+
free(data);
157+
158+
}
159+
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
american fuzzy lop++ - postprocessor for PNG
3+
------------------------------------------
4+
5+
Originally written by Michal Zalewski
6+
7+
Copyright 2015 Google Inc. All rights reserved.
8+
Adapted to the new API, 2020 by Dominik Maier
9+
10+
Licensed under the Apache License, Version 2.0 (the "License");
11+
you may not use this file except in compliance with the License.
12+
You may obtain a copy of the License at:
13+
14+
http://www.apache.org/licenses/LICENSE-2.0
15+
16+
See post_library.so.c for a general discussion of how to implement
17+
postprocessors. This specific postprocessor attempts to fix up PNG
18+
checksums, providing a slightly more complicated example than found
19+
in post_library.so.c.
20+
21+
Compile with:
22+
23+
gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz
24+
25+
*/
26+
27+
#include <stdio.h>
28+
#include <stdlib.h>
29+
#include <stdint.h>
30+
#include <string.h>
31+
#include <zlib.h>
32+
33+
#include <arpa/inet.h>
34+
35+
/* A macro to round an integer up to 4 kB. */
36+
37+
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
38+
39+
typedef struct post_state {
40+
41+
unsigned char *buf;
42+
size_t size;
43+
44+
} post_state_t;
45+
46+
void *afl_custom_init(void *afl) {
47+
48+
post_state_t *state = malloc(sizeof(post_state_t));
49+
if (!state) {
50+
51+
perror("malloc");
52+
return NULL;
53+
54+
}
55+
56+
state->buf = calloc(sizeof(unsigned char), 4096);
57+
if (!state->buf) { return NULL; }
58+
59+
return state;
60+
61+
}
62+
63+
size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
64+
unsigned int len,
65+
const unsigned char **out_buf) {
66+
67+
unsigned char *new_buf = (unsigned char *)in_buf;
68+
unsigned int pos = 8;
69+
70+
/* Don't do anything if there's not enough room for the PNG header
71+
(8 bytes). */
72+
73+
if (len < 8) {
74+
75+
*out_buf = in_buf;
76+
return len;
77+
78+
}
79+
80+
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
81+
don't have that, we can bail out. */
82+
83+
while (pos + 12 <= len) {
84+
85+
unsigned int chunk_len, real_cksum, file_cksum;
86+
87+
/* Chunk length is the first big-endian dword in the chunk. */
88+
89+
chunk_len = ntohl(*(uint32_t *)(in_buf + pos));
90+
91+
/* Bail out if chunk size is too big or goes past EOF. */
92+
93+
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
94+
95+
/* Chunk checksum is calculated for chunk ID (dword) and the actual
96+
payload. */
97+
98+
real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4));
99+
100+
/* The in-file checksum is the last dword past the chunk data. */
101+
102+
file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len);
103+
104+
/* If the checksums do not match, we need to fix the file. */
105+
106+
if (real_cksum != file_cksum) {
107+
108+
/* First modification? Make a copy of the input buffer. Round size
109+
up to 4 kB to minimize the number of reallocs needed. */
110+
111+
if (new_buf == in_buf) {
112+
113+
if (len <= data->size) {
114+
115+
new_buf = data->buf;
116+
117+
} else {
118+
119+
new_buf = realloc(data->buf, UP4K(len));
120+
if (!new_buf) {
121+
122+
*out_buf = in_buf;
123+
return len;
124+
125+
}
126+
127+
data->buf = new_buf;
128+
data->size = UP4K(len);
129+
memcpy(new_buf, in_buf, len);
130+
131+
}
132+
133+
}
134+
135+
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
136+
137+
}
138+
139+
/* Skip the entire chunk and move to the next one. */
140+
141+
pos += 12 + chunk_len;
142+
143+
}
144+
145+
*out_buf = new_buf;
146+
return len;
147+
148+
}
149+
150+
/* Gets called afterwards */
151+
void afl_custom_deinit(post_state_t *data) {
152+
153+
free(data->buf);
154+
free(data);
155+
156+
}
157+

0 commit comments

Comments
 (0)