Skip to content

Commit

Permalink
Add data fuzzing option to tcpreplay-edit
Browse files Browse the repository at this point in the history
This fuzzing was designed as to test high-level protocols. It modifies
randomly 1 out of 8 packets in order for stateful protocols to cover
more of their code. The random fuzzing actions focus on data start and
end because it often is the part of the data high-level protocols base
their decisions on.

0x00 and 0xff are considered bytes of a higher significance than the
other values, and given more appearance probability.

When a packet is fuzzed, we randomly apply one action (see fuzzing.h)
If no action corresponds, FUZZING_CHANGE_MID_RANDOM is default fuzzing
case.

Option is named --fuzz-seed (without short option), not to be mixed with
--seed (randomize src/dst IPv4/v6 addresses).
  • Loading branch information
Gabriel Ganne authored and Gabriel Ganne committed Mar 14, 2017
1 parent 7f92151 commit 41b6d36
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/tcpedit/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BUILT_SOURCES = tcpedit_stub.h

libtcpedit_a_SOURCES = tcpedit.c parse_args.c edit_packet.c \
portmap.c dlt.c checksum.c incremental_checksum.c \
tcpedit_api.c
tcpedit_api.c fuzzing.c

manpages: tcpedit.1

Expand Down
213 changes: 213 additions & 0 deletions src/tcpedit/fuzzing.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "defines.h"
#include "fuzzing.h"

#include "common/utils.h"

#include "tcpedit/tcpedit.h"

static unsigned int fuzz_seed = 0;

void
fuzzing_init(unsigned int _fuzz_seed)
{
fuzz_seed = _fuzz_seed;
srand(fuzz_seed);
}

#define SGT_MAX_SIZE 16
static inline int
fuzz_get_sgt_size(uint32_t r, uint32_t caplen)
{
if (0 == caplen) {
return 0;
}
if (caplen <= SGT_MAX_SIZE) {
/* packet too small, fuzzing only one byte */
return 1;
}
/* return random value between 1 and SGT_MAX_SIZE */
return (1 + (r % (SGT_MAX_SIZE - 1)));
}

static inline int
fuzz_reduce_packet_size(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
u_char **pktdata, COUNTER new_len)
{
assert(new_len <= pkthdr->len);

if (pkthdr->len < pkthdr->caplen) {
tcpedit_seterr(tcpedit, "%s", "Packet larger than capture len.");
return -1;
}

if (new_len == pkthdr->len) {
return 0;
}

pkthdr->len = new_len;
pkthdr->caplen = pkthdr->len;

/* do not fix lengths in ip/tcp/udp layers.
* fixlen option already does so, and can be called with fuzzing option. */

return 1;
}

