Masking/Hiding a password in Perl Source

C

Chris G.

I have written a Perl script that connects to various networking devices
and downloads their configurations to a TFTP server. This is working
great and I want to enhance its security by masking the password
somehow. Currently, I hardcode a variable to the password.

$password = 'mypassword';

In the interest of security, I want to find a way to mask this. I'm not
sure how to go about it though. I don't want to have a plain-text
password on the system anywhere.

Any suggestions?

Thanks,

Chris G.
c-gauthie-A-T-pcc-D-O-T-edu (just remove the - characters and make the
appropriate substitutions to email me.
 
A

anno4000

Chris G. said:
I have written a Perl script that connects to various networking devices
and downloads their configurations to a TFTP server. This is working
great and I want to enhance its security by masking the password
somehow. Currently, I hardcode a variable to the password.

$password = 'mypassword';

In the interest of security, I want to find a way to mask this. I'm not
sure how to go about it though. I don't want to have a plain-text
password on the system anywhere.

That is a laudable intention, but it will require human interaction.

If a program can decrypt a password without outside help, so can
someone who can read the program. Program-internal encryption may
make it harder, but not impossible. So you will at least have to
manually supply a master key that allows the program to access the
passwords it needs. Making the program a long-running server can
reduce the inconvenience, but once at startup human intervention is
needed.

Non of this is specific to Perl.

Anno
 
B

Brian McCauley

If a program can decrypt a password without outside help, so can
someone who can read the program. Program-internal encryption may
make it harder, but not impossible.

Just to expand on that... the use of "Program-internal encryption"
should be limited to addressing:

1) The posibility that someone happens to look over your shoulder while
you've got the script on the screen.

2) The possibility that someone who is trying not to learn the password
might accidently assimilate it subliminially.

Of course simply choosing a password that reads like line-noise can do
that almost as well!
 
T

Ted Zlatanov

I have written a Perl script that connects to various networking devices
and downloads their configurations to a TFTP server. This is working
great and I want to enhance its security by masking the password
somehow. Currently, I hardcode a variable to the password.

$password = 'mypassword';

In the interest of security, I want to find a way to mask this. I'm not
sure how to go about it though. I don't want to have a plain-text
password on the system anywhere.

This is actually a hard problem to solve in the general sense. It's
not really a Perl problem either, usually the OS has to manage
permissions.

The plain-text password will be in memory eventually (when you want to
use it), so this will simply delay but not impede the attacker who has
obtained root access.

If the attacker will not have root access, put the password file in a
file that only root can read, and then you can allow access to it
appropriately.

You may want to look into public/private keys as well. It depends on
your existing security infrastructure what you want to do.

Finally, you could make those devices provide their configurations
with a less privileged (non-admin) account, so you don't have the
admin password out there.

Ted
 
C

Chris G.

These are good suggestions. A little more information may help. The
whole point of the protecting the password within the source code is to
quiet the nay-sayers in my department who will scream bloody-murder
because anyone can read the password. Never mind that the connections
we make are using telnet, which is unsecure by default. I was
considering even a simple ROT13 call to jumble it.

I am not opposed to reading an encrypted string from a file and
decrypting it. I'm just trying to satisfy people on a more political
level than a technical level, if that makes sense.

Thanks for the suggestions and keep them coming!

Chris G.
 
P

Puckdropper

These are good suggestions. A little more information may help. The
whole point of the protecting the password within the source code is
to quiet the nay-sayers in my department who will scream bloody-murder
because anyone can read the password. Never mind that the connections
we make are using telnet, which is unsecure by default. I was
considering even a simple ROT13 call to jumble it.

I am not opposed to reading an encrypted string from a file and
decrypting it. I'm just trying to satisfy people on a more political
level than a technical level, if that makes sense.

Thanks for the suggestions and keep them coming!

Chris G.

*snip*

I asked a similar question about securing a database password several
months ago on another site. To sum up the result, the best suggestion I
got was to simply move the password to another file and read it in. You
can encrypt it if you want, but if they have access to your source code,
they have access to your decryption algorithm.

Puckdropper
 
C

cartercc

Chris said:
I have written a Perl script that connects to various networking devices
and downloads their configurations to a TFTP server. This is working
great and I want to enhance its security by masking the password
somehow. Currently, I hardcode a variable to the password.

We have a number of scripts that run queries on a remote database
server. These run in Perl, Java, and Visual Basic. We initialize these
scripts with configuration files to set up a VPN, a login session to
run the query, and an FTP session to retrieve the data. The
configuration files all look like this:

