Showing posts with label pack. Show all posts
Showing posts with label pack. Show all posts

Thursday, January 8, 2009

More Perl Security Through Obfuscation For Linux and Unix

Hey there,

Today's post is going to be a bit on the short side (like, under 5000 words ;) as I'm up to my neck in the work I do to feed my family :) This is also all in fun. I make no claims that anything I write in these types of posts should stand as a replacement for real security measures :)

As you may recall, we've done a number of posts, previous to this one, dealing with security through obfuscation. The basic premise of all of them being that, if you can make the risk of destroying your code, simply by changing it, just one more step closer to probable, no one will ever mess with your code... probably ;)

Today, we're going to be looking at a simple script that we'll feed through another simple script to generate our "stored code," and then one final script to process that code and execute it. Simple enough :)

First things first: The original script (This is the script we don't want people to mess with. It may seem to not do much and be rather harmless, but... it actually doesn't do much and is pretty harmless ;)

host # cat simple.pl
#!/usr/bin/perl

print "Goodbye Cruel World\n";
$counter = 1;
while ( $counter < 4 ) {
print "Goodbye ";
$counter++;
}
print "\n";
exit(0);


Now, since you've seen the code and the gravity of keeping it secure has just slammed on top of you like a Wile E. Coyote Acme Anvil, we'll convert our ".pl" (Perl) script into a ".bs" (bastioned source... better than what I had in mind originally ;) script ;). We'll do this by running it through another simple script that unpacks the code into Hex and then unpacks the Hex into Binary:

host # ./bs-in.pl simple.pl
host # cat simple.bs
0100110011001100010011001000110001001100011001101110110010101100111011001100110011101100010011000100110001100110011011000100110001101100100111000110110010100110010011000110011011101100000011000110110010101100111011000100110001101100110001100000110010000110000011001000011011101100000011001110110001001100011011001001110001101100101001101110110000101100010011000000110001001100010011000010110011101100011011000110011001101100011001100110110000101100011011000100110011101100100111000110110010101100010011000000110000101100110011001110110001001100111011001010110001101100101011000110110011000110010011000000110010101100111011000110110001100110111011000100110001101100110001100110110000101100101011001100011001101100101001100100110001001100110011000100011000001100100001100100110000101100011011001100110001101100011001101110110010101100011011001010011011101100001011000110110010101100111011000100110001001100000011001100110000100110010011000000110011001100100011001100110001000110000011001000011011101100111011000110110000011100011011001001110001101100110001100110110010101100010011000000110001001100000111000100110000001100010011000010110001101100110011000110110001100110111011001010110001101100101001101110110000101100011011001010110011101100010011000100110000001100110011001100011001001100000011001100110000101100010011000000110001001100100111000000110010011100111011000100011000001100100001100000110010011100111011000000110011101100010011000110110010011100011011001010011011101100001011000100110000001100010011000100110000101100111011000110110001100110011011000110011001101100001011000110110001001100111011001001110001101100101011000100110000001100010011000100110011001100010001100000110010000110000011001001110001001100001011000110110011001100011011000110011011101100101011000110110010100110111011000010110001101100101011001110110001001100010011000100011001001100010001101100110001000110000011001000011011101100001001100000110010000110111011000000110011101100010011000110110010011100011011001010011011101100001011000100110000001100010011000100110010101100110001100110110010100110010011000100110011001100010001100000110010000110011011001010110011101100000111000110110010011100111011000010110001001100000111001100110000001100010011001001110011001100010001100000110010000110


And you check that new ".bs" script into CVS separately from your "bs-in.pl" script (which you keep secured by packs of wild dogs ;), and destroy the original "simple.pl" script :)

Now, if you ever need to run your new-fangled script, you'll just process it through another script you've got set aside to parse your ".bs" scripts (permission and ownership protected, so folks can't see how easily you're making things difficult for them, of course) and you get the output you would have gotten if you just ran the regular "simple.pl" script:

host # ./bs-out.pl <simple.bs
Goodbye Cruel World
Goodbye Goodbye Goodbye


If you want, you can modify bs-out.pl to take command line arguments instead of STDIN, or both. You can also modify the execution line in "bs-out.pl" so it will run any executable script fairly simply. For today, this is as good as it gets ;)

