khast3x / h8mail

Email OSINT & Password breach hunting tool, locally or using premium services. Supports chasing down related email
Other
4.04k stars 506 forks source link

Snusbase API not working #166

Open gmignotte opened 11 months ago

gmignotte commented 11 months ago

Hi,

I've been trying h8mail and i've noticed that Snusbase API not working.

I've try :

h8mail -t compromise.email@gmail.com -k "snusbase_url=https://api-experimental.snusbase.com/data/search" "snusbase_token=xxxxxxxxxxxxxxxxxxxxxxxx" --debug

The response :

[@] DEBUG: Received the following---------------------

[@] https://api-experimental.snusbase.com/data/search

[@] DEBUG: RESPONSE HEADER---------------------
Date: Wed, 16 Aug 2023 14:42:47 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 161
Connection: keep-alive
vary: Origin
access-control-allow-origin: *
x-response-time: 1.435750961303711
CF-Cache-Status: DYNAMIC
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=xxxxxxxxxxxxxxxxxxxxxxxx"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 7f7a72293a49fa44-AMS
alt-svc: h3=":443"; ma=86400

[@] DEBUG: RESPONSE BODY---------------------
b'{"statusCode":415,"code":"FST_ERR_CTP_INVALID_MEDIA_TYPE","error":"Unsupported Media Type","message":"Unsupported Media Type: application/x-www-form-urlencoded"}'
[!] [snusbase]> Unsupported Media Type
[!] Snusbase error with compromise-email@gmail.com

If I try directly with : curl --request POST --url https://api-experimental.snusbase.com/data/search --header "Auth: xxxxxxxxxxxxxxxxxxxxxxxxxxxx" --header "Content-Type: application/json" --data '{"terms":["compromise-email@gmail.com"], "types":["email"], "wildcard": false}' It works.

alegra8611 commented 5 months ago

The URL in the run.py is out of date, furthermore, the request method in the classes.py is also misconfigured (mainly in the update headers line). I am currently playing around with the code to see if I can get it to work. Further infor on the api documentation can be found here: https://docs.snusbase.com/#42-python.

EDIT: Never got it working, instead I created my own Python script that may be integratable with h8mail's codebase?

#!/usr/bin/python3

import argparse
import os
import json
import datetime
import requests
import fade
from colorama import Fore, Style
from urllib.request import Request, urlopen

user = os.getlogin() 

def clear_screen():
    os.system('cls' if os.name == 'nt' else 'clear')

def create_directory(category):
    directory = f"/home/{user}/snus-email-tool/{category}"
    if not os.path.exists(directory):
        os.makedirs(directory)
    return directory

def save_error_log(error):
    now = datetime.datetime.now()
    timestamp = now.strftime("%Y-%m-%d_%H-%M-%S")
    log_directory = create_directory("logs")
    log_file = os.path.join(log_directory, f"error_{timestamp}.log")
    with open(log_file, "w") as file:
        file.write(str(error))

snusbase_auth = 'sbuncd7b2bfcflweh3dkbeqsuzlzqk'
snusbase_api = 'https://api-experimental.snusbase.com/'

def api_email():
    clear_screen()
    text_default_fade = fade.greenblue(text_default)
    print(text_default_fade)

    def send_request(url, body=None):

        headers = {
            'Auth': snusbase_auth,
            'Content-Type': 'application/json',
        }
        method = 'POST' if body else 'GET'
        data = json.dumps(body) if body else None
        response = requests.request(method, snusbase_api + url, headers=headers, data=data)
        return response.json()

    if __name__ == "__main__":
         parser = argparse.ArgumentParser()
         parser.add_argument('-F', '--filename', type=str)
         args = parser.parse_args()
         filename = args.filename

         f = open(filename, 'r')
         for line in f:
                result = line.split()
                search_response = send_request('data/search', {
                    'terms': result,
                    'types': ["email"],
                    'wildcard': False,
                })

                formatted_response = json.dumps(search_response, indent=2)
                print(formatted_response)

                output_directory = create_directory("output")
                output_file = os.path.join(output_directory, f"{result}.json")
                user_path = os.path.join(f"{output_file}")
                Results_default = f"Results have been saved to: {user_path}"
                Results_default_fade = fade.purpleblue(Results_default)
                print("\n") 
                print (Results_default_fade)
                with open(output_file, "w") as outfile:
                    outfile.write(formatted_response)

