-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmailfoguess.py
301 lines (280 loc) · 11.1 KB
/
mailfoguess.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import os
import json
import argparse
from modules.user import User
from modules.guesser import Guesser
def main(args):
print_more = args.print_informations
nb_print_localparts = args.nb_print_localparts
nb_print_emails = args.nb_print_emails
nb_print_verified = args.nb_print_verified
resume = None
if args.resume_path:
if os.path.isfile(args.resume_path) and args.resume_path.split(".")[-1]=="json":
with open(args.resume_path,"r") as f:
resume = json.load(f)
nb_emails = sum(len(resume["emails"][provider]) for provider in resume["emails"])
nb_validated_emails = sum(len(resume["validated_emails"][provider]) for provider in resume["validated_emails"])
print(f"Resuming file {args.resume_path}:")
print(f" + {len(resume['localparts'])} localparts already generated")
print(f" + {nb_emails} emails already generated")
print(f" + {nb_validated_emails} emails already processed during validation step")
else:
exit(f"File {args.resume_path} is not a valid file or doesn\'t exist. Verify file, spelling or extension (must be \'json\').\n")
if resume:
firstname = resume["firstname"] if resume["firstname"] else ""
middlename = resume["middlename"] if resume["middlename"] else ""
lastname = resume["lastname"] if resume["lastname"] else ""
username = resume["username"] if resume["username"] else ""
number = resume["number"] if resume["number"] else ""
elif not (args.firstname or args.middlename or args.lastname or args.username):
print("Please provide indications to generate potentials emails (leave empty for \"None\")")
firstname = input("\nFirstname ?\n> ")
middlename = input("\nMiddlename ?\n> ")
lastname = input("\nLastname ?\n> ")
username = input("\nUsername ?\n> ")
number = input("\nNumber ?\n> ")
if firstname+middlename+lastname+username == "":
exit("\nNot enough indications provided. Try [-h] to show options available.")
else:
firstname = args.firstname
middlename = args.middlename
lastname = args.lastname
username = args.username
number = args.number
user = User(
firstname = firstname,
middlename = middlename,
lastname = lastname,
username = username,
number = number,
)
guesser = Guesser(
user = user,
level = args.level,
separators = "-._"+args.separators,
)
if resume: guesser.resume(data=resume)
print("\n================================ USER ================================")
user.print()
print("\n============================= LOCAL-PART =============================")
print(f"Generating level: {guesser.level}")
print(f"Using separators: {guesser.separators}")
print(f"Number generated: {len(guesser.localparts)} generated in total")
if print_more and nb_print_localparts!=0:
print("Local-parts",end=f" (printing only {nb_print_localparts}):\n - " if len(guesser.localparts)>nb_print_localparts else ":\n - ")
if len(guesser.localparts)>nb_print_localparts:
printable_localparts = guesser.localparts[:int(nb_print_localparts/2)] + ["..."] + guesser.localparts[len(guesser.localparts)-int(nb_print_localparts/2):]
else: printable_localparts = guesser.localparts
print(*printable_localparts,sep="\n - ")
print("\n================================ EMAILS ==============================")
nb_emails = sum(len(guesser.emails[provider]) for provider in guesser.emails)
print(f"Emails : {nb_emails} generated in total with {len(guesser.providers)} different domains")
print(f"Domains used:")
for provider in guesser.providers:
print(f" + {provider} ({len(guesser.emails[provider])})",end=":\n\t- " if print_more and nb_print_emails!=0 else "\n")
if print_more and nb_print_emails!=0:
emails_from_provider = [email for email in guesser.emails[provider]]
if len(emails_from_provider) > nb_print_emails:
printable_emails = emails_from_provider[:int(nb_print_emails/2)] + ["..."] + emails_from_provider[len(emails_from_provider)-int(nb_print_emails/2):]
elif nb_print_emails: printable_emails = emails_from_provider
print(*printable_emails,sep="\n\t- ")
if args.verify:
print("\n#~~~~~~~~~~~~~~~~~~~~ VALIDATION ~~~~~~~~~~~~~~~~~~~~#")
try:
print("WARNING: Mailfoguess uses https://github.com/megadose/holehe to verify the generated mails. It can lead to false results due to rate limit or else.")
guesser.validate(validate_all=args.validate_all)
except KeyboardInterrupt as e:
print("\n[ctrl+c] Script interrupted by user.")
finally:
print("\n#~~~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~~~~#")
stats = guesser.validated_emails_stats()
print(f"Address processed : {stats[0]}")
print(f" + verified : {stats[1]}")
print(f" + unverified : {stats[2]}")
print(f" + non-existent : {stats[3]}")
if stats[4]:
print(f" + unprocessed : {stats[4]}")
if stats[1]:
print("By provider :")
for provider in guesser.validated_emails:
verified_emails = guesser.verified_emails(provider=provider)
if verified_emails:
print(f" + {provider}: {len(verified_emails)} verified adress found!",end=":\n\t- " if print_more and nb_print_verified!=0 else "\n")
if nb_print_verified!=0:
print("\t- ",end="")
if nb_print_verified:
printable_verified = verified_emails[:int(nb_print_emails/2)] + ["..."] + verified_emails[len(verified_emails)-int(nb_print_emails/2):]
else: printable_verified = verified_emails
print(*printable_verified,sep="\n\t- ")
print()
guesser.save(output_location=args.output_location)
if __name__ == "__main__":
arguments = argparse.ArgumentParser(
description="python script to guess the potentials email adress of someone",
)
#~~~~~~~~~~~~~~~~~ TARGET'S PARAMETERS ~~~~~~~~~~~~~~~~~#
target_informations = arguments.add_argument_group(
"Target",
description="Set known parameters concerning the target",
)
target_informations.add_argument(
"-f",
dest="firstname",
type=str,
nargs="?",
default=None,
required=False,
help="set target\'s firstname",
)
target_informations.add_argument(
"-m",
dest="middlename",
type=str,
nargs="?",
default=None,
required=False,
help="set target\'s middlename",
)
target_informations.add_argument(
"-l",
dest="lastname",
type=str,
nargs="?",
default=None,
required=False,
help="set target\'s lastname",
)
target_informations.add_argument(
"-u",
dest="username",
type=str,
nargs="?",
default=None,
required=False,
help="set target\'s username",
)
target_informations.add_argument(
"-n",
dest="number",
type=str,
nargs="?",
default=None,
required=False,
help="set a number to use (year of birth, locality...)",
)
#~~~~~~~~~~~~~~~~~ GENERATION PARAMETERS ~~~~~~~~~~~~~~~~~#
generation_parameters = arguments.add_argument_group(
"Generation",
description="Set parameters concerning the generation",
)
generation_parameters.add_argument(
"--verify","-V",
dest="verify",
action="store_true",
default=False,
required=False,
help="tries to verify the addresses using holehe (https://github.com/megadose/holehe)",
)
generation_parameters.add_argument(
"--yes","-Y",
dest="validate_all",
action="store_true",
default=False,
required=False,
help="assumes \"yes\" as the answer to all questions of validation (only with option --verify)",
)
generation_parameters.add_argument(
"--level","-L",
dest="level",
choices=["min","low","high","max"],
default="min",
required=False,
help="choose level of generation (default \'min\')",
)
generation_parameters.add_argument(
"--resume","-r",
dest="resume_path",
type=str,
nargs="?",
default=None,
required=False,
help="select a json file to resume or enrich wich new options",
)
generation_parameters.add_argument(
"--separators","-s",
dest="separators",
nargs="?",
type=str,
default="",
required=False,
help="set separators used for the generation of local-parts (default are \'-._\')",
)
#~~~~~~~~~~~~~~~~~ OUTPUT PARAMETERS ~~~~~~~~~~~~~~~~~#
output_parameters = arguments.add_argument_group(
"Output",
description="Select how the data will be displayed and/or saved",
)
output_parameters.add_argument(
"--no-banner",
dest="nobanner",
required=False,
default=False,
action="store_true",
help="doesn't display banner",
)
output_parameters.add_argument(
"--print-more","-P",
dest="print_informations",
action="store_true",
default=False,
required=False,
help="print generated informations on screen (local-part, emails and verified emails)",
)
output_parameters.add_argument(
"--output","-O",
dest="output_location",
nargs="?",
type=str,
default="./output",
required=False,
help="choose output location (default is \"./output\")",
)
output_parameters.add_argument(
"--nb-localparts",
dest="nb_print_localparts",
type=int,
nargs="?",
default=20,
required=False,
help="set the maximum of local-part printed when informations are displayed"
" (default is 20)",
)
output_parameters.add_argument(
"--nb-emails",
dest="nb_print_emails",
type=int,
nargs="?",
default=4,
required=False,
help="set the maximum of emails printed per domain when informations are displayed"
" (default is 4)",
)
output_parameters.add_argument(
"--nb-verified",
dest="nb_print_verified",
type=int,
nargs="?",
default=None,
required=False,
help="set the maximum of verified emails printed per domain when informations are displayed"
" (default is all)",
)
#~~~~~~~~~~~~~~~~~ OPTIONALS PARAMETERS ~~~~~~~~~~~~~~~~~#
args = arguments.parse_args()
if not args.nobanner:
try:
print(open("assets/banner.txt", "r").read())
except:
pass
main(args)