UDP通信程序的fuzz思路与CVE-2018-18066分析
字数 1404 2025-08-24 16:48:16
UDP通信程序的Fuzz思路与CVE-2018-18066分析
前言
随着网络交互程序越来越多,传统fuzz工具如afl-fuzz对网络协议支持有限。本文介绍如何通过修改net-snmp源码,将其UDP通信转换为stdin/stdout方式,使afl-fuzz能够有效进行fuzz测试,并分析发现的CVE-2018-18066漏洞。
环境准备
net-snmp编译安装
使用ASAN和afl-clang-fast编译器进行编译:
CXX=afl-clang-fast++ CC=afl-clang-fast ./configure --prefix=/root/0524/mortysnmp
AFL_USE_ASAN=1 make -j4
make install
启动snmpd服务监听1024端口:
./snmpd -f 127.0.0.1:1024
测试UDP通信:
echo 'hellotest' > /dev/udp/127.0.0.1/1024
程序流程分析
SNMP解析流程
通过动态调试(gdb)和静态分析,确定SNMP解析主要流程:
snmpd.c: main(int argc, char *argv[])snmpd.c: receive()snmp_api.c: snmp_read2(&readfds)snmp_api.c: snmp_sess_read2((void *) slp, fdset)snmp_api.c: rc = _sess_read(sessp, fdset)snmp_api.c: rc = _sess_process_packet(sessp, sp, isp, transport, opaque, olength, rxbuf, length)snmp_api.c: ret = snmp_parse(sessp, sp, pdu, packetptr, length)snmp_api.c: rc = _snmp_parse(sessp, pss, pdu, data, length)
请求包验证
在_sess_process_packet函数设置断点,确认packetptr指向接收到的UDP数据包内容,与网络抓包数据一致。
UDP通信转stdin/stdout实现
修改思路
- 在监听端口后添加发送socket请求的代码
- 通过stdin控制socket请求内容
- 修改程序在解析完成后立即退出
具体实现
- 添加UDP发送代码:
在init_master_agent函数后添加:
int mortys = 0;
int n = 0;
int reuse = 1;
struct sockaddr_in srv;
char buf[256] = {0};
bzero(&srv, sizeof(srv));
srv.sin_family = PF_INET;
srv.sin_addr.s_addr = inet_addr("127.0.0.1");
srv.sin_port = htons(1024);
/* 创建UDP套接字 */
s = socket(AF_INET, SOCK_DGRAM, 0);
memset(buf, 0, 256);
/* 从stdin读取用户输入到buf中 */
fgets(buf, 256, stdin);
/* 通过套接字s向服务器发送数据 */
if ((n = sendto(mortys, buf, strlen(buf), 0, (struct sockaddr *) &srv, sizeof(struct sockaddr))) < 0) {
perror("sendto");
return -1;
} else {
printf("send to len %d:%s\n", n, buf);
}
- 修改请求包内容:
在_sess_read函数中替换请求包内容为stdin输入。
- 添加程序退出点:
在receive和_snmp_parse函数中添加exit(0),使程序在完成SNMP解析后立即退出。
重新编译
make clean
AFL_USE_ASAN=1 make -j4
make install
功能验证
修改后程序可以直接通过stdin输入测试数据,无需网络发包:
echo "测试数据" | ./snmpd
CVE-2018-18066漏洞分析
漏洞描述
Net-SNMP 5.8之前版本存在错误的SNMP解析方式,可导致DoS漏洞。
漏洞触发流程
- 解析函数从
_sess_process_packet开始,packetptr指向请求包,length为包长度 - 解析后的内容通过
pdu对象传入snmp_oid_compare函数 - 执行到
if (*(name1) != *(name2))时,r14寄存器为0 - 执行
mov r15,QWORD PTR [r14]导致空指针异常
根本原因
SNMP OID比较函数未正确处理空指针情况,当接收到特定格式的恶意数据包时,会导致空指针解引用,引发程序崩溃。