Skip to content

Instantly share code, notes, and snippets.

@qistoph
Created August 4, 2017 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qistoph/3ff171c1d429b9b9ca0dad9de87e9538 to your computer and use it in GitHub Desktop.
Save qistoph/3ff171c1d429b9b9ca0dad9de87e9538 to your computer and use it in GitHub Desktop.
Search a list of hashes for your KeePass stored passwords
#!/usr/bin/perl
# Search a list of hashes for your KeePass stored passwords
# e.g. https://haveibeenpwned.com/Passwords
# Chris van Marle 2017
# License: GNU GPLv3
use strict;
use warnings;
use Data::Dumper;
use XML::XPath;
use Digest::SHA qw(sha1 sha1_hex);
use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END);
$|++;
my $shafile = "pwned-passwords-1.0.txt";
my $linelen = 2*20 + 2; # 20 bytes SHA in hex + \r\n
print "Reading SHA file\n";
my $fSHA;
open($fSHA, $shafile) || die("Couldn't open sha file ($shafile): $!");
seek($fSHA, 0, SEEK_END);
my $endPos = tell($fSHA);
my $totalLines = ($endPos / $linelen)-1;
print "Reading KeePass file\n";
my $xp = new XML::XPath(filename => 'KeePass.xml');
my $nodeset = $xp->findnodes('/KeePassFile/Root//Group/Entry'); # Find Entry's in Group (not for example History) that have a Password field
print "Entries in KeePass file: ";
print $nodeset->size()."\n";
foreach my $node ($nodeset->get_nodelist) {
my $title = $node->findvalue('String[Key/text()="Title"]/Value');
my $uuid = $node->findvalue('UUID');
my $pass = $node->findvalue('String[Key/text()="Password"]/Value');
next if($pass eq '');
my $hash = uc(sha1_hex($pass));
my $found = find(0, $totalLines, $hash);
if($found) {
printf("%s - %s: ", $title, $pass);
print $found ? "FOUND\n" : "not found\n";
}
}
sub readnr {
my $linenr = shift;
seek($fSHA, $linenr * $linelen, SEEK_SET);
my $val = <$fSHA>;
$val =~ s/\s+$//;
return $val;
}
sub find {
my ($startLine, $endLine, $target) = @_;
my $midLine = int(($endLine - $startLine) / 2 + $startLine);
#print "$startLine - $midLine - $endLine\n";
my $startValue = readnr($startLine);
#print "startValue: $startValue\n";
my $res1 = $target cmp $startValue;
#print "res1: $res1\n";
return 1 if ($res1 == 0);
return 0 if ($res1 < 0);
my $endValue = readnr($endLine);
#print "endValue: $endValue\n";
my $res2 = $target cmp $endValue;
#print "res2: $res2\n";
return 1 if($res2 == 0);
return 0 if($res2 > 0);
my $midValue = readnr($midLine);
#print "midValue: $midValue\n";
my $resM = $target cmp $midValue;
return 1 if($resM == 0);
return 0 if($startLine == $midLine or $endLine == $midLine);
return find($startLine, $midLine, $target) if($resM < 0);
return find($midLine, $endLine, $target) if($resM > 0);
die "Invalid state!";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment