[server] add support for American Fuzzy Lop (ALF) fuzzing

This commit is contained in:
Michael Rash
2014-11-13 20:55:04 -05:00
parent fe288120b3
commit aaa44656bc
17 changed files with 230 additions and 3 deletions

View File

@@ -356,6 +356,7 @@ EXTRA_DIST = \
test/tests/rijndael_backwards_compatibility.pl \
test/tests/os_compatibility.pl \
test/tests/fault_injection.pl \
test/tests/afl_fuzzing.pl \
test/tests/gpg_hmac.pl \
test/tests/gpg_no_pw.pl \
test/tests/gpg_no_pw_hmac.pl \

View File

@@ -167,6 +167,21 @@ if test "x$want_fuzzing_interfaces" = "xyes"; then
AC_DEFINE([FUZZING_INTERFACES], [1], [Define for fuzzing interfaces support])
fi
dnl Decide whether or not to compile in support for the 'American Fuzzy Lop'
dnl fuzzer from Michal Zalewski - this is for testing purposes only
dnl
want_afl_fuzzing_support=no
AC_ARG_ENABLE([afl-fuzzing],
[AS_HELP_STRING([--enable-afl-fuzzing],
[Build fwknop binaries with support for the American Fuzzy Lop fuzzer @<:@default is to disable@:>@])],
[want_afl_fuzzing_support=$enableval],
[])
if test "x$want_afl_fuzzing_support" = "xyes"; then
AC_DEFINE([AFL_FUZZING], [1], [Define for AFL fuzzing support])
AC_DEFINE([FUZZING_INTERFACES], [1], [Define for fuzzing interfaces support])
fi
dnl Decide whether or not to enable UDP server mode (no libpcap dependency)
dnl
want_udp_server=no

View File

