Permalink
Browse files

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

  • Loading branch information...
mrash committed Nov 14, 2014
1 parent fe28812 commit aaa44656bcfcb705d80768a7b9aa0d45a0e55e21
View
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
View
@@ -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
View
@@ -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
@@ -0,0 +1 @@
+1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA
@@ -0,0 +1 @@
+3145808919615481:root:1397329899:2.0.1:0:127.0.0.2,echo fwknoptest > /tmp/fwknoptest:AAAAA
@@ -0,0 +1 @@
+1716411011200157:root:1397329899:2.0.1:4:127.0.0.2,tcp/22:192.168.10.1,12345:1234:AAAAAA
View
@@ -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
@@ -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
@@ -103,6 +103,7 @@
"$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_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 @@
@rijndael_hmac,
@rijndael_hmac_fuzzing,
@fault_injection,
+ @afl_fuzzing,
@os_compatibility,
@perl_FKO_module,
@python_fko,
View
@@ -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",
+ },
+);

0 comments on commit aaa4465

Please sign in to comment.