int
fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
u_char **pktdata)
{
int packet_changed;
uint32_t r;
unsigned int * len;

assert(tcpedit != NULL);
assert(pkthdr != NULL);
assert(pktdata != NULL);

if (fuzz_seed == 0) {
return 0;
}

len = &(pkthdr->caplen);
packet_changed = 0;
r = rand();

/* TODO sktip ip/tcp/udp headers */

/* Randomly select one out of 8 packets */
if (((r >> 13) & 0x7) == 0 && (*len) > 1) {
uint32_t s;

s = (r >> 9) & FUZZING_TOTAL_ACTION_NUMBER_MASK;

dbgx(3, "packet fuzzed : %d", s);
switch (s) {
case FUZZING_DROP_PACKET:
{
/* simulate droping the packet */
packet_changed = fuzz_reduce_packet_size(tcpedit, pkthdr, pktdata, 0);
if (packet_changed < 0) {
/* could not change packet size, so packet left unchanged */
return 0;
}
}
break;
case FUZZING_REDUCE_SIZE:
{
/* reduce packet size */
uint32_t new_len = (r % ((*len) - 1)) + 1;
packet_changed = fuzz_reduce_packet_size(tcpedit, pkthdr, pktdata, new_len);
if (packet_changed < 0) {
/* could not change packet size, so packet left unchanged */
return 0;
}
packet_changed = 1;
}
break;
case FUZZING_CHANGE_START_ZERO:
{
/* fuzz random-size segment at the begining of the packet with 0x00 */
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
memset((*pktdata), 0x00, sgt_size);
packet_changed = 1;
}
break;
case FUZZING_CHANGE_START_RANDOM:
{
/* fuzz random-size segment at the begining of the packet with random Bytes */
int i;
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
for (i = 0; i < sgt_size; i++) {
(*pktdata)[i] = (*pktdata)[i] ^ (r >> 4);
}
packet_changed = 1;
}
break;
case FUZZING_CHANGE_START_FF:
{
/* fuzz random-size segment at the begining of the packet with 0xff */
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
memset((*pktdata), 0xff, sgt_size);
packet_changed = 1;
}
break;
case FUZZING_CHANGE_MID_ZERO:
{
/* fuzz random-size segment inside the packet with 0x00 */
uint32_t r = rand();
uint32_t offset = ((r >> 16) % ((*len) - 1)) + 1;
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len) - offset);
memset((*pktdata) + offset, 0x00, sgt_size);
packet_changed = 1;
}
break;
case FUZZING_CHANGE_MID_FF:
{
/* fuzz random-size segment inside the packet with 0xff */
uint32_t r = rand();
uint32_t offset = ((r >> 16) % ((*len) - 1)) + 1;
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len) - offset);
memset((*pktdata) + offset, 0xff, sgt_size);
packet_changed = 1;
}
break;
case FUZZING_CHANGE_END_ZERO:
{
/* fuzz random-sized segment at the end of the packet with 0x00 */
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
memset((*pktdata) + (*len) - sgt_size, 0x00, sgt_size);
packet_changed = 1;
}
break;
case FUZZING_CHANGE_END_RANDOM:
{
/* fuzz random-sized segment at the end of the packet with random Bytes */
int i;
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
for (i = ((*len) - sgt_size); i < (*len); i++) {
(*pktdata)[i] = (*pktdata)[i] ^ (r >> 4);
}
packet_changed = 1;
}
break;
case FUZZING_CHANGE_END_FF:
{
/* fuzz random-sized segment at the end of the packet with 0xff00 */
uint32_t r = rand();
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len));
memset((*pktdata) + (*len) - sgt_size, 0xff, sgt_size);
packet_changed = 1;
}
break;

default:
case FUZZING_CHANGE_MID_RANDOM:
{
/* fuzz random-size segment inside the packet with random Bytes */
int i;
uint32_t r = rand();
uint32_t offset = ((r >> 16) % ((*len) - 1)) + 1;
uint32_t sgt_size = fuzz_get_sgt_size(r, (*len) - offset);
for (i = offset; i < offset + sgt_size; i++) {
(*pktdata)[i] = (*pktdata)[i] ^ (r >> 4);
}
packet_changed = 1;
}
break;
}
}

/* No fuzzing for the other 7 out of 8 packets */
return packet_changed;
}
40 changes: 40 additions & 0 deletions src/tcpedit/fuzzing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef FUZZING_H
#define FUZZING_H

#include <stdint.h>
#include <stdlib.h>

#include "defines.h"
#include "tcpedit/tcpedit_types.h"

enum {
FUZZING_DROP_PACKET,
FUZZING_REDUCE_SIZE,
FUZZING_CHANGE_START_ZERO,
FUZZING_CHANGE_START_RANDOM,
FUZZING_CHANGE_START_FF,
FUZZING_CHANGE_MID_ZERO,
FUZZING_CHANGE_MID_RANDOM, /* the default case */
FUZZING_CHANGE_MID_FF,
FUZZING_CHANGE_END_ZERO,
FUZZING_CHANGE_END_RANDOM,
FUZZING_CHANGE_END_FF,
};
#define FUZZING_TOTAL_ACTION_NUMBER_MASK (0xf)

/**
* init fuzz seed and allocate buffer.
*/
void
fuzzing_init(unsigned int fuzz_seed);

