http://www.perlmonks.org?node_id=1071729

three18ti has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks

I apparently signed up for blogs.perl.org some time ago, and I have no idea what password I used. With the leak of my credentials (unfortunately my username is on the list) I would like to verify what password I used.

Since the crypt function is a one way hash function, I was going to "crypt" my standard passwords, but I'm having trouble identifying where the SALT value comes from.

Full disclosure, I tried to ask on irc.freenode.net #perl and was told to RTFS, (even though I had been), and when I tried to ask questions about the source (because frankly the begin block below makes no sense to me... it looks like it's modifying the symbol table directly, but to what end?) I was told again to RTFS.

I'm hoping against all hope that you are nicer than the people on irc, because frankly I'm a bit hot under the collar right now (and I now understand all the gripes about how shitty people in the Perl community are... having never experienced it for myself). (I get that people on irc and here are volunteering their time, but that's no reason to be rude about it. Besides this is a serious breach of security and I'd just like a _little_ help to gain a piece of mind. I don't _usually_ reuse passwords, but again, I have no idea what password I used on blogs.perl.org).

Anyway, I digress, from the Movable Type docs:

MT::Author =head2 $author->set_password($pass) One-way encrypts I<$pass> with a randomly-generated salt, using the Un +ix I<crypt> function, and sets the I<password> data field in the I<MT::Au +thor> object I<$author>. Because the password is one-way encrypted, there is B<no way> of recov +ering the initial password. =head2 $author->is_valid_password($check_pass) Tests whether I<$check_pass> is a valid password for the I<MT::Author> + object I<$author> (ie, whether it matches the password originally set using I<set_password>). This check is done by one-way encrypting I<$check_pa +ss>, using the same salt used to encrypt the original password, then compar +ing the two encrypted strings for equality.

The documentation for is_valid_password in MT::Auth is very similar:

MT::Auth =head2 MT::Auth->is_valid_password($author, $password, $crypted, \$err +or_ref) A routine that determines whether the given password is valid for the author object supplied. If the password is already processed by the 'crypt' function, the third parameter here will be positive. The \$err +or_ref is a reference to a scalar variable for storing any error message to be returned to the application. The routine itself should return 1 for a valid password, 0 or undef for an invalid one.

This says to me that the function is_valid_password somehow "magically" knows the SALT, but I don't understand HOW is_valid_password is getting that salt value, it's not being passed in as a parameter...

It looks to me that the salt value is a randomly generated two character salt:

sub set_password { my $auth = shift; my($pass) = @_; my @alpha = ('a'..'z', 'A'..'Z', 0..9); my $salt = join '', map $alpha[rand @alpha], 1..2; # FIXME: use something besides 'crypt' $auth->column('password', crypt $pass, $salt); }

It looks like MT::Author::is_valid_password is just a proxy for MT::Auth::is_valid_password, as it just calls MT::Auth::is_valid_password with the parameters passed to it:

sub is_valid_password { my $author = shift; my($pass, $crypted, $error_ref) = @_; $pass ||= ''; require MT::Auth; return MT::Auth->is_valid_password($author, $pass, $crypted, $erro +r_ref); }

Here's where I really don't understand, MT::Auth::is_valid_password doesn't seem to be defined, but in MT::Auth it looks like we're modifying the symbol table directly:

BEGIN { my @methods = qw( errstr sanity_check is_valid_password can_recover_password is_profile_needed password_exists validate_credentials invalidate_credentials delegate_auth can_logout synchronize synchronize_author synchronize_group new_user new_login login_form fetch_credentials ); no strict 'refs'; foreach my $meth (@methods) { *{"MT::Auth::$meth"} = sub { shift; _handle($meth, @_) }; } }

(It was when I asked for help understanding the above block of code that I was told I should RTFS for the second time).

My guess is that this code is shifting of the obj reference (since the object is passed as the first parameter when calling an object method), then passing the rest of the parameters to _handle. The following block is a block inside of main, so $auth_module is "cached" so _driver doesn't have to be called on every invocation. It seems like _driver is just instantiating an object of MT::Auth::$SOMETHING (my best guess is BasicAuth in this case), but then _handle is calling $method on some $object. (but if $method is is_valid_password then it can't do that because MT::Auth::BasicAuth doesn't define an "is_valid_password")

This is wrinkling my brain. What is going on here?

{ my $auth_module; sub _driver { my @auth_modes = split(/\s+/, MT->config->AuthenticationModule); foreach my $auth_mode (@auth_modes) { my $auth_module_name = 'MT::Auth::' . $auth_mode; eval 'require ' . $auth_module_name; if (my $err = $@) { die (MT->translate("Bad AuthenticationModule config '[_1]' +: [_2]", $auth_mode, $err)); } my $auth_module = $auth_module_name->new; die $auth_module_name->errstr if (!$auth_module || (ref(\$auth_module) eq 'SCALAR')); return $auth_module; } die(MT->translate("Bad AuthenticationModule config")); } sub _handle { my $method = shift; my $mod = $auth_module ||= _driver(); return undef unless $mod->can($method); $mod->$method(@_); } sub release { undef $auth_module; } }

I am curious as to what is going on here, I'm always looking for strategies to improve my code, but that is extremely low priority in comparison to verifying what password was leaked.

I asked the same question on reddit but /r/perl is not nearly as active as perlmonks.

Thanks for any assistance.

EDIT:

This appears to be the is_valid_password in MT::Auth::MT, my guess that we'd be using MT::Auth::BasicAuth is incorrect (I think)

sub is_valid_password { my $auth = shift; my($author, $pass, $crypted, $error_ref) = @_; $pass ||= ''; my $real_pass = $author->column('password'); if ((!$real_pass) || ($real_pass eq '(none)')) { return 0; } return $crypted ? $real_pass eq $pass : crypt($pass, $real_pass) eq $real_pass; }

Many thanks to Corion and Anonymous Monk for their assistance with this one

  • Comment on [SOLVED][blogs.perl.org credential release] How can I check the password that I used on blogs.perl.org
  • Select or Download Code

Replies are listed 'Best First'.
Re: [blogs.perl.org credential release] How can I check the password that I used on blogs.perl.org
by Anonymous Monk on Jan 23, 2014 at 12:03 UTC

    About salt: crypt puts the salt characters as first 2 characters of the encrypted version.

      Thanks Anonymous Monk. The best part, it's even spelled out in the Doc, but I didn't understand when I first read it.

      When verifying an existing digest string you should use the digest as the salt (like crypt($plain, $digest) eq $digest ). The SALT used to create the digest is visible as part of the digest. This ensures crypt() will hash the new string with the same salt as the digest. This allows your code to work with the standard crypt and with more exotic implementations. In other words, assume nothing about the returned string itself nor about how many bytes of SALT may matter.

        Only first 2 characters of a string are used as salt by crypt ...

        perl -e '$start = q[px]; print crypt( "polka" , $_ ) . "\n" for map $ +start. $_ , '' , q[a] .. q[x] , 0 .. 9' \ | uniq pxtbCUVxSeD2A
Re: [SOLVED][blogs.perl.org credential release] How can I check the password that I used on blogs.perl.org
by FloydATC (Deacon) on Jan 23, 2014 at 13:51 UTC

    As an aside, and FWIW, perlmonks != IRC in my experience.

    -- FloydATC

    Time flies when you don't know what you're doing

      I definitely agree, I've certainly gotten more terse answers via IRC, but I'm just baffled by the response I received today.
Re: [SOLVED][blogs.perl.org credential release] How can I check the password that I used on blogs.perl.org
by Anonymous Monk on Jan 23, 2014 at 22:44 UTC
    um, Modern Perl discusses that symbol table stuff around page 155