mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-16 11:58:08 +00:00
first version with unix domain sockets is ready for testing
This commit is contained in:
@ -1,5 +1,4 @@
|
|||||||
#include "../../include/afl-fuzz.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -7,10 +6,10 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
#define INIT_BUF_SIZE 4096
|
#define INIT_BUF_SIZE 4096
|
||||||
#define SOCKET_NAME "/tmp/atnwalk.socket"
|
#define SOCKET_NAME "/tmp/atnwalk.socket"
|
||||||
|
|
||||||
|
|
||||||
// handshake constants
|
// handshake constants
|
||||||
const uint8_t SERVER_ARE_YOU_ALIVE = 42;
|
const uint8_t SERVER_ARE_YOU_ALIVE = 42;
|
||||||
const uint8_t SERVER_YES_I_AM_ALIVE = 213;
|
const uint8_t SERVER_YES_I_AM_ALIVE = 213;
|
||||||
@ -23,8 +22,10 @@ const uint8_t SERVER_ENCODE_BIT = 0b00001000;
|
|||||||
|
|
||||||
|
|
||||||
typedef struct atnwalk_mutator {
|
typedef struct atnwalk_mutator {
|
||||||
uint8_t *decoded_buf;
|
uint8_t *fuzz_buf;
|
||||||
size_t decoded_size;
|
size_t fuzz_size;
|
||||||
|
uint8_t *post_process_buf;
|
||||||
|
size_t post_process_size;
|
||||||
} atnwalk_mutator_t;
|
} atnwalk_mutator_t;
|
||||||
|
|
||||||
|
|
||||||
@ -55,6 +56,32 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void put_uint32(uint8_t *buf, uint32_t val) {
|
||||||
|
buf[0] = (uint8_t) (val >> 24);
|
||||||
|
buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16);
|
||||||
|
buf[2] = (uint8_t) ((val & 0x0000ff00) >> 8);
|
||||||
|
buf[3] = (uint8_t) (val & 0x000000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t to_uint32(uint8_t *buf) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
val |= (((uint32_t) buf[0]) << 24);
|
||||||
|
val |= (((uint32_t) buf[1]) << 16);
|
||||||
|
val |= (((uint32_t) buf[2]) << 8);
|
||||||
|
val |= ((uint32_t) buf[3]);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_uint64(uint8_t *buf, uint64_t val) {
|
||||||
|
buf[0] = (uint8_t) (val >> 56);
|
||||||
|
buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48);
|
||||||
|
buf[2] = (uint8_t) ((val & 0x0000ff0000000000) >> 40);
|
||||||
|
buf[3] = (uint8_t) ((val & 0x000000ff00000000) >> 32);
|
||||||
|
buf[4] = (uint8_t) ((val & 0x00000000ff000000) >> 24);
|
||||||
|
buf[5] = (uint8_t) ((val & 0x0000000000ff0000) >> 16);
|
||||||
|
buf[6] = (uint8_t) ((val & 0x000000000000ff00) >> 8);
|
||||||
|
buf[7] = (uint8_t) (val & 0x00000000000000ff);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this custom mutator
|
* Initialize this custom mutator
|
||||||
@ -67,19 +94,21 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
|||||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||||
* Return NULL on error.
|
* Return NULL on error.
|
||||||
*/
|
*/
|
||||||
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
atnwalk_mutator_t *afl_custom_init(void *afl, unsigned int seed) {
|
||||||
srand(seed);
|
srand(seed);
|
||||||
atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t));
|
atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
perror("afl_custom_init alloc");
|
perror("afl_custom_init alloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
data->decoded_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
data->fuzz_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
||||||
data->decoded_size = INIT_BUF_SIZE;
|
data->fuzz_size = INIT_BUF_SIZE;
|
||||||
|
data->post_process_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
||||||
|
data->post_process_size = INIT_BUF_SIZE;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
/**
|
/**
|
||||||
* Perform custom mutations on a given input
|
* Perform custom mutations on a given input
|
||||||
*
|
*
|
||||||
@ -100,13 +129,12 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
uint8_t *add_buf, size_t add_buf_size, size_t max_size) {
|
uint8_t *add_buf, size_t add_buf_size, size_t max_size) {
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
int fd_socket;
|
int fd_socket;
|
||||||
ssize_t n;
|
uint8_t ctrl_buf[8];
|
||||||
uint8_t buffer[5];
|
uint8_t wanted;
|
||||||
|
|
||||||
// initialize the socket
|
// initialize the socket
|
||||||
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (fd_socket == -1) {
|
if (fd_socket == -1) {
|
||||||
perror("socket");
|
|
||||||
*out_buf = NULL;
|
*out_buf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -114,26 +142,127 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||||
if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
||||||
perror("atnwalk server is down");
|
close(fd_socket);
|
||||||
*out_buf = NULL;
|
*out_buf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!write_all(fd_socket, buffer, 5)) {
|
// TODO: how to set connection deadline? maybe not required if server already closes the connection?
|
||||||
perror("write to atnwalk server failed");
|
|
||||||
|
// TODO: there should be some kind of loop retrying with different seeds and ultimately giving up on that input?
|
||||||
|
// maybe this is not necessary, because we may also just return a single byte in case of failure?
|
||||||
|
|
||||||
|
// ask whether the server is alive
|
||||||
|
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||||
|
close(fd_socket);
|
||||||
*out_buf = NULL;
|
*out_buf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_all(fd_socket, buffer, 5)) {
|
// see whether the server replies as expected
|
||||||
perror("read to atnwalk server failed");
|
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||||
exit(EXIT_FAILURE);
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the server what we want to do
|
||||||
|
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
|
||||||
|
|
||||||
|
// 50% chance to perform a crossover if there is an additional buffer available
|
||||||
|
if ((add_buf_size > 0) && (rand() % 2)) {
|
||||||
|
wanted |= SERVER_CROSSOVER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the server what we want and how much data will be sent
|
||||||
|
ctrl_buf[0] = wanted;
|
||||||
|
put_uint32(ctrl_buf + 1, (uint32_t) buf_size);
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the data to mutate and encode
|
||||||
|
if (!write_all(fd_socket, buf, buf_size)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wanted & SERVER_CROSSOVER_BIT) {
|
||||||
|
// since we requested crossover, we will first tell how much additional data is to be expected
|
||||||
|
put_uint32(ctrl_buf, (uint32_t) add_buf_size);
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the additional data for crossover
|
||||||
|
if (!write_all(fd_socket, add_buf, add_buf_size)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lastly, a seed is required for crossover so send one
|
||||||
|
put_uint64(ctrl_buf, (uint64_t) rand());
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we requested mutation, we need to provide a seed for that
|
||||||
|
put_uint64(ctrl_buf, (uint64_t) rand());
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain the required buffer size for the data that will be returned
|
||||||
|
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
size_t new_size = (size_t) to_uint32(ctrl_buf);
|
||||||
|
|
||||||
|
// if the data is too large then we ignore this round
|
||||||
|
if (new_size > max_size) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_size > buf_size) {
|
||||||
|
// buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate
|
||||||
|
if (new_size > data->fuzz_size) {
|
||||||
|
data->fuzz_size = new_size << 1;
|
||||||
|
data->fuzz_buf = (uint8_t *) realloc(data->fuzz_buf, data->fuzz_size);
|
||||||
|
}
|
||||||
|
*out_buf = data->fuzz_buf;
|
||||||
|
} else {
|
||||||
|
// new_size fits into buf, so re-use it
|
||||||
|
*out_buf = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain the encoded data
|
||||||
|
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd_socket);
|
close(fd_socket);
|
||||||
|
return new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
/**
|
/**
|
||||||
* A post-processing function to use right before AFL writes the test case to
|
* A post-processing function to use right before AFL writes the test case to
|
||||||
* disk in order to execute the target.
|
* disk in order to execute the target.
|
||||||
@ -151,23 +280,90 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
* A return of 0 indicates an error.
|
* A return of 0 indicates an error.
|
||||||
*/
|
*/
|
||||||
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
|
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
|
||||||
data->decoded_buf[0] = 'p';
|
struct sockaddr_un addr;
|
||||||
data->decoded_buf[1] = 'u';
|
int fd_socket;
|
||||||
data->decoded_buf[2] = 't';
|
uint8_t ctrl_buf[8];
|
||||||
data->decoded_buf[3] = 's';
|
|
||||||
data->decoded_buf[4] = ' ';
|
// initialize the socket
|
||||||
data->decoded_buf[5] = ';';
|
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
data->decoded_buf[6] = '\n';
|
if (fd_socket == -1) {
|
||||||
return 7;
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||||
|
if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask whether the server is alive
|
||||||
|
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see whether the server replies as expected
|
||||||
|
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the server what we want and how much data will be sent
|
||||||
|
ctrl_buf[0] = SERVER_DECODE_BIT;
|
||||||
|
put_uint32(ctrl_buf + 1, (uint32_t) buf_size);
|
||||||
|
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the data to decode
|
||||||
|
if (!write_all(fd_socket, buf, buf_size)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain the required buffer size for the data that will be returned
|
||||||
|
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
size_t new_size = (size_t) to_uint32(ctrl_buf);
|
||||||
|
|
||||||
|
// need to use data->post_process_buf, let's see whether we need to reallocate
|
||||||
|
if (new_size > data->post_process_size) {
|
||||||
|
data->post_process_size = new_size << 1;
|
||||||
|
data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size);
|
||||||
|
}
|
||||||
|
*out_buf = data->post_process_buf;
|
||||||
|
|
||||||
|
// obtain the decoded data
|
||||||
|
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||||
|
close(fd_socket);
|
||||||
|
*out_buf = buf;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd_socket);
|
||||||
|
return new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
/**
|
/**
|
||||||
* Deinitialize everything
|
* Deinitialize everything
|
||||||
*
|
*
|
||||||
* @param data The data ptr from afl_custom_init
|
* @param data The data ptr from afl_custom_init
|
||||||
*/
|
*/
|
||||||
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
||||||
free(data->decoded_buf);
|
free(data->fuzz_buf);
|
||||||
|
free(data->post_process_buf);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
@ -130,12 +130,15 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
|
|||||||
new_size = afl->max_length;
|
new_size = afl->max_length;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// TODO: think about how to enable the change without breaking other implementations
|
||||||
if (new_mem != *mem) { *mem = new_mem; }
|
// if (new_mem != *mem) { *mem = new_mem; }
|
||||||
|
|
||||||
/* everything as planned. use the potentially new data. */
|
/* everything as planned. use the potentially new data. */
|
||||||
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
|
// TODO: think about how to enable the change without breaking other implementations
|
||||||
len = new_size;
|
afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size);
|
||||||
|
|
||||||
|
// TODO: think about how to enable the change without breaking other implementations
|
||||||
|
// len = new_size;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user