Skip to content

Commit

Permalink
Merge pull request #43 from khast3x/2.4
Browse files Browse the repository at this point in the history
2.4
  • Loading branch information
khast3x authored Oct 19, 2019
2 parents 269117e + eac5cd9 commit 2c8c8b9
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 66 deletions.
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<p align="center">
<p align="center">
<a href="https://github.com/khast3x/h8mail/releases/"> <img src="https://i.postimg.cc/LXR6Jq8Y/logo-transparent.png" width="420" title="h8maillogo">
</p>

Expand All @@ -11,7 +11,7 @@
----
<p align="center">
<a href="https://khast3x.club/2019/08/14/h8mail_2.3-release/?ref=readmebutton" First Anniversary update, feedback and pull requests are welcomed heart birthday"> <img src="https://i.postimg.cc/L83gRWvc/button-click-here-to-read-the-official-write-up.png" title="h8maillogo">
<a href="https://khast3x.club/h8mail/2019/10/19/h8mail_2.4-release/?ref=readmebutton" First Anniversary update, feedback and pull requests are welcomed heart birthday"> <img src="https://i.postimg.cc/L83gRWvc/button-click-here-to-read-the-official-write-up.png" title="h8maillogo">
</p>


Expand Down Expand Up @@ -83,21 +83,21 @@

#### APIs