filetype::VPN
username::username
password::password
hostname::123.45.67.89

The best that we can do is save the config files as the name of the
user of the app and make them readable only, like this r-------- (or
400). This only defers the problem to someone obtaining the user's
password (or root).

At some point, your remote machine will expect a 'real' username and
password, and while you can tunnel the connection, I don't think
there's any way to encrypt it on your local machine and have it
unencrypted on the other end.

CC
 
T

Tad McClellan

l v said:
do not use variable names like $password to advertise what the variable
holds.


My boss never notices when I put passwords in programs:

$this_is_not_a_password = '!@#$%^&*()';

works like a charm!

:)
 
P

Peter Scott

These are good suggestions. A little more information may help. The
whole point of the protecting the password within the source code is to
quiet the nay-sayers in my department who will scream bloody-murder
because anyone can read the password. Never mind that the connections we
make are using telnet, which is unsecure by default. I was considering
even a simple ROT13 call to jumble it.

Oh. I was going to suggest kerberizing the application and then using a
keytab file for authentication. Of course, anyone who snarfs the keytab
file can still perform any operation as that principal they want, with the
exception that they cannot discover or change the password. Sounds like
you'd be okay with just reading the password off a local disk file with
minimal permissions.
 
J

J. Gleixner

Robert said:
As other have answered there really isn't "a" solution to this. I make
myself feel better by using the unpack command in my script.

my $password = unpack "u", qq{&<&QE87-E};

Sure that isn't any better than any other solution but it isn't "plain"
text either and that was all I was trying to solve. You could probably
do some silly obfuscation on it too.

This really is a false sense of security.

If security really is an issue, at all, you should look at more secure
transport solutions, such as SSH/SCP. and ensuring the machine is
as secure as possible. Even that might not be enough, however spending
more time in those areas will be much more beneficial, compared to
trying to find different ways to avoid having a password in clear text,
in a script. IMHO.
 
C

Chris G.

While this is not a "secure" solution, obscuring the password or reading
it from a file are really my options. Using a protocol like SSH is
something I REALLY want to do, but the "gods" who set the policies like
telnet. A group of us "pee-ons" who see the value and need in SSH and
other common-sense security strategies have tried (unsuccessfully)
several times to convince the management of this value.

I appreciate the input on all of this! I'm liking the unpack idea (so
far), as well as reading from a file.

Chris G.
 
C

Craig K

This is one way I have been doing this.... it takes the username and/or
password from one of three sources... system environment, command line
argument or runtime prompt.... I did not want to store my passwords
anyware in the script or otherwise in a file as too many nosy folks out
there. If I need to schedule the script, I can supply the username
and passwords on the command line while scheduling.

This script is for TACACS logins but you can modify for whatever
username and or passwords you want to utilize.... obviously.

Hope it may help someone....


if (!defined $ARGV[0])
{
$username = "$ENV{'USER'}";
chomp ($username);
}
else
{
chomp ($username = $ARGV[0]);
}
if (!defined $username)
{
print "Enter your TACACS username: ";
chomp ($username = <STDIN>);
}
if (!defined $ARGV[1])
{
print "\nYou are logged in with or have specified the following
username: [ $username ]. This will be used for your TACACS account.";
print "\nEnter your TACACS password: ";
system('stty', '-echo');
chomp ($userpass = <STDIN>);
system('stty', 'echo');
}
else
{
chomp ($userpass = $ARGV[1]);
}
 
J

J. Gleixner

Craig said:
If I need to schedule the script, I can supply the username
and passwords on the command line while scheduling.

FYI: Depending on the OS, the password can then be found in the process
table, so it might be available to anyone or any process running a 'ps',
for example.
This script is for TACACS logins [...]
Whatever that is.
 
C

Craig K

J. Gleixner said:
Craig said:
If I need to schedule the script, I can supply the username
and passwords on the command line while scheduling.

FYI: Depending on the OS, the password can then be found in the process
table, so it might be available to anyone or any process running a 'ps',
for example.

This is true, but the OP asked for hiding the passwords within the
script which was the request that I offered a solution to. Also, if
you are running telnet, as the OP mentioned, I can put a sniffer on
the segment and have the password within 10 seconds.
This script is for TACACS logins [...]
Whatever that is.

If you dont know what it is I would guess then you most likely are not
using it. Substitute whatever authentication means you are using.
 
C

Craig K

