Tuesday, October 25, 2011

snmp_bot

snmp_bot is a library for botloader. Instead of attacking a target snmp_bot gathers data from it. It works best when the data-gathering and the attacking are carried out on separate networks:

Configuring snmp_bot

To configure snmp_bot you need to specify an option-string in the conf file which you feed to botloader. Because data-gathering bots behave differently from attack bots the name of snmp_bot is prefixed with '#':

#snmp_bot 1 debug=1 time=120 oids=inOctets:.1.3.6.1.4.1.8072.2.6.1.1.0,droppedOctets:.1.3.6.1.4.1.8072.2.6.1.2.0,outOctets:.1.3.6.1.4.1.8072.2.6.1.3.0,cpuLoad1Min:.1.3.6.1.4.1.8072.2.6.1.4.0,userCPU%:.1.3.6.1.4.1.8072.2.6.1.5.0,systemCPU%:.1.3.6.1.4.1.8072.2.6.1.6.0,realMemoryFree%:.1.3.6.1.4.1.8072.2.6.1.7.0,totalMemoryFree%:.1.3.6.1.4.1.8072.2.6.1.8.0 dest_ip=192.168.200.68

This must all be on one line, so it's a bit difficult to edit. The snmp_oids are specified via the oids option. This consists of a comma-separated list of oids, with an optional column-heading separated by a colon. So the oid value "droppedOctets:.1.3.6.1.4.1.8072.2.6.1.2.0" means "monitor the oid .1.3.6.1.4.1.8072.2.6.1.2.0" on the target and write the values to a file with the heading "droppedOctets". The interval for sampling the oid value is set to 5 seconds, but you can change this when invoking botloader on the commandline:

sudo botloader -c snmp_bot.conf -i en0 -t 10

This means that the sampling interval should be 10 seconds instead of 5.

Other values

Botloader itself takes charge of gathering data from any data bots it is asked to monitor. But it also gathers sent and received counts from the attack bots and adds that to the log. So you will find columns "sent" and "rcvd" also in the output.

The default output file is called "data.dat". If you rename this as "something.txt" you can load it into Excel or OpenOffice spreadsheet as CSV format, using tabs as delimters. Then you can see the table of values properly:

Sunday, August 7, 2011

Broken pipe on write

This one puzzled me for a bit. I opened a socket, bound it to a local interface alias address, called connect to a remote machine. Everything was fine. No errors, errno = 0. Then I called write on the socket and it says: "broken pipe". It seems that the cause was that I forgot to set the family for the call to connect:

struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( atoi(serv) );
if ( !inet_pton(AF_INET, host, &servaddr.sin_addr) )
{
 printf("inet_pton failed\n");
 rc = -1;
}
else if ( connect(fd,(const struct sockaddr *)&servaddr, 
    sizeof(servaddr)) == 0 )
{
    printf("Connected\n");
    // return connected socket
    rc = fd;
}

So I thought I'd file this one for reference, in case I get it again. It's amazing how a simple typo can get you into so much trouble.

Sunday, November 7, 2010

Getting/Setting the netmask in Linux/BSD

Recently I have been wrestling with a method for generating multiple aliases for one interface, as in the last post. Part of this was finding suitable ip-addresses to act as aliases. My first idea was to choose free ip-addresses on the local subnet, depending on how big it was, then pinging all possible addresses to find out which ones were already taken. This turned out much more complex than I had thought, unreliable and slow.

Then I had the idea of just expanding the interface's netmask up a level, ignoring all the addresses of the existing subnet without testing them, and generating alias ips that couldn't possibly conflict with any already on the network. To do that I needed to get and set the current netmask programmatically. I didn't find much on the setting (you won't find it in Steven's book, for example). So I wrote my own two routines get_netmask and set_netmask and put them into an example program that even works on BSD:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <string.h>

/**
 * @param skfd an open socket
 * @param intf the interface name, e.g. eth0
 * @return the netmask as a string
 */
char *get_netmask( int skfd, char *intf )
{
    struct ifreq ifr;
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy( ifr.ifr_name, intf, IFNAMSIZ-1 );
    if ( ioctl(skfd,SIOCGIFNETMASK,&ifr) == -1 )
    {
        printf("could not read interface %s\n",intf);
        exit( 0 );
    }
    /* display result */
    return inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
}
/**
 * @param skfd an open socket
 * @param intf the interface name, e.g. eth0
 * @param newmask the new mask a a string e.g. "255.255.0.0"
 */
void set_netmask( int skfd, char *intf, char *newmask )
{
    struct ifreq ifr;
    unsigned int dst;
    struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
    memset(&ifr, 0, sizeof(ifr));
    sin->sin_family = AF_INET;
    if ( !inet_pton(AF_INET, newmask, &sin->sin_addr) )
    {
        printf("failed to convert netmask\n");
        exit( 0 );
    }
    strncpy( ifr.ifr_name, intf, IFNAMSIZ-1 );
    if ( ioctl(skfd,SIOCSIFNETMASK,&ifr) == -1 )
    {
        printf("could not read interface %s\n",intf);
        exit( 0 );
    }
}
/**
 * main entry routine
 * accepts 2 arguments: the interface name and the new netmask
 * e.g. ./intf eth0 255.255.0.0
 */
int main( int argc, char **argv )
{
    char *str;
    int skfd = socket( AF_INET, SOCK_DGRAM, 0);
    if ( skfd == -1 )
    {
        printf("Couldn't open socket\n");
        exit(0);
    }
    printf("netmask was: %s\n", get_netmask(skfd,argv[1]) );
    set_netmask( skfd, argv[1], argv[2] );
    printf("netmask is now: %s\n", get_netmask(skfd,argv[1]) );
    close( skfd );
    return 0;
}