| Service | Functions | Status |
|------------------------------------------------------------------ |:-----------------------------------------------------------------: |:--------------------------: |
| [HaveIBeenPwned(v3)](https://haveibeenpwned.com/) | Number of email breaches | :white_check_mark: :key: |
| [HaveIBeenPwned Pastes(v3)](https://haveibeenpwned.com/Pastes) :new: | URLs of text files mentioning targets | :white_check_mark: :key: |
| [Hunter.io](https://hunter.io/) - Public | Number of related emails | :white_check_mark: |
| [Hunter.io](https://hunter.io/) - Service (free tier) | Cleartext related emails, Chasing | :white_check_mark: :key: |
| [WeLeakInfo](https://weleakinfo.com/) - Public :new: | Number of search-able breach results | :white_check_mark: :key: |
| [WeLeakInfo](https://weleakinfo.com/) - Service :new: | Cleartext passwords, hashs and salts, usernames, IPs | :white_check_mark: :key: |
| [Snusbase](https://snusbase.com/) - Service | Cleartext passwords, hashs and salts, usernames, IPs - Fast :zap: | :white_check_mark: :key: |
| [Leak-Lookup](https://leak-lookup.com/) - Public :new: | Number of search-able breach results | :white_check_mark: (:key:) |
| [Leak-Lookup](https://leak-lookup.com/) - Service :new: | Cleartext passwords, hashs and salts, usernames, IPs | :white_check_mark: :key: |
| [Emailrep.io](https://emailrep.io/) - :new: | Last seen in breaches, social media profiles | :white_check_mark: |
| Service | Functions | Status |
|----------------------------------------------------------------|:-----------------------------------------------------------------:|:--------------------------:|
| [HaveIBeenPwned(v3)](https://haveibeenpwned.com/) | Number of email breaches | :white_check_mark: :key: |
| [HaveIBeenPwned Pastes(v3)](https://haveibeenpwned.com/Pastes) | URLs of text files mentioning targets | :white_check_mark: :key: |
| [Hunter.io](https://hunter.io/) - Public | Number of related emails | :white_check_mark: |
| [Hunter.io](https://hunter.io/) - Service (free tier) | Cleartext related emails, Chasing | :white_check_mark: :key: |
| [WeLeakInfo](https://weleakinfo.com/) - Public | Number of search-able breach results | :white_check_mark: :key: |
| [WeLeakInfo](https://weleakinfo.com/) - Service | Cleartext passwords, hashs and salts, usernames, IPs, domain | :white_check_mark: :key: |
| [Snusbase](https://snusbase.com/) - Service | Cleartext passwords, hashs and salts, usernames, IPs - Fast :zap: | :white_check_mark: :key: |
| [Leak-Lookup](https://leak-lookup.com/) - Public | Number of search-able breach results | :white_check_mark: (:key:) |
| [Leak-Lookup](https://leak-lookup.com/) - Service | Cleartext passwords, hashs and salts, usernames, IPs, domain | :white_check_mark: :key: |
| [Emailrep.io](https://emailrep.io/) - Service (free) | Last seen in breaches, social media profiles | :white_check_mark: |
| [Scylla.sh](https://scylla.sh/) - Service (free) | Cleartext passwords, hashs and salts, usernames, IPs, domain | :white_check_mark: |

*:key: - API key required*
*:new: - new in h8mail v2+*


-----
Expand Down Expand Up @@ -337,11 +337,12 @@ $ h8mail -t [email protected] -k "leak-lookup_pub=1bf94ff907f68d511de9a610
## :tangerine: Supported custom queries
| | username | domain | hash | password | ip |
|------------|:--------:|:------:|:----:|:--------:|:--------------:|
| WeLeakInfo | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| LeakLookup | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: |
| Snusbase | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| | username | domain | hash | password | ip |
|------------|:------------------:|:------------------:|:------------------:|:------------------:|:------------------:|
| WeLeakInfo | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| LeakLookup | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: |
| Snusbase | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Scylla.sh | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
As of writing, some service providers are undergoing upgrades and might support additional queries.
Expand Down Expand Up @@ -410,8 +411,8 @@ $ python3 -m h8mail -h
* [WeLeakInfo](https://weleakinfo.com/) for being developer friendly
* h8mail's Pypi integration is strongly based on the work of audreyr's [CookieCutter PyPackage](https://github.com/audreyr/cookiecutter-pypackage)
* Logo generated using Hatchful by Shopify
* [Jake Creps](https://twitter.com/jakecreps) for his [h8mail v2 introduction](https://jakecreps.com/2019/06/21/h8mail/)
* [Jake Creps](https://twitter.com/jakecreps) for his [h8mail v2 introduction](https://jakecreps.com/2019/06/21/h8mail/)
* [Alejandro Caceres](https://twitter.com/_hyp3ri0n) for making scylla.sh available. Be sure to [support](https://www.buymeacoffee.com/Eiw47ImnT) him if you can
-----
Expand Down
114 changes: 88 additions & 26 deletions h8mail/utils/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def dump(self):
print("Path: {}".format(self.filepath))
print("Line: {}".format(self.line))
print("Content: {}".format(self.content))
print()


class target:
Expand Down Expand Up @@ -79,34 +80,37 @@ def make_request(
)
# response = requests.request(url="http://127.0.0.1:8000", headers=self.headers, method=meth, timeout=timeout, allow_redirects=redirs, data=data, params=params)
if self.debug:
print(
c.fg.lightred + "\nDEBUG: Sent the following---------------------"
)
c.debug_news("DEBUG: Sent the following---------------------")
print(self.headers)
print(url, meth, data, params)
print("DEBUG: Received the following---------------------")
print(response.url)
print("\nDEBUG: RESPONSE HEADER---------------")
c.debug_news("DEBUG: Received the following---------------------")
c.debug_news(response.url)
c.debug_news("DEBUG: RESPONSE HEADER---------------------")
print(
"\n".join(
"{}: {}".format(k, v) for k, v in response.headers.items()
)
)
print("\nDEBUG: RESPONSE BODY---------------")
c.debug_news("DEBUG: RESPONSE BODY---------------------")
print(json.dumps(response.json(), indent=2))
print(c.reset)
print(response)
except Exception as ex:
c.bad_news("Request could not be made for " + self.target)
print(url)
print(ex)
print(response)
return response

# Soon to be deprecated
# Deprecated
def get_hibp(self):
try:
sleep(1.3)
c.info_news(c.bold + "HIBP free tier will stop working on the 2019/08/18")
c.info_news(c.bold + "You can already use a purchased API key using h8mail (config file)" + c.reset)
c.info_news(
c.bold
+ "You can already use a purchased API key using h8mail (config file)"
+ c.reset
)
url = "https://haveibeenpwned.com/api/v2/breachedaccount/{}?truncateResponse=true".format(
self.target
)
Expand Down Expand Up @@ -142,7 +146,7 @@ def get_hibp(self):
c.bad_news("HIBP error: " + self.target)
print(ex)

# Soon to be deprecated
# Deprecated
def get_hibp_pastes(self):
try:
sleep(1.3)
Expand Down Expand Up @@ -291,6 +295,10 @@ def get_emailrepio(self):
data = response.json()
if data["details"]["credentials_leaked"] is True:
self.pwned += int(data["references"]) # or inc num references
if data["references"] == 1:
self.data.append(("EMAILREP_LEAKS", "{} leaked credential".format(data["references"])))
else:
self.data.append(("EMAILREP_LEAKS", "{} leaked credentials".format(data["references"])))
c.good_news(
"Found {num} breaches for {target} using emailrep.io".format(
num=data["references"], target=self.target
Expand Down Expand Up @@ -318,6 +326,60 @@ def get_emailrepio(self):
c.bad_news("emailrep.io error: " + self.target)
print(ex)

def get_scylla(self, user_query="email"):
try:
sleep(0.5)
self.headers.update({"Accept": "application/json"})
if user_query == "email":
uri_scylla = 'Email: "' + self.target + '"'
elif user_query == "password":
uri_scylla = 'Password: "' + self.target + '"'
elif user_query == "username":
uri_scylla = 'User: "' + self.target + '"'
elif user_query == "ip":
uri_scylla = 'IP: "' + self.target + '"'
elif user_query == "hash":
uri_scylla = 'Hash: "' + self.target + '"'
elif user_query == "domain":
uri_scylla = 'Email: "*@' + self.target + '"'
url = "https://scylla.sh/search?q={}".format(
requests.utils.requote_uri(uri_scylla)
)
response = self.make_request(url)
self.headers.popitem()
if response.status_code not in [200, 404]:
c.bad_news("Could not contact scylla.sh for " + self.target)
print(response.status_code)
print(response)
return
data = response.json()
for d in data:
for field, k in d["_source"].items():
if "User" in field and k is not None:
self.data.append(("SCYLLA_USERNAME", k))
self.pwned += 1
if "Email" in field and k is not None and user_query is not "email":
self.data.append(("SCYLLA_EMAIL", k))
self.pwned += 1
if "Password" in field and k is not None:
self.data.append(("SCYLLA_PASSWORD", k))
self.pwned += 1
if "PassHash" in field and k is not None:
self.data.append(("SCYLLA_HASH", k))
self.pwned += 1
if "PassSalt" in field and k is not None:
self.data.append(("SCYLLA_HASHSALT", k))
self.pwned += 1
if "IP" in field and k is not None:
self.data.append(("SCYLLA_LASTIP", k))
self.pwned += 1
if "Domain" in field and k is not None:
self.data.append(("SCYLLA_SOURCE", k))
self.pwned += 1
except Exception as ex:
c.bad_news("scylla.sh error: " + self.target)
print(ex)

def get_hunterio_public(self):
try:
target_domain = self.target.split("@")[1]
Expand Down Expand Up @@ -381,8 +443,6 @@ def get_snusbase(self, api_url, api_key, user_query):
)
)
for result in response["result"]:
if result["tablenr"] and self.not_exists(result["tablenr"]):
self.data.append(("SNUS_SOURCE", result["tablenr"]))
if result["username"]:
self.data.append(("SNUS_USERNAME", result["username"]))
if result["email"] and self.not_exists(result["email"]):
Expand All @@ -404,6 +464,8 @@ def get_snusbase(self, api_url, api_key, user_query):
self.pwned += 1
if result["lastip"]:
self.data.append(("SNUS_LASTIP", result["lastip"]))
if result["tablenr"] and self.not_exists(result["tablenr"]):
self.data.append(("SNUS_SOURCE", result["tablenr"]))

except Exception as ex:
c.bad_news("Snusbase error with {target}".format(target=self.target))
Expand Down Expand Up @@ -456,15 +518,6 @@ def get_leaklookup_priv(self, api_key, user_query):
if self.not_exists(db):
self.data.append(("LKLP_SOURCE", db))
for d in data:
if "password" in d.keys():
if "plaintext" in d:
self.pwned += 1
self.data.append(("LKLP_HASH", d["password"]))
b_counter += 1
else:
self.pwned += 1
self.data.append(("LKLP_PASSWORD", d["password"]))
b_counter += 1
if "username" in d.keys():
self.pwned += 1
self.data.append(("LKLP_USERNAME", d["username"]))
Expand All @@ -477,6 +530,15 @@ def get_leaklookup_priv(self, api_key, user_query):
self.data.append(
("LKLP_RELATED", d["email_address"].strip())
)
if "password" in d.keys():
if "plaintext" in d:
self.pwned += 1
self.data.append(("LKLP_HASH", d["password"]))
b_counter += 1
else:
self.pwned += 1
self.data.append(("LKLP_PASSWORD", d["password"]))
b_counter += 1

c.good_news(
"Found {num} entries for {target} using LeakLookup (private)".format(
Expand Down Expand Up @@ -533,18 +595,18 @@ def get_weleakinfo_priv(self, api_key, user_query):
if response["Total"] == 0:
return
for result in response["Data"]:
if "Username" in result:
self.data.append(("WLI_USERNAME", result["Username"]))
if "Email" in result and self.not_exists(result["Email"]):
self.data.append(("WLI_RELATED", result["Email"].strip()))
if "Password" in result:
self.data.append(("WLI_PASSWORD", result["Password"]))
self.pwned += 1
if "Hash" in result:
self.data.append(("WLI_HASH", result["Hash"]))
self.pwned += 1
if "Username" in result:
self.data.append(("WLI_USERNAME", result["Username"]))
if "Database" in result and self.not_exists(result["Database"]):
self.data.append(("WLI_SOURCE", result["Database"]))
if "Email" in result and self.not_exists(result["Email"]):
self.data.append(("WLI_RELATED", result["Email"].strip()))
except Exception as ex:
c.bad_news(
"WeLeakInfo error with {target} (private)".format(target=self.target)
Expand Down
23 changes: 19 additions & 4 deletions h8mail/utils/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ def good_news(news):
print(colors.bold + colors.fg.green + "[>] " + colors.reset + news.strip())

@staticmethod
def test_news(news):
def debug_news(news):
"""
Print a Success
Print a Debug
"""
print(colors.bold + colors.fg.green + "[>] " + colors.reset + news.strip())
print()
print(colors.bold + colors.fg.lightred + "[@] " + news + colors.reset)

@staticmethod
def bad_news(news):
Expand Down Expand Up @@ -195,7 +196,7 @@ def print_result(target, data, source):
colors.reset,
)
)
else:
elif "IP" in source:
print(
"{}{:15}{}|{}{:>25.25}{} > {}{}{}".format(
colors.fg.lightblue,
Expand All @@ -209,6 +210,20 @@ def print_result(target, data, source):
colors.reset,
)
)
else:
print(
"{}{:15}{}|{}{:>25.25}{} > {}{}{}".format(
colors.fg.lightblue,
source,
colors.fg.lightgrey,
colors.fg.pink,
target,
colors.fg.lightgrey,
colors.fg.lightgrey,
data,
colors.reset,
)
)

@staticmethod
def print_res_header(target):
Expand Down
Loading

0 comments on commit 2c8c8b9

Please sign in to comment.