forked from houbbit/haveibeenpwned
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhaveibeenpwned.py
75 lines (67 loc) · 4.73 KB
/
haveibeenpwned.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
#!/usr/bin/env python
# Author = Laurens Houben
# Contact = https://www.linkedin.com/in/laurenshouben
# TODO:
# - Retrieve breached domain from response in case of a breach:
# Example response for [email protected]:
# [{"Title":"Adobe","Name":"Adobe","Domain":"adobe.com","BreachDate":"2013-10-04","AddedDate":"2013-12-04T00:00:00Z","PwnCount":152445165,"Description":"In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, <em>encrypted</em> password and a password hint in plain text. The password cryptography was poorly done and <a href=\"http://stricture-group.com/files/adobe-top100.txt\" target=\"_blank\" rel=\"noopener\">many were quickly resolved back to plain text</a>. The unencrypted hints also <a href=\"http://www.troyhunt.com/2013/11/adobe-credentials-and-serious.html\" target=\"_blank\" rel=\"noopener\">disclosed much about the passwords</a> adding further to the risk that hundreds of millions of Adobe customers already faced.","DataClasses":["Email addresses","Password hints","Passwords","Usernames"],"IsVerified":true,"IsSensitive":false,"IsActive":true,"IsRetired":false,"IsSpamList":false,"LogoType":"svg"},{"Title":"Xbox-Scene","Name":"Xbox-Scene","Domain":"xboxscene.com","BreachDate":"2015-02-01","AddedDate":"2016-02-07T20:26:56Z","PwnCount":432552,"Description":"In approximately February 2015, the Xbox forum known as <a href=\"http://xboxscene.com/\" target=\"_blank\" rel=\"noopener\">Xbox-Scene</a> was hacked and more than 432k accounts were exposed. The IP.Board forum included IP addresses and passwords stored as salted hashes using a weak implementation enabling many to be rapidly cracked.","DataClasses":["Email addresses","IP addresses","Passwords","Usernames"],"IsVerified":true,"IsSensitive":false,"IsActive":true,"IsRetired":false,"IsSpamList":false,"LogoType":"png"}]
# -
import requests
import time
import argparse
parser = argparse.ArgumentParser(description="Verify if email address has been pwned")
parser.add_argument("-a", dest="address",
help="Single email address to be checked")
parser.add_argument("-f", dest="filename",
help="File to be checked with one email addresses per line")
args = parser.parse_args()
rate = 1.3 # 1.3 seconds is a safe value that in most cases does not trigger rate limiting
server = "haveibeenpwned.com" # Website to contact
sslVerify = True # Verify server certificate (set to False when you use a debugging proxy like BurpSuite)
proxies = { # Proxy to use (debugging)
# 'http': 'http://127.0.0.1:8080', # Uncomment when needed
# 'https': 'http://127.0.0.1:8080', # Uncomment when needed
}
# Set terminal ANSI code colors
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAILRED = '\033[91m'
ENDC = '\033[0m'
address = str(args.address)
filename = str(args.filename)
lstEmail = ["[email protected]","[email protected]]
def main():
if address != "None":
checkAddress(address)
elif filename != "None":
email = [line.rstrip('\n') for line in open(filename)] # strip the newlines
for email in email:
checkAddress(email)
else:
for email in lstEmail:
checkAddress(email)
def checkAddress(email):
sleep = rate # Reset default acceptable rate
check = requests.get("https://" + server + "/api/v2/breachedaccount/" + email + "?includeUnverified=true",
proxies = proxies,
verify = sslVerify)
if str(check.status_code) == "404": # The address has not been breached.
print OKGREEN + "[i] " + email + " has not been breached." + ENDC
time.sleep(sleep) # sleep so that we don't trigger the rate limit
return False
elif str(check.status_code) == "200": # The address has been breached!
print FAILRED + "[!] " + email + " has been breached!" + ENDC
time.sleep(sleep) # sleep so that we don't trigger the rate limit
return True
elif str(check.status_code) == "429": # Rate limit triggered
print WARNING + "[!] Rate limit exceeded, server instructed us to retry after " + check.headers['Retry-After'] + " seconds" + ENDC
print WARNING + " Refer to acceptable use of API: https://haveibeenpwned.com/API/v2#AcceptableUse" + ENDC
sleep = float(check.headers['Retry-After']) # Read rate limit from HTTP response headers and set local sleep rate
time.sleep(sleep) # sleeping a little longer as the server instructed us to do
checkAddress(email) # try again
else:
print WARNING + "[!] Something went wrong while checking " + email + ENDC
time.sleep(sleep) # sleep so that we don't trigger the rate limit
return True
if __name__ == "__main__":
main()