######################################################################
PasswordMonkey 0.08
######################################################################
NAME
PasswordMonkey - Password prompt responder
SYNOPSIS
use PasswordMonkey;
use PasswordMonkey::Filler::Sudo;
use PasswordMonkey::Filler::Adduser;
my $sudo = PasswordMonkey::Filler::Sudo->new(
password => "supersecrEt",
);
my $adduser = PasswordMonkey::Filler::Adduser->new(
password => "logmein",
);
my $monkey = PasswordMonkey->new();
$monkey->filler_add( $sudo );
$monkey->filler_add( $adduser );
# Spawn a script that asks for
# - the sudo password and then
# - the new password for 'adduser' twice
$monkey->spawn("sudo adduser testuser");
# Password monkey goes to work
$monkey->go();
# ==== In action:
# [sudo] password for mschilli:
# (waits two seconds)
# ******** (types 'supersecrEt\n')
# ...
# Copying files from `/etc/skel' ...
# Enter new UNIX password:
# ******** (types 'logmein')
# Retype new UNIX password:
# ******** (types 'logmein')
DESCRIPTION
PasswordMonkey is a plugin-driven approach to provide passwords to
prompts, following strategies human users would employ as well. It comes
with a set of Filler plugins who know how to deal with common
applications expecting password input (sudo, ssh) and a set of Bouncer
plugins who know how to employ different security strategies once a
prompt has been detected. It can be easily extended to support
additional applications.
That being said, let me remind you that USING PLAINTEXT PASSWORDS IN
AUTOMATED SYSTEMS IS ALMOST ALWAYS A BAD IDEA. Use ssh keys, custom sudo
rules, PAM modules, or other techniques instead. This Expect-based
module uses plain text passwords and it's useful in a context with
legacy applications, because it provides a slightly better and safer
mechanism than simpler Expect-based scripts, but it is still worse than
using passwordless technologies. You've been warned.
Return Codes
The $monkey->go() method call returns a true value upon success, so
running
if( ! $monkey->go() ) {
print "Something went wrong!\n";
}
will catch any errors. Also,
$monkey->is_success();
will return true on success. Note that hitting a timeout or a bad exit
status of the spawned process is considered an error. To check for these
cases, use the following accessors:
if( $monkey->exit_status() ) {
print "The process exited with rc=", $monkey->exit_status(), "\n";
}
if( $monkey->timed_out() ) {
print "The monkey timed out!\n";
}
To get the number of password fills the monkey performed, use
my $nof_fills = $monkey->fills();
Note that "exit_status()" returns the Perl-specific return code of
"system()". If you need the shell-specific return code, you need to use
"exit_status() >> 8" instead (check 'perldoc -f system' for details).
Fillers
PasswordMonkey::Filler::Sudo
Sudo passwords
Running a command like
$ sudo adduser testuser
[sudo] password for mschilli:
********
PasswordMonkey::Filler::Passwd
The passwd Program
Copying files from `/etc/skel' ...
Enter new UNIX password:
********
Retype new UNIX password:
********
PasswordMonkey::Filler::SSH
$ ssh localhost
testuser@localhost's password:
********
Bouncer Plugins
Bouncer plugins can configure a number of security checks to run after a
prompt has been detected. These checks are also implemented as plugins,
and are added to filler plugins via their "bouncer_add" method.
Verifying inactivity after password prompts: Bouncer::Wait
To make sure that we are actually dealing with a sudo password prompt in
the form of
# [sudo] password for joeuser:
and not just a fly-by text string matching the prompt regular
expression, we add a Wait Bouncer object to it, which blocks the Sudo
plugin's response until two seconds have passed without any other
output, making sure that the application is actually waiting for input:
use PasswordMonkey;
my $sudo = PasswordMonkey::Filler::Sudo->new(
password => "supersecrEt",
);
my $wait_two_secs =
PasswordMonkey::Bouncer::Wait->new( seconds => 2 );
$sudo->bouncer_add( $wait_two_secs );
$monkey->filler_add( $sudo );
$monkey->spawn("sudo ls");
This will spawn sudo, detect if it's asking for the user's password by
matching its output against a regular expression, and, upon a match,
waits two seconds and proceeds only if there's no further output
activity until then.
Typing on terminals with echo on: Bouncer::NoEcho
PasswordMonkey starts typing innocuous characters after receiving a
password prompt like "Password:" and checks if those characters appear
on the screen:
Password: abc
If nothing is displayed, the prompt is okay and the user hits
"Backspace" to delete the test characters, followed by the real password
and the "Return" key. If, on the other hand, characters start to show up
on screen, the password entering process is aborted immediately.
Hitting enter to see prompt reappear: Bouncer::Retry
To see if a password prompt is really genuine, PasswordMonkey hits enter
and verifies the prompt reappears:
Password:
Password:
before it starts typing the password.
Filler API
Writing new filler plugins is easy, see the sudo plugin as an example:
package PasswordMonkey::Filler::Sudo;
use strict;
use warnings;
use base qw(PasswordMonkey::Filler);
sub prompt {
return qr(^\[sudo\] password for [\w_]+:\s*$);
}
All that's required is that you let your plugin inherit from the
PasswordMonkey::Filler base class and then override the "prompt" method
to return a regular expression for the prompt upon which the plugin is
supposed to send its password.
"new( key =" value )>
Most plugins accept a 'password' option, to set the password they'll
transmit with once their internally configured prompt has been
detected.
"prompt()"
Returns the regular expression that the plugin is waiting for to
respond with the password.
Bouncer API
A Bouncer plugin defines a "check()" method which uses the a reference
to the Expect object to run its prompt verification tests.
AUTHOR
2011, Mike Schilli <cpan@perlmeister.com>
COPYRIGHT & LICENSE
Copyright (c) 2011 Yahoo! Inc. All rights reserved. The copyrights to
the contents of this file are licensed under the Perl Artistic License
(ver. 15 Aug 1997).