Hope you enjoy hash-binary/binary-hash unpacking/packing your "Hello World" scripts (This one came out slightly different since Pink Floyd is playing in the background ;) Both scripts are tagged onto the end of this post.

Cheers,


Creative Commons License


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

#!/usr/bin/perl

#
# bs-in.pl - Usage: bs-in.pl "regular script or program in any language"
#
# 2009 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

local $/;
open(FILE, "<$ARGV[0]");
$simple = <FILE>;
close(FILE);
$simple1 = unpack "H*", $simple;
$simple2 = unpack "b*", $simple1;
$outputfilename = `echo $ARGV[0]|sed 's/\.pl\$/.bs/'`;
open(FILE2, ">>$outputfilename");
print FILE2 "$simple2";
close(FILE2);




Creative Commons License


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

#!/usr/bin/perl

#
# bs-out.pl - Usage: bs-out.pl <YourBSFile.bs
#
# 2009 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

local $/;
$simple = <STDIN>;
$simple1 = pack "b*", $simple;
$simple2 = pack "H*", $simple1;
system("/usr/bin/perl -e '$simple2';");


, Mike




Discover the ClickBank affiliate program that pays 100% commission!



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

Tuesday, March 18, 2008

Using Unpack To Convert Binary Values To Decimal

Hey There,

Today's post may seem like a step back for regular readers, but I like to keep this blog accessible, so I've decided to revisited the Perl unpack function to demonstrate how it can be used in one of its simplest forms on either Linux or Unix. A more advanced example can be found in our previous post on taking a look inside the wtmpx file.

The Perl script we're presenting today only consists of one simple unpack function surrounded by a whole bunch of processing code. If certain parts were modularized, this would make a decent simple function in a greater calculator/conversion script.

Notice that when we use the unpack value to convert a binary number, say:

11101110

to the decimal number:

238

all we're really doing is feeding the value (11101110) to the unpack function and telling it to convert the input using a standard template ("C" in this case - which stands for an unsigned character - octet - value). You'll not that we've actually put "C*" to account for an infinitely variable number of unsigned octet character values. If we didn't do this (Just put "C" instead), the unpack function would only process the first character the script fed it, so our original input:

11101110

would translate to this:

1

So, as you can see, in this simple function - unpack("C*", $binary) - the definition of the predefined template value C can make a huge amount of difference. It can also allow you to be as specific as you need to be. For instance - unpack("CC", $binary) - would produce:

3

from the same input. This can also be written as - unpack("C2", $binary) - which will save you a lot of typing if you want to match exactly 245 C's ;)

Hope you find this script useful and that it helps you to get more into Perl's pack and unpack functions. Once you get past the seeming incomprehensibility of the general statements, it all makes sense :)

Cheers,


Creative Commons License


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

#!/usr/bin/perl

#
# bd - convert binary numbers to decimal
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

print "Binary Number:\t";
chomp ($binary=<stdin>);
@bitvalue = unpack("C*", $binary);
$bitvalue = @bitvalue;
$substring = $bitvalue - 1;
while ($substring ne -1) {
$number = substr($binary, $substring, 1);
$binarray[$substring] = $number;
--$substring;
}
@decarray = reverse(@binarray);
$exponent = 0;
foreach $subscript (@decarray) {
if ($subscript == 1) {
$subscript = 2 ** $exponent;
} elsif ($subscript == 0) {
$subscript = 0;
} else {
print "Are you sure you know what a Binary Number is?\nMaybe you shouldn't be using this...\n";
exit;
}
$exponent++;
}
$decimal = "0";
foreach $integer (@decarray) {
$decimal += $integer;
}
print "Decimal Value:\t$decimal\n";
exit;


, Mike




Sunday, December 16, 2007

Simple Encryption and Decryption For Fun And No Profit

Here's another little fun thing for the weekend. It's based on Perl's pack and unpack functions and is a good introduction to using them for other purposes. It's also a good way to rediscover the fun of "passing notes in class," even though you're older and have a real job now ;)

You can use this script any way you want to; in fact it's written with a few things left out (how you want to deal with shell special characters -- another complete post on its own -- and if you want to expand on it to read and/or write to STDIN/STDOUT so you can pipe one instance to another, even though that defeats the purpose to a certain degree).

