首页 -> 安全研究
安全研究
安全漏洞
Asterisk IAX2远程内存破坏漏洞
发布日期:2006-06-06
更新日期:2006-06-09
受影响系统:
Asterisk Asterisk <= 1.2.8不受影响系统:
Asterisk Asterisk <= 1.0.10
Asterisk Asterisk 1.2.9描述:
Asterisk Asterisk 1.0.11
BUGTRAQ ID: 18295
CVE(CAN) ID: CVE-2006-2898
Asterisk是开放源码的软件PBX,支持各种VoIP协议和设备。
Asterisk的IAX消息解析的实现上存在内存破坏漏洞,远程攻击者可能利用此漏洞在服务器上执行任意指令。
IAX协议的所有通讯都依赖于4569/UDP端口。协议使用15位的标识号在同一UDP端口上多路传输几个IAX2流。IAX2消息被称为帧,Asterisk源码包的iax2.h头文件中定义了几个基本的帧类型。
IAX2完整帧使用如下的12字节首部:
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) */
unsigned char type; /* Frame type */
unsigned char csub; /* Compressed subclass */
unsigned char iedata[0];
} __attribute__ ((__packed__));
IAX2的mini-frame使用4字节的首部:
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];
} __attribute__ ((__packed__));
以下6字节的报文首部用于支持视频帧:
struct ast_iax2_video_hdr {
unsigned short zeros; /* Zeros field -- must be zero */
unsigned short callno; /* Video call number */
unsigned short ts; /* Timestamp and mark if present */
unsigned char data[0];
} __attribute__ ((__packed__));
Asterisk的channels/chan_iax2.c文件中实现的socket_read()函数从网络读取IAX2报文。
以下节选自该文件的revision 29849:
static int socket_read(int *id, int fd, short events, void *cbdata)
{
struct sockaddr_in sin;
int res;
int updatehistory=1;
int new = NEW_PREVENT;
unsigned char buf[4096];
void *ptr;
socklen_t len = sizeof(sin);
...
res = recvfrom(fd, buf, sizeof(buf), 0,(struct sockaddr *) &sin,
&len);
if (res < 0) {
if (errno != ECONNREFUSED)
ast_log(LOG_WARNING, "Error: %s\n",
strerror(errno));
handle_error();
return 1;
}
if(test_losspct) { /* simulate random loss condition */
if( (100.0*rand()/(RAND_MAX+1.0)) < test_losspct)
return 1;
}
[A] if (res < sizeof(struct ast_iax2_mini_hdr)) {
ast_log(LOG_WARNING,
"midget packet received (%d of %d min)\n", res,
(int)sizeof(struct ast_iax2_mini_hdr));
return 1;
}
if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
/* This is a video frame, get call number */
fr->callno = find_callno(ntohs(vh->callno) & ~0x8000,
dcallno, &sin, new,1, fd);
[B] minivid = 1;
} else if (meta->zeros == 0) {
....
在[A]执行了长度检查以确保从网络读取的字节数不少于完整的mini frame首部所需的字节数。如果通过了这个检查,就会进一步检查判断报文是否属于[B]的启用视频的会话。由于IAX2 mini-frame所需的首部长度小于视频帧的首部长度,因此Asterisk不会拒绝大于等于4字节但小于6字节的截短了的视频帧。
之后的视频帧处理是由以下执行流完成的:
...
} else if (minivid) {
f.frametype = AST_FRAME_VIDEO;
if (iaxs[fr->callno]->videoformat > 0)
f.subclass = iaxs[fr->callno]->videoformat
| (ntohs(vh->ts) & 0x8000 ? 1: 0);
else {
ast_log(LOG_WARNING,
"Received mini frame before first full video frame\n ");
iax2_vnak(fr->callno);
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
[C] f.datalen = res - sizeof(struct ast_iax2_video_hdr);
if (f.datalen)
f.data = buf + sizeof(struct ast_iax2_video_hdr);
else
f.data = NULL;
...
}
...
[D] iax_frame_wrap(fr, &f)
在[C]处视频负载的长度是通过从网络读取的字节数(recvfrom()调用的返回代码)减去视频首部(视频首部中所需要的字节数)的方法来计算的,因此如果收到了截短的视频帧,这个减法的结果可能是负数,存储在f.datalen,而f.data会指向接收报文边界以外的内存。
之后在[D]调用了iax2-parser.c中实现的iax_frame_wrap()函数:
void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
{
fr->af.frametype = f->frametype;
fr->af.subclass = f->subclass;
fr->af.mallocd = 0; /* Our frame is static relative to the
container */
fr->af.datalen = f->datalen;
fr->af.samples = f->samples;
fr->af.offset = AST_FRIENDLY_OFFSET;
fr->af.src = f->src;
fr->af.delivery.tv_sec = 0;
fr->af.delivery.tv_usec = 0;
fr->af.data = fr->afdata;
if (fr->af.datalen) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* We need to byte-swap slinear samples from network
byte order */
if ((fr->af.frametype == AST_FRAME_VOICE) &&
(fr->af.subclass ==AST_FORMAT_SLINEAR)) {
ast_swapcopy_samples(fr->af.data, f->data,
fr->af.samples);
} else
#endif
[E] memcpy(fr->af.data, f->data, fr->af.datalen);
}
}
[E]处的memcpy()会接收指向从网络读取报文以外内存的指针做为其第二个参数,负数做为第三个参数,导致缓冲区溢出。攻击者可以利用这个漏洞在Asterisk的系统上执行任意代码。
<*来源:Damian Saura
Alejandro Lozanoff
Eduardo Koch
Norberto Kueffner
Steve K
Ivan Arce
链接:http://marc.theaimsgroup.com/?l=bugtraq&m=114990618632486&w=2
http://secunia.com/advisories/20497/print/
*>
建议:
临时解决方法:
* 在边界阻断到4569/udp端口的入站报文。
厂商补丁:
Asterisk
--------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
* Asterisk asterisk-1.0.11.tar.gz
http://ftp.digium.com/pub/telephony/asterisk/releases/asterisk-1.0.11.tar.gz
* Asterisk asterisk-1.2.9.tar.gz
http://ftp.digium.com/pub/telephony/asterisk/releases/asterisk-1.2.9.tar.gz
浏览次数:3594
严重程度:0(网友投票)
绿盟科技给您安全的保障