初始化
首先定义一些变量,likely_buggy
标志服务器是否可能出现 crash。
如果存在清除脚本,则执行,一般用来清除执行服务端所产生的痕迹。
等待服务器初始化:
清除缓冲区并充值缓冲区大小:
创建 TCP/UDP 套接字:
设置超时时间,这里的 socket_timeout_usecs
默认为 1000 也就是 1000us=1ms,按照作者注释,不设置的话,如果服务器在处理完所有请求后仍然处于活动状态则会导致巨大延迟。
设置目标服务器的端口:
设置本地测试端的端口。有些服务(例如 Kamailio SIP)只会发送给特定的端口,也正因如此,AFLNet 提供了 -l
参数指定端口。
连接服务端,如果没有连接上则等待一段事件后多次尝试:
发送数据
首先接受一次数据,这是为了处理刚连上服务端的时候服务端发来的一些消息,如果出现问题则会跳转到 HANDLE_RESPONSES。
循环发送数据
接下来循环发送保存在 kl_messages
中的数据。一些变量的含义:
messages_sent
:已发送的消息数量
kl_messages
:保持待发送消息的链表
在接收前重置 [[00-notes/00-fuzz/AFLNet/source-code/afl-fuzz.c/aflnet-specific-vars#response_bytes|response_bytes
]]。
如果没发完报文还是跳到 HANDLE_RESPONSES
一切正常后,从服务器接收数据并跳到 HANDLE_RESPONSES,这里还保存了上一个返回的 buf_size,用于后续的判断:
接下来将 [[00-notes/00-fuzz/AFLNet/source-code/afl-fuzz.c/aflnet-specific-vars#response_bytes|response_bytes
]] 的最后一个元素更新为返回的 buf 的大小。
这里用到了上文保存的 prev_buf_size
,如果执行前后 buf_size 没有变化,则可能是出现了 crash,将 likely_buggy
设置为 1(但实际上如果进入了 403 等情况也会相同吧,所以这里是 likely_buggy
)。
HANDLE_RESPONSES
进行一次接收,可能是为了避免服务端反应慢导致一些数据没收到的情况,然后像上文那样更新 response_bytes
。
接下来等待服务端执行完毕,首先将 session_virgin_bits
置为 1,然后不断执行 [[00-notes/00-fuzz/afl/source-code/afl-fuzz.c/has_new_bits|has_new_bits
]] 函数。因为上一步全
结束阶段
如果看上去 crash 的话就直接返回 0,否则才去 kill 它(我觉得这里可以判断一下这个 pid 是否存在,存在的话再 kill 更好吧)
参考资料