Friday, October 8, 2010

Programmatic interface alias creation in Linux

In *nix you can create an alias for an interface. So for my ethernet card residing at eth0, whose address is normally 192.168.100.4, I can also create a large number of aliases, for example, 192.168.100.45 for interface eth0:45. I have to give it a unique name not more than 16 bytes long, or it won't be able to distinguish it from my normal interface. Now why would I want to do that? Because, in my case I want to define hundreds or thousands of aliased addresses on my machine, so I can bind on to each of them and send ip-packets from those aliased addresses to a server. That way, I can simulate a DDoS attack of 200 or 5000 machines with just one machine. That's cool. But how do you do it?

You're supposed to use ifconfig, a commandline tool, but since I needed speed I wanted to be able to do it programmatically. How? On BSD you can call ioctl with SIOCAIFADDR to set the ip-address of an interface. But on Linux you have to use SIOCSIFADDR instead. Just give it a unique name and call ioctl with that argument and you're done. Since I didn't see any sample code for this when I Googled, I thought I'd save other people's time by putting this up. It copies the default netmask and broadcast address from the default interface, so you don't have to set these. You'll need to be supervisor to execute it.

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>

int skfd;
int set_ip_using(const char *name, int c, unsigned long ip)
{
    struct ifreq ifr;
    struct sockaddr_in sin;

    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = ip;
    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
    if (ioctl(skfd, c, &ifr) < 0)
 {
  printf("failed to set ip-address\n");
  exit(0);
    }
 return 0;
}
int main ( int argc, char **argv )
{
 char *ip_address=NULL;
 char *interface;
 if ( argc==3 )
 {
  struct sockaddr_in sin;
  unsigned long ip;
  ip_address=argv[2];
  interface = argv[1];
  skfd = socket( AF_INET, SOCK_DGRAM, 0);
  if ( skfd == -1 )
  {
   printf("Couldn't open socket\n");
   exit(0);
  }
  inet_pton( AF_INET, ip_address, &sin );
  memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));  
  set_ip_using( interface,SIOCSIFADDR,ip );
  close( skfd );
 }
 else
  printf("usage: setip <interface-name> <ip-address>\n");
}

Tuesday, September 28, 2010

Two-way dynamic linking in C

Building a dynamic library (or shared object lib) on Linux is easy. All you do is compile your code with the -fPIC or -fpic flags then use the -shared flag for the link-step:

gcc -fPIC foo.c -shared -o foo.so

Then you can load the dynamic library in your main program by using dl_open and dl_sym to get any global symbol from the library.

But what if you also want your shared object library to link with symbols in the main program? This might be necessary, for example, if the dynamic module wanted to obtain a key from the main program. It would have to call a routine in main just as main is calling routines in the library. In this case you must instruct the main program also to export its symbols during linking:

gcc main.c -ldl -rdynamic -o main

Then, main, when it loads the shared object lib foo, will enable both foo to call routines in main, and main to call routines in foo.

Here's main.c. You can use the last command above to compile it

#include <dlfcn.h>
#include <stdio.h>
int bar()
{
 printf("dynamic lib called bar\n");
 return 0;
}
int main( int argc, char **argv )
{
 void *handle;
 handle = dlopen( "./foo.so", RTLD_GLOBAL|RTLD_LAZY );
 if ( handle != NULL )
 {
  int (*r)(void);
  int res;
  *(void **)(&r) = dlsym(handle, "foo");
  res = (*r)();
  printf("foo returned %d\n",res );
 }
 else
  printf("failed to open foo.so\n");
}

And foo.c. This compiles with the first command above:

#include <stdio.h>
extern int bar();
int foo()
{
 printf("called foo inside lib\n");
 bar();
 return 0;
}

Then run it by calling main:

./main
called foo inside lib
dynamic lib called bar
foo returned 0

Wednesday, May 19, 2010

Capturing packets from an Interface in a MIB

I had to use pcap to capture packets arriving at a particular interface. For that the snmp daemon needs to run as root. You can configure the options for starting up the snmpd program in /etc/default/snmpd. What's not cool, though, is trying to start it up and shut it down. It seems that nanosleep on Linux doesn't work, or rather it only works with a resolution of 1 second. No matter how many nanoseconds you specify nanosleep doesn't sleep until you fill in the tv_sec field. This is, however, more annoying than a show-stopper. I can now start packet capture via pcap_loop and kill it with pcap_breakloop. Stopping takes a few seconds but mostly works. So now we have a MIB that actually detects DDoS attacks!!!

Thursday, May 13, 2010

Average CPU usage for a terminating process

Someone asked me if we can easily compute the average CPU usage of a particular program over its lifetime when the program is scheduled to terminate at some point in the future. At that time it should print out the result. Here's what I came up with:

#!/bin/bash
# get average CPU for a process
total=0
times=0
pid=`pgrep "$1"`
while [ -n "$pid" ]; do
temp=`ps -eo pid,pcpu | grep $pid | awk '{print $2}'`
total=`echo "scale=2;$total+$temp" | bc`
times=$[$times+1]
sleep 1
pid=`pgrep "$1"`
done
average=`echo "scale=2;$total/$times" | bc`
echo "Average cpu usage for $1 is: $average"

To run it give it an argument, which should be the name of the process or part or all of the command that launched it, and background the process, e.g.:

./perprocesscpu.sh "java myprogram" &

So, when "java myprogram" terminates, this script tells me its average CPU usage.