CVE:CVE-2006-2923
CNNVD:CNNVD-200606-196
IAXClient是用于实现IAX2 VoIP协议的开放源码函数库。
IAXClient对IAX消息的处理上存在内存破坏漏洞，远程攻击者可能利用此漏洞在服务器上执行任意指令。
IAX消息被称为帧。iaxclient/lib/libiax2/src/iax2.h文件中定义了两个帧类型，分别是IAX完整帧(full frame)和IAX小型帧(mini-frame)。
/* Full frames are always delivered reliably */
struct ast_iax2_full_hdr {
unsigned short scallno; /* Source call number -- high bit must be 1 */
unsigned short dcallno; /* Destination call number -- high bit is 1 if
retransmission */
unsigned int ts; /* 32-bit timestamp in milliseconds (from 1st
transmission) */
unsigned char oseqno; /* Packet number (outgoing) */
unsigned char iseqno; /* Packet number (next incoming expected) */
char type; /* Frame type */
unsigned char csub; /* Compressed subclass */
unsigned char iedata[0];
} __PACKED;
/* Mini header is used only for voice frames -- delivered unreliably */
struct ast_iax2_mini_hdr {
unsigned short callno; /* Source call number -- high bit must be 0, rest
must be non-zero */
unsigned short ts; /* 16-bit Timestamp (high 16 bits from last
ast_iax2_full_hdr) */
/* Frametype implicitly VOICE_FRAME */
/* subclass implicit from last ast_iax2_full_hdr */
unsigned char data[0];
} __PACKED;
解析通过网络接收的IAX报文是由iaxclient/lib/libiax2/src/iax.c中实现的iax_net_process()函数完成的。以下截取自该文件的revision 536：
struct iax_event *iax_net_process(unsigned char *buf, int len, struct
sockaddr_in *sin)
{
struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf;
struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)buf;
struct iax_session *session;
if (ntohs(fh->scallno)  & IAX_FLAG_FULL) {
/* Full size header */
[A] if (len < sizeof(struct ast_iax2_full_hdr)) {
DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
}
/* We have a full header, process appropriately */
session = iax_find_session(sin, ntohs(fh->scallno)  & ~IAX_FLAG_FULL,
ntohs(fh->dcallno)  & ~IAX_FLAG_RETRANS, 1);
if (!session)
session = iax_txcnt_session(fh, len-sizeof(struct ast_iax2_full_hdr),
sin, ntohs(fh->scallno)  & ~IAX_FLAG_FULL, ntohs(fh->dcallno)  &
~IAX_FLAG_RETRANS);
if (session)
return iax_header_to_event(session, fh, len - sizeof(struct
ast_iax2_full_hdr), sin);
DEBU(G "No session?\n");
return NULL;
} else {
[B] if (len < sizeof(struct ast_iax2_mini_hdr)) {
DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
}
/* Miniature, voice frame */
session = iax_find_session(sin, ntohs(fh->scallno), 0, 0);
if (session)
return iax_miniheader_to_event(session, mh, len - sizeof(struct
ast_iax2_mini_hdr));
DEBU(G "No session?\n");
return NULL;
}
}
len参数是从同一文件中实现的iax_net_read()函数接收到的，其值设置为recvfrom(2)函数调用的返回值，也就是从网络读取的字节数。buf参数是指向栈中分配的固定大小缓冲区的指针，数据从iax_net_read()函数读取。
函数在[A]和[B]执行了长度检查以确保所接收到的报文不是截短了的full-frame或mini-frame，但在输出错误消息后仍可能出现过小的报文，这就导致了两个可利用的漏洞。
IAX2截短full-frame漏洞
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在[A]的情况下full-frame报文是由以下执行流处理的：
iax_net_read()
iax_net_process()
iax_find_session()
iax_txcnt_session()
iax_header_to_event()
同一文件中也实现了iax_txcnt_session：
static struct iax_session *iax_txcnt_session(struct ast_iax2_full_hdr
*fh, int datalen,
struct sockaddr_in *sin, short callno, short dcallno)
{
int subclass = uncompress_subclass(fh->csub);
unsigned char buf[ 65536 ]; /* allocated on stack with same size asiax_net_read() */
struct iax_ies ies;
struct iax_session *cur;
if ((fh->type != AST_FRAME_IAX) || (subclass != IAX_COMMAND_TXCNT) ||
(!datalen)) {
return NULL; /* special handling for TXCNT only */
}
[C] memcpy(buf, fh->iedata, datalen); /* prepare local buf for
iax_parse_ies() */
if (iax_parse_ies( &ies, buf, datalen)) {
return NULL; /* Unable to parse IE's */
}
...
datalen参数接收iax_net_process()传送的值，其计算方法为datalen = len-sizeof(struct ast_iax2_full_hdr)。如果full frame报文是从网络读取的话，该值就可能小于0。
然后在[C]使用了负值datalen的memcpy就会在栈中固定大小的缓冲区buf触发溢出。攻击者可以通过创建11字节长的UDP报文触发这个漏洞，执行任意代码。 
由于使用了负数长度参数的malloc(2)、memset(2)和memcpy(2)组合，iax_header_to_event()函数也存在类似问题，在这种情况下是堆溢出。
IAX2截短mini-frame漏洞
~~~~
solution:Upgrade loudhush loudhush to a higher version than 1.3.6,and avoid the version 1.3.6