/*
* fuzz packet data.
* only one out of 8 packets are fuzzed.
* fuzzed packets get one random modification from the enum above.
* Returns whether the packet has been modified (1, or 0)
*/
int
fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, u_char **pktdata);

#endif /* FUZZING_H */
5 changes: 5 additions & 0 deletions src/tcpedit/parse_args.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ tcpedit_post_args(tcpedit_t *tcpedit) {
}
}

/* --fuzz-seed */
if (HAVE_OPT(FUZZ_SEED)) {
tcpedit->fuzz_seed = OPT_VALUE_FUZZ_SEED;
}

/* TCP/UDP port rewriting */
if (HAVE_OPT(PORTMAP)) {
int ct = STACKCT_OPT(PORTMAP);
Expand Down
18 changes: 15 additions & 3 deletions src/tcpedit/plugins/dlt_en10mb/en10mb.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,22 +586,34 @@ dlt_en10mb_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *p
int
dlt_en10mb_l2len(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
{
int l2len;
struct tcpr_ethernet_hdr *eth = NULL;

assert(ctx);
assert(packet);
assert(pktlen);


l2len = -1;
eth = (struct tcpr_ethernet_hdr *)packet;
switch (ntohs(eth->ether_type)) {
case ETHERTYPE_VLAN:
return 18;
l2len = 18;
break;

default:
return 14;
l2len = 14;
break;
}

if (l2len > 0) {
if (pktlen < l2len) {
/* can happen if fuzzing is enabled */
return 0;
}

return l2len;
}

tcpedit_seterr(ctx->tcpedit, "%s", "Whoops! Bug in my code!");
return -1;
}
Expand Down
9 changes: 9 additions & 0 deletions src/tcpedit/tcpedit.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "incremental_checksum.h"
#include "edit_packet.h"
#include "parse_args.h"
#include "fuzzing.h"


#include "lib/sll.h"
Expand Down Expand Up @@ -220,6 +221,14 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
}
}

if (tcpedit->fuzz_seed != 0) {
retval = fuzzing(tcpedit, *pkthdr, pktdata);
if (retval < 0) {
return TCPEDIT_ERROR;
}
needtorecalc += retval;
}

/* (Un)truncate or MTU truncate packet? */
if (tcpedit->fixlen || tcpedit->mtu_truncate) {
if ((retval = untrunc_packet(tcpedit, *pkthdr, pktdata, ip_hdr, ip6_hdr)) < 0)
Expand Down
14 changes: 14 additions & 0 deletions src/tcpedit/tcpedit_opts.def
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,18 @@ Delete the packet
EOText;
};

flag = {
name = fuzz-seed;
arg-type = number;
arg-default = 0;
arg-range = "0->";
descrip = "Apply random fuzzing to the packets based on given seed";
doc = <<- EOText
This fuzzing was designed as to test high-level protocols. It modifies randomly
1 out of 8 packets in order for stateful protocols to cover more of their code.
The random fuzzing actions focus on data start and end because it often is the
part of the data high-level protocols base their decisions on.
EOText;
};

#include plugins/dlt_stub.def
2 changes: 2 additions & 0 deletions src/tcpedit/tcpedit_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ typedef struct {
int mtu; /* Deal with different MTU's */
bool mtu_truncate; /* Should we truncate frames > MTU? */
int maxpacket; /* L2 header + MTU */

unsigned long fuzz_seed;
} tcpedit_t;


Expand Down
6 changes: 6 additions & 0 deletions src/tcpreplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#ifdef TCPREPLAY_EDIT
#include "tcpreplay_edit_opts.h"
#include "tcpedit/tcpedit.h"
#include "tcpedit/fuzzing.h"
tcpedit_t *tcpedit;
#else
#include "tcpreplay_opts.h"
Expand Down Expand Up @@ -126,6 +127,11 @@ main(int argc, char *argv[])
}
}

#ifdef TCPREPLAY_EDIT
/* fuzzing init */
fuzzing_init(tcpedit->fuzz_seed);
#endif

/* init the signal handlers */
init_signal_handlers();

Expand Down

0 comments on commit 41b6d36

Please sign in to comment.