###################################################################### PasswordMonkey 0.07 ###################################################################### 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 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).