if (dumb_mode == 1 || no_forkserver) {
if (waitpid(child_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
} else {
s32 res;
if ((res = read(fsrv_st_fd, &status, 4)) != 4) {
if (stop_soon) return 0;
RPFATAL(res, "Unable to communicate with fork server (OOM?)");
}
}
if (dumb_mode == 1 || no_forkserver) {
if (use_net) send_over_network();
if (waitpid(child_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
} else {
if (use_net) send_over_network();
s32 res;
if ((res = read(fsrv_st_fd, &status, 4)) != 4) {
if (stop_soon) return 0;
RPFATAL(res, "Unable to communicate with fork server (OOM?)");
}
}
int n;
u8 likely_buggy = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in local_serv_addr;
//Clean up the server if needed
if (cleanup_script) system(cleanup_script);
//Wait a bit for the server initialization
usleep(server_wait_usecs);
//Clear the response buffer and reset the response buffer size
if (response_buf) {
ck_free(response_buf);
response_buf = NULL;
response_buf_size = 0;
}
if (response_bytes) {
ck_free(response_bytes);
response_bytes = NULL;
}
int sockfd = -1;
if (net_protocol == PRO_TCP)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
else if (net_protocol == PRO_UDP)
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
PFATAL("Cannot create a socket");
}
//Set timeout for socket data sending/receiving -- otherwise it causes a big delay
//if the server is still alive after processing all the requests
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = socket_timeout_usecs;
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(net_port);
serv_addr.sin_addr.s_addr = inet_addr(net_ip);
//This piece of code is only used for targets that send responses to a specific port number
//The Kamailio SIP server is an example. After running this code, the intialized sockfd
//will be bound to the given local port
if(local_port > 0) {
local_serv_addr.sin_family = AF_INET;
local_serv_addr.sin_addr.s_addr = INADDR_ANY;
local_serv_addr.sin_port = htons(local_port);
local_serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(sockfd, (struct sockaddr*) &local_serv_addr, sizeof(struct sockaddr_in))) {
FATAL("Unable to bind socket on local source port");
}
}
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
//If it cannot connect to the server under test
//try it again as the server initial startup time is varied
for (n=0; n < 1000; n++) {
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) break;
usleep(1000);
}
if (n== 1000) {
close(sockfd);
return 1;
}
}
//retrieve early server response if needed
if (net_recv(sockfd, timeout, poll_wait_msecs, &response_buf, &response_buf_size)) goto HANDLE_RESPONSES;
//write the request messages
kliter_t(lms) *it;
messages_sent = 0;
for (it = kl_begin(kl_messages); it != kl_end(kl_messages); it = kl_next(it)) {
n = net_send(sockfd, timeout, kl_val(it)->mdata, kl_val(it)->msize);
messages_sent++;
//Allocate memory to store new accumulated response buffer size
response_bytes = (u32 *) ck_realloc(response_bytes, messages_sent * sizeof(u32));
//Jump out if something wrong leading to incomplete message sent
if (n != kl_val(it)->msize) {
goto HANDLE_RESPONSES;
}
//retrieve server response
u32 prev_buf_size = response_buf_size;
if (net_recv(sockfd, timeout, poll_wait_msecs, &response_buf, &response_buf_size)) {
goto HANDLE_RESPONSES;
}
//Update accumulated response buffer size
response_bytes[messages_sent - 1] = response_buf_size;
//set likely_buggy flag if AFLNet does not receive any feedback from the server
//it could be a signal of a potentiall server crash, like the case of CVE-2019-7314
if (prev_buf_size == response_buf_size) likely_buggy = 1;
else likely_buggy = 0;
}
int net_recv(int sockfd, struct timeval timeout, int poll_w, char **response_buf, unsigned int *len) {
char temp_buf[1000];
int n;
struct pollfd pfd[1];
pfd[0].fd = sockfd;
pfd[0].events = POLLIN;
int rv = poll(pfd, 1, poll_w);
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
// data received
if (rv > 0) {
if (pfd[0].revents & POLLIN) {
n = recv(sockfd, temp_buf, sizeof(temp_buf), 0);
if ((n < 0) && (errno != EAGAIN)) {
return 1;
}
while (n > 0) {
usleep(10);
*response_buf = (unsigned char *)ck_realloc(*response_buf, *len + n + 1);
memcpy(&(*response_buf)[*len], temp_buf, n);
(*response_buf)[(*len) + n] = '\0';
*len = *len + n;
n = recv(sockfd, temp_buf, sizeof(temp_buf), 0);
if ((n < 0) && (errno != EAGAIN)) {
return 1;
}
}
}
} else
if (rv < 0) // an error was returned
return 1;
// rv == 0 poll timeout or all data pending after poll has been received successfully
return 0;
}
HANDLE_RESPONSES:
net_recv(sockfd, timeout, poll_wait_msecs, &response_buf, &response_buf_size);
if (messages_sent > 0 && response_bytes != NULL) {
response_bytes[messages_sent - 1] = response_buf_size;
}
//wait a bit letting the server to complete its remaining task(s)
memset(session_virgin_bits, 255, MAP_SIZE);
while(1) {
if (has_new_bits(session_virgin_bits) != 2) break;
}
close(sockfd);
if (likely_buggy && false_negative_reduction) return 0;
if (terminate_child && (child_pid > 0)) kill(child_pid, SIGTERM);
//give the server a bit more time to gracefully terminate
while(1) {
int status = kill(child_pid, 0);
if ((status != 0) && (errno == ESRCH)) break;
}
return 0;
}
if (state_aware_mode) {
if (state_ids_count == 0) {
PFATAL("No server states have been detected. Server responses are likely empty!");
}
while (1) {
u8 skipped_fuzz;struct queue_entry *selected_seed = NULL;
while(!selected_seed || selected_seed->region_count == 0) {
target_state_id = choose_target_state(state_selection_algo);/* Update favorites based on the selected state */
cull_queue();/* Update number of times a state has been selected for targeted fuzzing */
khint_t k = kh_get(hms, khms_states, target_state_id);
if (k != kh_end(khms_states)) {
kh_val(khms_states, k)->selected_times++;
}selected_seed = choose_seed(target_state_id, seed_selection_algo);
}
if (selected_seed) {
if (!queue_cur) {
current_entry = 0;
cur_skipped_paths = 0;
queue_cur = queue;
queue_cycle++;
}
while (queue_cur != selected_seed) {
queue_cur = queue_cur->next;
current_entry++;
if (!queue_cur) {
current_entry = 0;
cur_skipped_paths = 0;
queue_cur = queue;
queue_cycle++;
}
}
}
skipped_fuzz = fuzz_one(use_argv);
if (!stop_soon && sync_id && !skipped_fuzz) {
if (!(sync_interval_cnt++ % SYNC_INTERVAL))
sync_fuzzers(use_argv);
}
if (!stop_soon && exit_1) stop_soon = 2;
if (stop_soon) break;
queue_cur = queue_cur->next;
current_entry++;
unsigned int choose_target_state(u8 mode) {
u32 result = 0;
switch (mode) {
case RANDOM_SELECTION: //Random state selection
selected_state_index = UR(state_ids_count);
result = state_ids[selected_state_index];
break;
case ROUND_ROBIN: //Round-robin state selection
result = state_ids[selected_state_index];
selected_state_index++;
if (selected_state_index == state_ids_count) selected_state_index = 0;
break;
case FAVOR:
/* Do ROUND_ROBIN for a few cycles to get enough statistical information*/
if (state_cycles < 5) {
result = state_ids[selected_state_index];
selected_state_index++;
if (selected_state_index == state_ids_count) {
selected_state_index = 0;
state_cycles++;
}
break;
}
result = update_scores_and_select_next_state(FAVOR);
break;
default:
break;
}
return result;
}
typedef struct {
u32 id; /* 状态id */
u8 is_covered; /* 状态是否被覆盖 */
u32 paths; /* 此状态经过的所有路径 */
u32 paths_discovered; /* 由此状态新发现的路径*/
u32 selected_times; /* 此状态被选择过的次数*/
u32 fuzzs; /* fuzz总次数 */
u32 score; /* 状态分数 */
u32 selected_seed_index; /* 最近选择过此状态的种子序号*/
void **seeds; /* 保存了所有能到达此状态的种子* */
u32 seeds_count; /* 能到达此状态的种子数量 */
} state_info_t;
u32 update_scores_and_select_next_state(u8 mode) {
u32 result = 0, i;
if (state_ids_count == 0) return 0;
u32 *state_scores = NULL;
state_scores = (u32 *)ck_alloc(state_ids_count * sizeof(u32));
if (!state_scores) PFATAL("Cannot allocate memory for state_scores");
khint_t k;
state_info_t *state;
//Update the states' score
for(i = 0; i < state_ids_count; i++) {
u32 state_id = state_ids[i];
k = kh_get(hms, khms_states, state_id);
if (k != kh_end(khms_states)) {
state = kh_val(khms_states, k);
switch(mode) {
case FAVOR:
state->score = ceil(1000 * pow(2, -log10(log10(state->fuzzs + 1) * state->selected_times + 1)) * pow(2, log(state->paths_discovered + 1)));
break;
//other cases are reserved
}
if (i == 0) {
state_scores[i] = state->score;
} else {
state_scores[i] = state_scores[i-1] + state->score;
}
}
}
u32 randV = UR(state_scores[state_ids_count - 1]);
u32 idx = index_search(state_scores, state_ids_count, randV);
result = state_ids[idx];
if (state_scores) ck_free(state_scores);
return result;
}
khint_t k;
state_info_t *state;
struct queue_entry *result = NULL;
k = kh_get(hms, khms_states, target_state_id);
if (k != kh_end(khms_states)) {
state = kh_val(khms_states, k);
if (state->seeds_count == 0) return NULL;
case RANDOM_SELECTION: //Random seed selection
state->selected_seed_index = UR(state->seeds_count);
result = state->seeds[state->selected_seed_index];
break;
case ROUND_ROBIN: //Round-robin seed selection
result = state->seeds[state->selected_seed_index];
state->selected_seed_index++;
if (state->selected_seed_index == state->seeds_count) state->selected_seed_index = 0;
break;
if (state->seeds_count > 10) {
//Do seed selection similar to AFL + take into account state-aware information
//e.g., was_fuzzed information becomes state-aware
u32 passed_cycles = 0;
while (passed_cycles < 5) {
result = state->seeds[state->selected_seed_index];
if (state->selected_seed_index + 1 == state->seeds_count) {
state->selected_seed_index = 0;
passed_cycles++;
} else state->selected_seed_index++;
//Skip this seed with high probability if it is neither an initial seed nor a seed generated while the
//current target_state_id was targeted
if (result->generating_state_id != target_state_id && !result->is_initial_seed && UR(100) < 90) continue;
u32 target_state_index = get_state_index(target_state_id);
if (pending_favored) {
/* If we have any favored, non-fuzzed new arrivals in the queue,
possibly skip to them at the expense of already-fuzzed or non-favored
cases. */
if (((was_fuzzed_map[target_state_index][result->index] == 1) || !result->favored) && UR(100) < SKIP_TO_NEW_PROB) continue;
/* Otherwise, this seed is selected */
break;
} else if (!result->favored && queued_paths > 10) {
/* Otherwise, still possibly skip non-favored cases, albeit less often.
The odds of skipping stuff are higher for already-fuzzed inputs and
lower for never-fuzzed entries. */
if (queue_cycle > 1 && (was_fuzzed_map[target_state_index][result->index] == 0)) {
if (UR(100) < SKIP_NFAV_NEW_PROB) continue;
} else {
if (UR(100) < SKIP_NFAV_OLD_PROB) continue;
}
/* Otherwise, this seed is selected */
break;
}
}
}
看雪ID:Ayakaaa
https://bbs.kanxue.com/user-home-954038.htm
# 往期推荐
球分享
球点赞
球在看