Hopefully, it will pique your curiosity about Perl and its ability to compress and convert different data types (I'm using hexadecimal and character here, but the available list is voluminous).

I've included usage points in the comments section of the script, but the basic usage would be:

tranz.pl encode your message here
tranz.pl decode 458616e6b6370264f62702659637964796e6760245865602c496e657870216e6460255e6968702d456e6167656279656
<-- The Hex output from a message encoded with this script.

Enjoy, and have a safe Sunday :)


Creative Commons License


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

#!/usr/bin/perl

#
# 2007 - Mike Golvach - eggi@comcast.net
# Sanitize shell special characters in
# whatever manner you prefer - or just
# backslash them on the command line :)
#
# Sample usage:
# trans.pl encode hi there
# trans.pl encode hi there >FILE
# trans.pl encode `cat FILE`
# trans.pl decode 8696024786562756
# trans.pl decode `cat FILE`
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

$input = $ARGV[0];
shift @ARGV;
$message = join(" ",@ARGV);

if ( $input eq "encode") {
$output=unpack("h*",$message);
@length=$output=~/.{0,256}/g;
print("$output \n");
} elsif ( $input eq "decode" ) {
chomp($message);
$output.=pack"h*",$message;
print "\n$output\n";
} else {
print "Usage: $0 [encode|decode] whatever you want to type\n";
exit(1)
}


, Mike





Thursday, December 6, 2007

Taking a Look Inside Solaris' wtmpx

This is a Bonus Post, for those admins among us who aren't satisfied with the kind of information you can get from Solaris' standard commands that use /var/adm/wtmpx (like "last"). This is in line with the script we're also building up, in this post, to try and determine whether or not users have logged in within an arbitrary period of time and automatically lock up accounts and/or delete them completely based on that information.