@@ -36,6 +36,7 @@
#include "base64.h"
#include "fko_common.h"
#if !AFL_FUZZING
static unsigned char map2[] =
{
0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36,
@@ -49,13 +50,24 @@ static unsigned char map2[] =
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33
};
#endif
int
b64_decode(const char *in, unsigned char *out)
{
int i, v;
int i;
unsigned char *dst = out;
#if ! AFL_FUZZING
int v;
#endif
#if AFL_FUZZING
/* short circuit base64 decoding in AFL fuzzing mode - just copy
* data as-is.
*/
for (i = 0; in[i]; i++)
*dst++ = in[i];
#else
v = 0;
for (i = 0; in[i] && in[i] != '='; i++) {
unsigned int index= in[i]-43;
@@ -68,6 +80,7 @@ b64_decode(const char *in, unsigned char *out)
if (i & 3)
*dst++ = v >> (6 - 2 * (i & 3));
}
#endif
*dst = '\0';

View File

@@ -75,6 +75,10 @@ last_field(char *str)
static int
verify_digest(char *tbuf, int t_size, fko_ctx_t ctx)
{
#if AFL_FUZZING
return FKO_SUCCESS;
#endif
switch(ctx->digest_type)
{
case FKO_DIGEST_MD5:
@@ -113,6 +117,12 @@ verify_digest(char *tbuf, int t_size, fko_ctx_t ctx)
static int
is_valid_digest_len(int t_size, fko_ctx_t ctx)
{
#if AFL_FUZZING
ctx->digest_type = FKO_DIGEST_SHA256;
ctx->digest_len = t_size;
return FKO_SUCCESS;
#endif
switch(t_size)
{
case MD5_B64_LEN:

View File

@@ -153,13 +153,14 @@ enum {
/* Our getopt_long options string.
*/
#define GETOPTS_OPTION_STRING "a:c:C:d:Dfhi:Kl:O:p:P:RStvV"
#define GETOPTS_OPTION_STRING "Aa:c:C:d:Dfhi:Kl:O:p:P:RStvV"
/* Our program command-line options...
*/
static struct option cmd_opts[] =
{
{"access-file", 1, NULL, 'a'},
{"afl-fuzzing", 0, NULL, 'A'},
{"config-file", 1, NULL, 'c'},
{"packet-limit", 1, NULL, 'C'},
{"digest-file", 1, NULL, 'd'},

View File

@@ -1031,6 +1031,14 @@ config_init(fko_srv_options_t *opts, int argc, char **argv)
GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) {
switch(cmd_arg) {
case 'A':
#if AFL_FUZZING
opts->afl_fuzzing = 1;
#else
log_msg(LOG_ERR, "[*] fwknopd not compiled with AFL fuzzing support");
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
#endif
break;
case 'a':
set_config_entry(opts, CONF_ACCESS_FILE, optarg);
break;

View File

@@ -58,11 +58,19 @@ static void setup_pid(fko_srv_options_t *opts);
static void init_digest_cache(fko_srv_options_t *opts);
static void set_locale(fko_srv_options_t *opts);
static pid_t get_running_pid(const fko_srv_options_t *opts);
#if AFL_FUZZING
static void afl_pkt_from_stdin(fko_srv_options_t *opts);
#endif
#if HAVE_LIBFIU
static void enable_fault_injections(fko_srv_options_t * const opts);
#endif
#if AFL_FUZZING
#define AFL_MAX_PKT_SIZE 1024
#define AFL_DUMP_CTX_SIZE 4096
#endif
int
main(int argc, char **argv)
{
@@ -114,7 +122,8 @@ main(int argc, char **argv)
/* Make sure we have a valid run dir and path leading to digest file
* in case it configured to be somewhere other than the run dir.
*/
if(! check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0))
if(!opts.afl_fuzzing
&& ! check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0))
clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
/* Initialize the firewall rules handler based on the fwknopd.conf
@@ -175,6 +184,12 @@ main(int argc, char **argv)
clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
}
#if AFL_FUZZING
/* SPA data from STDIN. */
if(opts.afl_fuzzing)
afl_pkt_from_stdin(&opts);
#endif
/* Prepare the firewall - i.e. flush any old rules and (for iptables)
* create fwknop chains.
*/
@@ -274,10 +289,69 @@ static void set_locale(fko_srv_options_t *opts)
return;
}
#if AFL_FUZZING
static void afl_pkt_from_stdin(fko_srv_options_t *opts)
{
FILE *fp = NULL;
fko_ctx_t decode_ctx = NULL;
unsigned char spa_pkt[AFL_MAX_PKT_SIZE] = {0};
int res = 0, es = EXIT_SUCCESS;
char dump_buf[AFL_DUMP_CTX_SIZE];
fp = fdopen(STDIN_FILENO, "r");
if(fp != NULL)
{
if(fgets((char *)spa_pkt, AFL_MAX_PKT_SIZE, fp) == NULL)
{
fclose(fp);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
}
fclose(fp);
fko_new(&decode_ctx);
res = fko_set_encoded_data(decode_ctx, (char *) spa_pkt,
strlen((char *)spa_pkt), 0, FKO_DIGEST_SHA256);
if(res == FKO_SUCCESS)
res = fko_set_spa_data(decode_ctx, (const char *) spa_pkt);
if(res == FKO_SUCCESS)
res = fko_decode_spa_data(decode_ctx);
if(res == FKO_SUCCESS)
res = dump_ctx_to_buffer(decode_ctx, dump_buf, sizeof(dump_buf));
if(res == FKO_SUCCESS)
log_msg(LOG_INFO, "%s", dump_buf);
fko_destroy(decode_ctx);
if(res == FKO_SUCCESS)
{
log_msg(LOG_INFO, "SPA packet decode success: %s", fko_errstr(res));
es = EXIT_SUCCESS;
}
else
{
log_msg(LOG_ERR, "Could not decode SPA packet: %s", fko_errstr(res));
es = EXIT_FAILURE;
}
}
else
log_msg(LOG_ERR, "Could not acquire SPA packet from stdin.");
clean_exit(opts, NO_FW_CLEANUP, es);
}
#endif
static void init_digest_cache(fko_srv_options_t *opts)
{
int rp_cache_count;
#if AFL_FUZZING
if(opts->afl_fuzzing)
return;
#endif
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
{
rp_cache_count = replay_cache_init(opts);
@@ -311,6 +385,11 @@ static void setup_pid(fko_srv_options_t *opts)
{
pid_t old_pid;
#if AFL_FUZZING
if(opts->afl_fuzzing)
return;
#endif
/* If we are a new process (just being started), proceed with normal
* start-up. Otherwise, we are here as a result of a signal sent to an
* existing process and we want to restart.

View File

@@ -577,6 +577,7 @@ typedef struct fko_srv_options
unsigned char fw_list_all; /* List all current firewall rules */
unsigned char fw_flush; /* Flush current firewall rules */
unsigned char test; /* Test mode flag */
unsigned char afl_fuzzing; /* SPA pkts from stdin for AFL fuzzing */
unsigned char verbose; /* Verbose mode flag */
unsigned char exit_after_parse_config; /* Parse config and exit */
unsigned char enable_udp_server; /* Enable UDP server mode */

50
test/afl/README Normal file
View File

@@ -0,0 +1,50 @@
The fwknop project supports various fuzzing strategies, and one of the most
important is usage of the 'American Fuzzy Lop' (AFL) fuzzer written by Michal
Zalewski (see: https://code.google.com/p/american-fuzzy-lop/). Because AFL is
not designed to handle encryption schemes (see the README included in the AFL
sources for more information on this), a special --enable-afl-fuzzing command
line switch is available to the fwknop autoconf configure script. This argument
allows encryption and base64 encoding to be bypassed when feeding SPA packet
data to fwknopd via stdin. It is the feature that enables AFL fuzzing.
This directory contains enabling scripts in order to make it easy to fuzz
fwknop with AFL. It is assumed that AFL is installed and in your path. The
files are in this directory are organized as follows:
afl-compile.sh - Script to compile fwknop underneath afl-gcc.
afl-fuzzing.in - AFL input directory which contains input test cases.
afl-fuzzing.out - AFL output directory.
afl-run.sh - Script to invoke AFL with proper command line arguments to
fwknopd for fuzzing enablement.
Here is an example of what fwknopd produces when compiled for AFL support when
a dummy SPA packet is provided in non-encoded/encrypted form via fwknopd's
stdin:
$ ./fwknopd-stdin-test.sh
+ SPA_PKT=1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA
+ LD_LIBRARY_PATH=../../lib/.libs ../../server/.libs/fwknopd -c ../conf/default_fwknopd.conf -a ../conf/default_access.conf -A -f -t
+ echo -n 1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA
Warning: REQUIRE_SOURCE_ADDRESS not enabled for access stanza source: 'ANY'
SPA Field Values:
=================
Random Value: 1716411011200157
Username: root
Timestamp: 1397329899
FKO Version: 2.0.1
Message Type: 1 (Access msg)
Message String: 127.0.0.2,tcp/22
Nat Access: <NULL>
Server Auth: <NULL>
Client Timeout: 0
Digest Type: 3 (SHA256)
HMAC Type: 0 (None)
Encryption Type: 1 (Rijndael)
Encryption Mode: 2 (CBC)
Encoded Data: 1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22
SPA Data Digest: AAAAA
HMAC: <NULL>
Final SPA Data: 200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA
SPA packet decode success: Success

8
test/afl/afl-compile.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh -x
cd ../../
CC=afl-gcc ./extras/apparmor/configure_args.sh --enable-afl-fuzzing
make clean
make
cd test/afl
exit

View File

@@ -0,0 +1 @@
1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA

View File

@@ -0,0 +1 @@
3145808919615481:root:1397329899:2.0.1:0:127.0.0.2,echo fwknoptest > /tmp/fwknoptest:AAAAA

View File

@@ -0,0 +1 @@
1716411011200157:root:1397329899:2.0.1:4:127.0.0.2,tcp/22:192.168.10.1,12345:1234:AAAAAA

16
test/afl/afl-run.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh -x
OLD_DIR=afl-out-archive
OUT_DIR=afl-fuzzing.out
[ ! -d $OLD_DIR ] && mkdir $OLD_DIR
TS=`date +"%m%d%y%H%M%S"`
[ -d $OUT_DIR ] && mv $OUT_DIR "$OLD_DIR/$OUT_DIR-$TS"
mkdir $OUT_DIR
### make sure that a basic SPA packet to stdin in fwknopd -A mode works
./fwknopd-stdin-test.sh || exit
LD_LIBRARY_PATH=../../lib/.libs afl-fuzz -i afl-fuzzing.in -o $OUT_DIR ../../server/.libs/fwknopd -c ../conf/default_fwknopd.conf -a ../conf/default_access.conf -A -f -t
exit

6
test/afl/fwknopd-stdin-test.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh -x
SPA_PKT="1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA"
#SPA_PKT="1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:A"
echo -n $SPA_PKT | LD_LIBRARY_PATH=../../lib/.libs ../../server/.libs/fwknopd -c ../conf/default_fwknopd.conf -a ../conf/default_access.conf -A -f -t

View File

@@ -103,6 +103,7 @@ my @test_files = (
"$tests_dir/rijndael_hmac.pl",
"$tests_dir/rijndael_hmac_fuzzing.pl",
"$tests_dir/fault_injection.pl",
"$tests_dir/afl_fuzzing.pl",
"$tests_dir/os_compatibility.pl",
"$tests_dir/perl_FKO_module.pl",
"$tests_dir/python_fko.pl",
@@ -128,6 +129,7 @@ our @rijndael_hmac = (); ### from tests/rijndael_hmac.pl
our @rijndael_fuzzing = (); ### from tests/rijndael_fuzzing.pl
our @rijndael_hmac_fuzzing = (); ### from tests/rijndael_hmac_fuzzing.pl
our @fault_injection = (); ### from tests/fault_injection.pl
our @afl_fuzzing = (); ### from tests/alf_fuzzing.pl
our @gpg_no_pw = (); ### from tests/gpg_now_pw.pl
our @gpg_no_pw_hmac = (); ### from tests/gpg_now_pw_hmac.pl
our @gpg = (); ### from tests/gpg.pl
@@ -733,6 +735,7 @@ my @tests = (
@rijndael_hmac,
@rijndael_hmac_fuzzing,
@fault_injection,
@afl_fuzzing,
@os_compatibility,
@perl_FKO_module,
@python_fko,

13
test/tests/afl_fuzzing.pl Normal file
View File

@@ -0,0 +1,13 @@
@afl_fuzzing = (
### run fwknopd with the -A arg for American Fuzzy Lop support regardless
### of whether AFL support has been compiled in - if not, an error is
### thrown and is therefore good for code coverage
{
'category' => 'AFL',
'subcategory' => 'FUZZING',
'detail' => 'pkt to stdin',
'function' => \&generic_exec,
'cmdline' => 'echo -n "1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA" | ' .
"$lib_view_str $valgrind_str $fwknopdCmd $default_server_conf_args -A -f -v",
},
);