#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use Net::SNMP; $|++; my %o = ( verbose => 1 ); GetOptions (\%o, 'host=s', 'user=s', 'password=s', 'newpassword=s', 'verbose!', 'help', ); unless ($o{host}) { $o{help}++ } unless ($o{user}) { $o{help}++ } unless ($o{password}) { $o{help}++ } unless ($o{newpassword}) { $o{help}++ } if ($o{help}) { print <<_EOF_; Usage: snmpv3-chpass [options] -host the AP's current ip -user the user to change -password SNMPv3 password -newpassword the new password -(no)verbose toggle verbosity Assumes MD5 authentication and that the same password is used for both Authentication and Privacy. Should be easily modified to use SHA1 authentication. _EOF_ exit 0;} my ($res,$session,$error); ($session,$error) = Net::SNMP->session ( -version => 'snmpv3', -hostname => $o{host}, -username => $o{user}, -authpassword => $o{password}, -privpassword => $o{password}, ); $session or die "fatal: $error\n"; die "error: new password must be >= 8 characters.\n" unless length($o{ +newpassword}) >= 8; # we go digging into places we don't belong... # these are private to the Net::SNMP module. my $security = $session->{_security}; my @engine_id = unpack "C*", $security->{_engine_id}; my @user_name = unpack "C*", $security->{_user_name}; my $oldkey = $security->{_auth_key}; my $newkey = $security->_key_generate($o{newpassword}); # $oldkey and $newkey are the passwords localized to the current # Authoritative Engine. # # @engine_id and @user_id hold the octets of the respective values, # they are needed to build the OID's used to set the new passwords. # back to the normal stuff # the data we need to change the password my $keychange = encode_keychange($oldkey, $newkey); # the oid's we need to set to change the password my $auth_oid = join '.', '1.3.6.1.6.3.15.1.2.2.1.7', # the ownAuthKeyOid scalar(@engine_id), @engine_id, scalar(@user_name), @user_name; my $priv_oid = join '.', '1.3.6.1.6.3.15.1.2.2.1.10', # the ownPrivKeyOid scalar(@engine_id), @engine_id, scalar(@user_name), @user_name; $res = $session->set_request( -varbindlist => [ $auth_oid, OCTET_STRING, $keychange, $priv_oid, OCTET_STRING, $keychange, # you might need to tell your device to save the # password change to NVRAM or you'll lose the # change after the next reboot. # this is for an Enterasys RoamAbout: # '1.3.6.1.4.1.731.2.2.1.6.1.0', INTEGER, 2, ]); $res or warn "error: ".$session->error."\n"; exit 0; use Digest::MD5; sub encode_keychange { my ($oldkey,$newkey) = @_; my $len = length $oldkey; my $keychange = pack "C*", (rand(255)) x $len; my $md5 = Digest::MD5->new; my $pre = substr($md5->add($oldkey.$keychange)->digest, 0, $len); my $post = "$pre" ^ "$newkey"; return $keychange.$post; }