text_default ='''
              DMMMMMMD                 
           MMMMMMMMMMMMMMMM             
         MMMMMMMMMMMMMMMMMMMM           
        MMMMMMMMMMMMMMMMMMMMMM.         
      MMMMMMMMMMMMMMMMMMMMMMMMMM        
     MMMMMMMMMMMMMMMMMMMMMMMMMMMM       
    .MMMMMMMMMMMMMMMMMMMMMMMMMMMM       
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM      
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM      
    MM+  MMMMMMMMMMMMMMMMMMMM$  MM      
    +M.    ZMMMMMMMMMMMMMMO     M       
     MM       MMMMMMMMMM       MM       
     MMD         MMMM.        .MM       
      MMMMMM    MMM=MMI   DMMMMM        
       MMMMMMMMMMM  +MMMMMMMMMMM        
      MMMMMMMMMMM 8M MMMMMMMMMMMD       
      MMMMM   MMM.MM MMMM    MMM        
       MMM7   MMMMMMMMMMM    M8         
              MM MM M MMM               
              MM MM,M MM                
              MM.MM=M MM                
              MM~MM+M MM                
              8M~MM+M MM                
              ,M~MMIM MM                
               M:MMZM MM                
               M.MMIM MM 

Authors: Alegra
'''

api_email()
cstrv commented 1 month ago

in run.py

snusbase_url = "https://api-experimental.snusbase.com/"

in classes.py

def get_snusbase(self, api_url, api_key, user_query):
        try:
            # Определяем тип поиска
            if user_query == "ip":
                user_query = "lastip"
            if user_query == "domain":
                search_terms = ["%@{}".format(self.target)]
                search_types = ["email"]
            else:
                search_terms = [self.target]
                search_types = [user_query]

            # Готовим запрос
            payload = {
                "terms": search_terms,
                "types": search_types,
                "wildcard": False
            }

            c.info_news("[" + self.target + "]>[snusbase]")
            url = api_url + "data/search"
            self.headers.update({"Auth": api_key, "Content-Type": "application/json"})

            # Отправляем запрос
            req = self.make_request(url, meth="POST", data=json.dumps(payload))
            self.headers.popitem()
            self.headers.popitem()

            response = req.json()

            if self.debug:
                print("DEBUG: Snusbase response:", json.dumps(response, indent=4))

            if "error" in response:
                c.bad_news("[snusbase]> " + response["error"])
                c.bad_news("[snusbase]> " + response["message"])
                return 1

            if "size" in response:
                c.good_news(
                    "Found {num} entries for {target} using Snusbase".format(
                        num=response["size"], target=self.target
                    )
                )
                for source, results in response["results"].items():
                    for result in results:
                        if "email" in result and self.not_exists(result["email"]):
                            self.data.append(("SNUS_RELATED", result["email"].strip()))
                        if "username" in result:
                            self.data.append(("SNUS_USERNAME", result["username"]))
                            self.pwned += 1
                        if "password" in result:
                            self.data.append(("SNUS_PASSWORD", result["password"]))
                            self.pwned += 1
                        if "hash" in result:
                            if "salt" in result:
                                self.data.append(
                                    (
                                        "SNUS_HASH_SALT",
                                        result["hash"].strip() + " : " + result["salt"].strip(),
                                    )
                                )
                                self.pwned += 1
                            else:
                                self.data.append(("SNUS_HASH", result["hash"]))
                                self.pwned += 1
                        if "lastip" in result:
                            self.data.append(("SNUS_LASTIP", result["lastip"]))
                            self.pwned += 1
                        if "name" in result:
                            self.data.append(("SNUS_NAME", result["name"]))
                            self.pwned += 1
                        if self.not_exists(source):
                            self.data.append(("SNUS_SOURCE", source))
        except Exception as ex:
            c.bad_news(f"Snusbase error with {self.target}")
            print(ex)

def make_request(
        self,
        url,
        meth="GET",
        timeout=20,
        redirs=True,
        data=None,
        params=None,
        verify=True,
        auth=None,
    ):
        try:
            headers = self.headers
            if meth == "POST" and data is not None:
                headers = {**self.headers, "Content-Type": "application/json"}

            response = requests.request(
                url=url,
                headers=headers,
                method=meth,
                timeout=timeout,
                allow_redirects=redirs,
                data=data,
                params=params,
                verify=verify,
                auth=auth,
            )

            if self.debug:
                c.debug_news("DEBUG: Sent the following---------------------")
                print(headers)
                print(url, meth, data, params)
                c.debug_news("DEBUG: Received the following---------------------")
                c.debug_news(response.url)
                c.debug_news("DEBUG: RESPONSE HEADER---------------------")
                print(
                    "\n".join(
                        f"{k}: {v}" for k, v in response.headers.items()
                    )
                )
                c.debug_news("DEBUG: RESPONSE BODY---------------------")
                print(response.content)
        except Exception as ex:
            c.bad_news("Request could not be made for " + self.target)
            print(url)
            print(ex)
        return response     

this should help