Craig said:
This is true, but the OP asked for hiding the passwords within the
script which was the request that I offered a solution to. Also, if
you are running telnet, as the OP mentioned, I can put a sniffer on
the segment and have the password within 10 seconds.

In looking further... I think I mixed my newsgroup messages. The OP
only mentions connects to devices, not telnets. Anyway, let me correct
my statement to be that any unencrypted connection (i.e. telnet, ftp,
etc) could have the password gathered in short order with a sniffer.
 
C

Chris G.

Actually, you're absolutely correct on the sniffing the telnet
connections. Sadly, several of us have not been able to convince our
organization's leadership that moving to SSL for web interfaces and SSH
for command-line sessions is necessary on our network equipment. I like
your idea, though I am not exactly sure I understand how you implement
that in an automated fashion. I like the example you gave, though. It
gives me a great start on my next iteration of this script, which
includes command-line options for usernames, passwords, and more.
(Simple stuff, I know). We don't use TACACS or RADIUS at the moment,
but that's on the project list.

Thanks for the help!

Chris
 
J

J.D. Baldwin

[Bcc-ed to poster due to age of article]

In the previous article said:
I have written a Perl script that connects to various networking
devices and downloads their configurations to a TFTP server. This
is working great and I want to enhance its security by masking the
password somehow. Currently, I hardcode a variable to the password.

$password = 'mypassword';

In the interest of security, I want to find a way to mask this. I'm
not sure how to go about it though. I don't want to have a
plain-text password on the system anywhere.

Any suggestions?

I came in here looking for a generalized solution to this. With the
understanding that all that is being accomplished here is obfuscation,
NOT any genuine "security," I have a solution I am considering turning
into a module. I am interested in comments as to whether it would be
a useful module (including naming suggestions).

I have two functions: encryptpw and decryptpw. Only decryptpw actually
belongs in your program. Given a directory $ACCESSDIR, account name
$acctname, and password $pw, encryptpw creates a random key and stores
the key and password directly in file $ACCESSDIR/$acctname.

So, once you run encryptpw, you'll have a file that looks like this
(dummy data):

ab7458e29a2e01e4b566b8541dfe3a2326312a539fc4bb158eb1c83ff
53616c7465645f5f8d8ad43ea2bc5678a2c43c59a245d239abcb2ff3d67d1acf0eeb7d27

You only need to do this once (well, again whenever you change the
password, but you get the idea).

Set the file read permissions on the above file such that only
authorized users (e.g., group members, ACL-designated users, whatever)
can read it.

Then, in the program, run decryptpw to get the password back, and
store it in a variable.

The "encryptpw" function is currently actually a standalone program,
encrypt.pl. I have included a slightly sanitized encrypt.pl and
decryptpw below.

Once again, ALL this does for you is keep from having a password
sitting out there naked in the text of your script. Anyone with read
access to the "encrypted" password file who knows anything at all
about Perl can read the password directly with his own copy of
decryptpw and the print statement.

I know the storage/retrieval is a little kludgy, particularly the
0-padding. I am working on a new version that relies on Storable, now
that I know about Storable.

================ encrypt.pl:

#!/usr/bin/perl -w

use Crypt::CBC;
use Digest::MD5 qw(md5_hex);

$BASEDIR = "/my/basedir";
$ACCESSDIR = "$BASEDIR/access";

umask 077;

while ( 1 )
{
print "Please input an account name: ";
$acctname = <STDIN>;
chomp $acctname;
last if ( length($acctname) );
}

if ( ( $acctname =~ /^(en|de)crypt.pl$/ ) || ( $acctname eq "README" ) )
{
# I (stupidly? keep the scripts in $ACCESSDIR -- don't ever allow
# overwriting of the scripts!

print "FATAL ERROR: Cannot overwrite script $acctname\n";
exit -1;
}

system("stty -echo");
while ( 1 )
{
$pw1 = '';

while ( ! length($pw1) )
{
print "\n";
$strlen = length("Please input the password for account $acctname: ");
printf ("%${strlen}s",
"Please input the password for account $acctname: ");
chomp($pw1=<STDIN>);
}

$pw2 = '';
printf ("\n%${strlen}s", "Please verify the password: ");
chomp($pw2=<STDIN>);

print "\n";
last if ( $pw1 eq $pw2 );

print "\nPassword mismatch - try again\n";
}

system("stty echo");

# Pad $pw1 out to eight bytes if necessary:

$pw1 .= "\0"x(8 - length($pw1));

# Generate two 32-byte hex strings

$bigkey = md5_hex(rand) . md5_hex(rand);