I think this is still one post per day; so why am I calling it a Bonus Post? Partially because it was the first thing that came into my mind when I was trying to describe this blog-post and partially because the Perl scriplet that we're going to look at today is made up of constructs and functions that are what they are, and nothing more. I checked around and saw that there are variations on this script on other sites; mostly because there's only one un-convoluted way to do it (Even the argument to pack can't vary when tearing open the wtmpx structure(A32 A4 A32 l s s2 x2 l2 l x20 s A257 x). For that reason, I can only take credit for slapping together these predefined functions in a way that's slightly different than most. Some of it's in the coding and some of it's in what I'm trying to get out of the /var/adm/wtmpx file (nobody else seems to want it). This process is so rigid, I can no more take credit for it than I could take credit for inventing the "while loop" ;)

What we're looking for here is the "year." Yes, the "year." It's one of those things that I've never been able to figure out: Why was it left out of the "last" command? Great confusion can come of trying to pull auditing information and only knowing the months and dates people logged on. The "year" just seems like it should be included by default. I have no answer as to why it's not, but I do have a way for you to get it. Except for the initial command line, I've left out the error checking to save on space.

Note that the parts of the unpacked /var/adm/wtmpx are all the same, as well. We can change the names of the variables, but when you get right down to it, the file is composed of parts, and those parts are parts of a predefined structure. Note that in the below script, I'm looking for a user name and a year, like so:

$wtmpx_username holds the user name variable( I tried to name my variables in this script so that I would be reminded of what they represent later, when I've long since forgotten). Note that if we were coding this in "c" and accessing the actual utmp struct it would be a lot more work to make the variable names more easily memorable. The great thing about Perl is that it mimics the "c" behaviour but is actually only passing you an array of individual variables, so you can call them whatever you want.

$wtmpx_seconds holds the number of seconds since the epoch at which the login occurred. We pass that number to the Perl localtime() function, and it, in turn, can be parsed out to provide the "year!" If you want to read more about using the localtime() function in a script, check out this previous post.

That being said, you can find lots of different things inside /var/adm/wtmpx, like $wtmpx_line_device (usually the tty/pty), which can be compared against the string "system boot" to figure out every time your system has been rebooted. Of course, for the most part, the "last" command, and it's companions, get you all the information you really need. But it's nice to know you can get more specific data if you want it :)

Below; the Bonus Post Perl scriplet, and a promise to dive into understanding the pack and unpack functions in a future post!


Creative Commons License


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

#!/usr/bin/perl

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

if ( $#ARGV != 0 ) {
print "Usage: $0 accountName\n";
exit(1);

$account_name = $ARGV[0];
$recordsize = length(pack("A32 A4 A32 l s s2 x2 l2 l x20 s A257 x",( )));

open(WTMPX,"/var/adm/wtmpx");
while (read(WTMPX,$record,$recordsize)) {
($wtmpx_username,$wtmpx_userid,$wtmpx_line_device,$wtmpx_process_id,$wtmpx_type,$wtmpx_termination_status,$wtmpx_exit_status,$wtmpx_seconds,$wtmpx_useconds,$wtmpx_session,$wtmpx_syslen,$wtmpx_hostname) = unpack($template,$record);
if ($wtmpx_username eq "$account_name"){
print "$account_name ".scalar localtime($wtmpx_seconds)."\n";
}
}


, Mike





Saturday, December 1, 2007

Disabling and Removing Old User Accounts

Depending upon the size of your network, keeping track of user accounts on all of your Unix and Linux boxes can range from fairly simple to unbelievably hard to keep track of. I've noticed on the internet boards that lots of people are looking for the "one" way to semi-automate determining if user accounts need to be disabled, or if they're so old they need to be deleted.

I'm not a believer in the "one" solution theory. One of the things I love about Linux and Unix is, depending on how creative you're willing to be, there are probably 50 or more ways to do anything.

In any event I started looking at this problem, and noticed that almost everyone was using the "finger," "logins" or "last" commands to figure out how long it had been since someone logged in. In some extreme cases, I've even found examples where folks "pack" and "unpack" /var/adm/wtmpx with Perl to get the information. So, I naturally thought: Is it possible to do this without using the system's login-logging facilities?

The more I thought about this, the more I came to understand that both methods had their virtues and their faults. For instance, if /var/adm/wtmpx is missing, a lot of regular system accounting programs won't work. If you corrupt that file and remove /var/adm/lastlog (I'm using Solaris as my model - substitute file locations and names as necessary), "logins," "finger" and "last" don't report correctly unless they're reporting an error. The alternative approach also has its flaws. If, for instance, a user utilizes SSH to run a single command from a remote host using key-based passworless login, that shell won't be interactive and it won't update any shell history files!

Tackling this problem will take more than one post, so we'll start out with the core; treat this as a sort of tutorial on the phases that you go through from scratch to a decent script. Our assumption here will be that we have no access to any of the regular utilities like "last," "finger" and "logins." We'll use Perl to check out all users' .sh_history or .bash_history files (just covering sh, ksh and bash for now) and use the "stat" and "time" functions to determine how long it's been since the user last logged in.

Here's the core of the code, to get started. I've written it so it can be run on its own for now:


Creative Commons License


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

#!/bin/perl

#
# 2007 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
#
# We don't need to check for errors on the command line since
# we won't be accepting any arguments
#

$today=time();

@user_dirs=`awk -F":" '{print \$6}' /etc/passwd`;
foreach $history_file (@user_dirs) {
chomp($history_file);
print "${history_file}: ";
if ( -f "$history_file/.sh_history" ) {
@file_dates=stat("$history_file/.sh_history");
$sh_file_date=$file_dates[8];
} else {
$sh_file_date=0;
}
if ( -f "$history_file/.bash_history" ) {
@file_dates=stat("$history_file/.sh_history");
$bash_file_date=$file_dates[8];
} else {
$bash_file_date=0;
}
if ( $sh_file_date > $bash_file_date ) {
$file_date = $sh_file_date;
} elsif ( $bash_file_date > $sh_file_date ) {
$file_date = $bash_file_date;
} else {
print "Cannot find .bash_history or .sh_history for $history_file. Moving on!\n";
next;
}
$difference=$today - $file_date;
if ( $difference >= 3888000 && $difference < 7776000 ) {
print "User needs to be disabled- ";
print "45 days old or older, but under 90\n";
# YOUR CUSTOM CODE HERE - "passwd -l" would probably suffice"
} elsif ( $difference >= 7776000 ) {
print "User needs to be deleted - ";
print "90 days old or older\n";
# YOUR CUSTOM CODE HERE -
} else {
print "OK\n";
}
}


Within the next post or two, we'll follow up on this, so that we can add functionality to check system files, using system utilities, to verify that our initial information is correct. It's possible that someone just "touch"ed a user's history file and that access time information isn't necessarily correct. Also, as we noted above, folks can be using the host remotely, in a non-interactive shell, and never alter the access time of their history file.

For the time being, this code should be a good start, and something to think about and improve upon. Until next time :)

, Mike