# Take the first 56 characters of this, which will be our ASCII key:

$key = substr($bigkey, 0, 56);

$binkey = pack("H*", $key);
$cipher = Crypt::CBC->new( -key => $binkey,
-cipher => 'Blowfish',
-header => "randomiv",
);
$ciphertext = $cipher -> encrypt($pw1);

$ascii_armor = unpack("H*", $ciphertext);

if ( -e "$ACCESSDIR/$acctname" )
{
print "$ACCESSDIR/$acctname exists and will be overwritten, OK [y/N]? ";
chomp ($answer = <STDIN>);

# Acceptable affirmative answers are Y, y, Yes, yes:

if ( ! ( $answer =~ /^[Yy]([Ee][Ss])?$/ ) )
{
print "ABORTING, no action taken\n";
exit 0;
}
}

unless ( open(OUTFILE, ">$ACCESSDIR/$acctname") )
{
die "Unable to open $ACCESSDIR/$acctname for writing: $!";
}

print OUTFILE "$key\n$ascii_armor\n";
close OUTFILE;

================ decryptpw:

use Crypt::CBC;

$BASEDIR = "/must/be/same/as/used/by/encrypt.pl/of/course!";
$ACCESSDIR = "$BASEDIR/access";

sub decryptpw
{
# Takes one argument: the name of an account for which a password
# has been stored in $ACCESSDIR under the name of the account

$acctname = $_[0];

unless ( open(INFILE, "$ACCESSDIR/$acctname") )
{
die "Unable to open $ACCESSDIR/$acctname for reading: $!";
}

chomp ($key = <INFILE>)
or die "Cannot read key from $ACCESSDIR/$acctname";
chomp ($ascii_armor = <INFILE>)
or die "Cannot read pw hash from $ACCESSDIR/$acctname";
close INFILE;

$binkey = pack("H*", $key);
$ciphertext = pack("H*", $ascii_armor);

$cipher = Crypt::CBC->new( -key => $binkey,
-cipher => 'Blowfish'',
-header => "randomiv",
);

$pass = $cipher -> decrypt($ciphertext);

# Get rid of the null characters we used to pad the password during
# encryption:

$pass =~ s/\0*$//;
return $pass;

}
 
E

Eric Schwartz

So, once you run encryptpw, you'll have a file that looks like this
(dummy data):

ab7458e29a2e01e4b566b8541dfe3a2326312a539fc4bb158eb1c83ff
53616c7465645f5f8d8ad43ea2bc5678a2c43c59a245d239abcb2ff3d67d1acf0eeb7d27

You only need to do this once (well, again whenever you change the
password, but you get the idea).

Set the file read permissions on the above file such that only
authorized users (e.g., group members, ACL-designated users, whatever)
can read it.

If you're going to to that, then why not just use the unencrypted
password in the separate file? Anybody who can read your encrypted
file can easily decrypt it, and anyone who can't read it doesn't care
whether or not the file they can't read is encrypted or in plaintext.

-=Eric
 
J

J.D. Baldwin

In the previous article said:
If you're going to to that, then why not just use the unencrypted
password in the separate file? Anybody who can read your encrypted
file can easily decrypt it,

"Anybody"? You don't work with the same crew I do. I doubt more than
one of the fifty people with read access to that file would know what
to do with it. Of course, that isn't the point ....
and anyone who can't read it doesn't care whether or not the file
they can't read is encrypted or in plaintext.

.... with the understanding, stated several times over, that this is
nothing more than security-through-obscurity, which is in fact no real
security at all, the point is not to keep access to the password from
authorized persons, the point is to keep it from being casually or
"accidentally" viewed.

I much prefer ssh keys and (when appropriate) agents for caching same,
but some of the technologies I need automated access to don't support
that because the vendors STILL don't take ssh (or any other security
features of their products) seriously. *koff*Cisco*koff*
 
E

Eric Schwartz

... with the understanding, stated several times over, that this is
nothing more than security-through-obscurity, which is in fact no real
security at all, the point is not to keep access to the password from
authorized persons, the point is to keep it from being casually or
"accidentally" viewed.

I know, I'm just saying that if you set the right permissions, ACLs,
what-have-you, it can't be casually or "accidentally" viewed anyway,
so adding obscurity on top of it gives you zero benefit. That's all I
was responding to-- your first obscurity, setting file permissions, is
sufficient. Adding any sort of encryption on top of that is
pointless, because the only people who can read it are exactly the
people you *want* to have the password anyway.

-=Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top