Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
35ac275
Update README.md
OSINT-TECHNOLOGIES Feb 3, 2025
59bc899
Update SECURITY.md
OSINT-TECHNOLOGIES Feb 3, 2025
1d57a0e
Update LICENSE
OSINT-TECHNOLOGIES Feb 3, 2025
e79524d
Bumped version
OSINT-TECHNOLOGIES Feb 3, 2025
37e4c79
Added config parameter for selenium snapshotting setups
OSINT-TECHNOLOGIES Feb 3, 2025
c237cb8
Added logging and config paragraphs in docs
OSINT-TECHNOLOGIES Feb 3, 2025
3a1356a
Create config.md (blank)
OSINT-TECHNOLOGIES Feb 3, 2025
330dae6
Create logging.md (blank)
OSINT-TECHNOLOGIES Feb 3, 2025
83f607c
Added folder for future snapshotting modules
OSINT-TECHNOLOGIES Feb 3, 2025
f15be4e
Update pyproject.toml with new requirements
OSINT-TECHNOLOGIES Feb 3, 2025
f91ee74
Update requirements.txt with new requirements
OSINT-TECHNOLOGIES Feb 3, 2025
c036141
Added basic functionality of page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
5fdad50
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
79c6cd1
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
d5aaccb
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
675f908
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
6a0db74
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
a75f4de
Added basic support for page snapshotting
OSINT-TECHNOLOGIES Feb 3, 2025
5ab2583
Update poetry.lock with new requirements
OSINT-TECHNOLOGIES Feb 3, 2025
394cc72
Update README.md
OSINT-TECHNOLOGIES Feb 3, 2025
84f10b2
Delete apis/api_keys.db
OSINT-TECHNOLOGIES Feb 4, 2025
0840534
Delete apis/api_keys_reference.db
OSINT-TECHNOLOGIES Feb 4, 2025
410888b
Added HudsonRock API key field (not required for scans)
OSINT-TECHNOLOGIES Feb 4, 2025
c3b8b2d
Added HudsonRock API key field (not required for scans)
OSINT-TECHNOLOGIES Feb 4, 2025
bc88590
Added HudsonRock API support for DB interactions
OSINT-TECHNOLOGIES Feb 4, 2025
8eabc5b
Created basic implementation of HudsonRock API logic
OSINT-TECHNOLOGIES Feb 4, 2025
04520b8
Added basic support for HudsonRock API
OSINT-TECHNOLOGIES Feb 4, 2025
4ad6784
Added basic support for HudsonRock API
OSINT-TECHNOLOGIES Feb 4, 2025
23348dc
Update README.md
OSINT-TECHNOLOGIES Feb 4, 2025
01cfd4c
Added HTML snapshotting support
OSINT-TECHNOLOGIES Feb 5, 2025
65ccc04
Added HTML snapshotting support
OSINT-TECHNOLOGIES Feb 5, 2025
80a9e21
Created html_snapshotting.py module
OSINT-TECHNOLOGIES Feb 5, 2025
fd5b3f7
Update README.md
OSINT-TECHNOLOGIES Feb 5, 2025
5b20aac
Addded support of HudsonRock API results reporting
OSINT-TECHNOLOGIES Feb 5, 2025
857d92e
Added HTML preparation function for formatted_output
OSINT-TECHNOLOGIES Feb 5, 2025
91de206
Added support of HudsonRock API results reporting
OSINT-TECHNOLOGIES Feb 5, 2025
c2ffbcc
Added HudsonRock API results transfering logic to reporting modules
OSINT-TECHNOLOGIES Feb 5, 2025
44254bb
Update dpulse.py
OSINT-TECHNOLOGIES Feb 5, 2025
da767eb
Update README.md with API keys requirements
OSINT-TECHNOLOGIES Feb 5, 2025
baaec5d
Update api.md with APIs key requirements
OSINT-TECHNOLOGIES Feb 5, 2025
ca72459
Update api.md with some HudsonRock API info
OSINT-TECHNOLOGIES Feb 5, 2025
a5174c2
Fixed bug which did not allowed to use APIs except HudsonRock
OSINT-TECHNOLOGIES Feb 6, 2025
ee977a6
Corrected minor cosmetical issue
OSINT-TECHNOLOGIES Feb 6, 2025
b7dbd0a
Added snapshotting_ui_mark usage in HTML report
OSINT-TECHNOLOGIES Feb 6, 2025
a00a101
Added snapshotting_ui_mark usage in HTML report
OSINT-TECHNOLOGIES Feb 6, 2025
12a40f0
Fixed "dirty API key" problem for VirusTotal API (added key clean pro…
OSINT-TECHNOLOGIES Feb 6, 2025
887c99c
Fixed "dirty API key" problem for SecurityTrails API
OSINT-TECHNOLOGIES Feb 6, 2025
3a7e0d5
Cleaned-up VirusTotal API output
OSINT-TECHNOLOGIES Feb 6, 2025
3b20787
Update README.md
OSINT-TECHNOLOGIES Feb 6, 2025
39020cb
Changed output's visual design
OSINT-TECHNOLOGIES Feb 6, 2025
20c16c6
Changed output's visual design
OSINT-TECHNOLOGIES Feb 6, 2025
9020e66
Unified reporting data from VirusTotal API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
2714654
Unified reporting data from VirusTotal API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
5e3f9dd
Unified reporting data from VirusTotal API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
09bbcc3
Update dpulse.py
OSINT-TECHNOLOGIES Feb 6, 2025
c4da16c
Update api_securitytrails.py
OSINT-TECHNOLOGIES Feb 6, 2025
8f45809
Changed SecurityTrails output's visual design
OSINT-TECHNOLOGIES Feb 6, 2025
0c64940
Unified output of SecurityTrails API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
c6868ea
Unified output of SecurityTrails API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
7e54d86
Unified output of SecurityTrails API in one variable
OSINT-TECHNOLOGIES Feb 6, 2025
884ee19
Update dpulse.py
OSINT-TECHNOLOGIES Feb 6, 2025
ce9fe7c
Disabled SI variant selection (PageSearch SI end of life)
OSINT-TECHNOLOGIES Feb 6, 2025
70f54b6
Update README.md
OSINT-TECHNOLOGIES Feb 6, 2025
758086f
Delete docs/dpulse-docs/docs/pagesearch_sitemap.md
OSINT-TECHNOLOGIES Feb 6, 2025
9aa3e23
Deleted PageSearch Sitemap Inspection part from docs
OSINT-TECHNOLOGIES Feb 6, 2025
bcbf6ff
Removed PageSearch Sitemap Inspection info from docs
OSINT-TECHNOLOGIES Feb 6, 2025
37a0af1
Update README.md
OSINT-TECHNOLOGIES Feb 6, 2025
0a69006
Deactivated PageSearch SI module usage
OSINT-TECHNOLOGIES Feb 7, 2025
f589077
Removed PageSearch SI module usage
OSINT-TECHNOLOGIES Feb 7, 2025
0455cdb
Removed PageSearch Sitemap Inspection module
OSINT-TECHNOLOGIES Feb 7, 2025
9ad3fb3
Removed PageSearch Sitemap Inspection results from HTML template
OSINT-TECHNOLOGIES Feb 7, 2025
ab48989
Temporarily disabled XLSX reporting selection
OSINT-TECHNOLOGIES Feb 7, 2025
574e546
Merge branch 'main' into rolling
OSINT-TECHNOLOGIES Feb 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
</p>

<p align="center">
<img alt="Static Badge" src="https://img.shields.io/badge/supports-virustotal_api-red?style=for-the-badge"> <img alt="Static Badge" src="https://img.shields.io/badge/supports-securitytrails_api-red?style=for-the-badge">

<img alt="Static Badge" src="https://img.shields.io/badge/supports-virustotal_api (key required)-red?style=for-the-badge"> <img alt="Static Badge" src="https://img.shields.io/badge/supports-securitytrails_api (key required)-red?style=for-the-badge"> <img alt="Static Badge" src="https://img.shields.io/badge/supports-hudsonrock_api (no key required)-red?style=for-the-badge">
</p>

> Attention! DPULSE is a research tool. It is not intended for criminal activities! Use DPULSE only on allowed domains and for legal purposes!
Expand Down Expand Up @@ -58,7 +57,7 @@ DPULSE is a software solution for conducting OSINT research in relation to a cer
- CPEs, used web-technologies and so on
- It also can download sitemap.xml and robots.txt files from a domain

2. ***PageSearch standard scan:*** extended subdomains deep search function, which starts in addition to basic scan and which can find:
2. ***PageSearch scan:*** extended subdomains deep search function, which starts in addition to basic scan and which can find:
- more e-mail addresses
- API keys
- exposed passwords
Expand All @@ -67,18 +66,17 @@ DPULSE is a software solution for conducting OSINT research in relation to a cer
- documents, config files, databases files (and PageSearch can download them!)
- specified words by user in PDF files

3. ***PageSearch Sitemap inspection scan:*** sitemap links crawler which starts in addition to basic scan and which can find even more e-mails

4. ***Dorking scan:*** extended domain research function with prepared Google Dorking databases for different purposes, such as:
3. ***Dorking scan:*** extended domain research function with prepared Google Dorking databases for different purposes, such as:
- IoT dorking
- files dorking
- admin panels dorking
- web elements dorking
- Moreover, this mode allows you to create your own custom Google Dorking database

6. ***API scan:*** extended domain research function with prepared functions for 3rd party APIs usage. Currently DPULSE supports these API:
4. ***API scan:*** extended domain research function with prepared functions for 3rd party APIs usage. Currently DPULSE supports these API:
- VirusTotal API (for brief domain information gathering)
- SecurityTrails API (deep subdomains and DNS enumeration)
- HudsonRock API (for querying a database with exposed computers which were compromised through global info-stealer campaigns)

Finally, DPULSE compiles all found data into an easy-to-read HTML or XLSX report by category. It also saves all information about scan in local report storage database, which can be restored later.

Expand Down Expand Up @@ -164,8 +162,8 @@ If you have problems with starting installer.sh, you should try to use `dos2unix


# Tasks to complete before new release
- [ ] Add web pages snapshoting (with screenshots)
- [ ] Add web pages snapshoting (with web pages copying as HTML objects)
- [x] Add web pages snapshoting (with screenshots)
- [x] Add web pages snapshoting (with web pages copying as HTML objects)
- [ ] Add web pages snapshoting (with Wayback Machine)

# DPULSE mentions in social medias
Expand Down
150 changes: 150 additions & 0 deletions apis/api_hudsonrock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import requests
from colorama import Fore, Style
import re

def hudsonrock_html_prep(formatted_output):
formatted_output = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', formatted_output)
start_marker = "=== HUDSONROCK API REPORT ==="
end_marker = "[+] Email Data:"
start_index = formatted_output.find(start_marker)
end_index = formatted_output.find(end_marker)
if start_index != -1 and end_index != -1:
formatted_output = formatted_output[:start_index] + formatted_output[end_index:]
return formatted_output

def api_hudsonrock_get(email=None, username=None, domain=None, ip=None):
base_url = "https://cavalier.hudsonrock.com/api/json/v2/osint-tools/"
results = {}

def make_request(url):
try:
response = requests.get(url)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
return {'error': str(e)}

if email:
email_url = f"{base_url}search-by-email?email={email}"
results['email'] = make_request(email_url)

if username:
username_url = f"{base_url}search-by-username?username={username}"
results['username'] = make_request(username_url)

if domain:
domain_url = f"{base_url}search-by-domain?domain={domain}"
results['domain'] = make_request(domain_url)

urls_by_domain_url = f"{base_url}urls-by-domain?domain={domain}"
results['urls_by_domain'] = make_request(urls_by_domain_url)

if ip:
ip_url = f"{base_url}search-by-ip?ip={ip}"
results['ip'] = make_request(ip_url)

return results


def api_hudsonrock_check(domain, ip, email, username):
results = api_hudsonrock_get(email, username, domain, ip)
formatted_output = Fore.LIGHTBLUE_EX + "\n=== HUDSONROCK API REPORT ===\n" + Style.RESET_ALL
formatted_output += f"\n{Fore.LIGHTBLUE_EX}[+] Provided Data:{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Domain:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{domain}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}IP:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{ip}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}E-mail:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{email}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Username:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{username}{Style.RESET_ALL}\n"

def format_section(title, data):
nonlocal formatted_output
formatted_output += f"\n{Fore.LIGHTBLUE_EX}[+] {title}:{Style.RESET_ALL}\n"
if 'error' in data:
formatted_output += f"{Fore.RED}Error appeared when trying to get results for {title} requests. Probably given data is incorrect.{Style.RESET_ALL}\n"
return

if title == 'Email Data':
formatted_output += f"{Fore.GREEN}Message:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('message', 'No message available')}{Style.RESET_ALL}\n"
for i, stealer in enumerate(data.get('stealers', []), 1):
formatted_output += f"\n{Fore.GREEN}--- STEALER {i} ---{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Computer Name:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('computer_name', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}OS:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('operating_system', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Date Compromised:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('date_compromised', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Malware Path:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('malware_path', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}IP:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('ip', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Passwords:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_passwords', []))}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Logins:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_logins', []))}{Style.RESET_ALL}\n"

elif title == 'Username Data':
formatted_output += f"{Fore.GREEN}Message:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('message', 'No message available')}{Style.RESET_ALL}\n"
for i, stealer in enumerate(data.get('stealers', []), 1):
formatted_output += f"\n{Fore.GREEN}--- STEALER {i} ---{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Stealer Family:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('stealer_family', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Computer Name:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('computer_name', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}OS:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('operating_system', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Date Compromised:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('date_compromised', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Malware Path:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('malware_path', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}IP:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('ip', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Passwords:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_passwords', []))}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Logins:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_logins', []))}{Style.RESET_ALL}\n"

elif title == 'Domain Data':
formatted_output += f"{Fore.GREEN}Total Entries:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('total', 0)}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Total Stealers:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('totalStealers', 0)}{Style.RESET_ALL}\n"
formatted_output += f"\n{Fore.GREEN}Sample Employee URLs:{Style.RESET_ALL}\n"
employee_urls = data.get('data', {}).get('employees_urls', [])
if employee_urls:
for url_data in employee_urls[:10]:
formatted_output += f"{Fore.GREEN}Type:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('type', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| URL:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('url', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| Occurrence:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('occurrence', 'N/A')}{Style.RESET_ALL}\n"
else:
formatted_output += f"{Fore.RED}No employee URLs available.{Style.RESET_ALL}\n"

elif title == 'Attack Surface Data':
formatted_output += f"{Fore.GREEN}Message:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('message', 'No message available')}{Style.RESET_ALL}\n"
formatted_output += f"\n{Fore.GREEN}Sample Employee URLs:{Style.RESET_ALL}\n"
employees = data.get('data', {}).get('employees_urls', [])
if employees:
for url_data in employees[:10]:
formatted_output += f"{Fore.GREEN}Type:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('type', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| URL:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('url', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| Occurrence:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('occurrence', 'N/A')}{Style.RESET_ALL}\n"
else:
formatted_output += f"{Fore.RED}No employee URLs available.{Style.RESET_ALL}\n"
formatted_output += f"\n{Fore.GREEN}Sample Client URLs:{Style.RESET_ALL}\n"
clients = data.get('data', {}).get('clients_urls', [])
if clients:
for url_data in clients[:10]:
formatted_output += f"{Fore.GREEN}Type:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('type', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| URL:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('url', 'N/A')}{Style.RESET_ALL}"
formatted_output += f" {Fore.GREEN}| Occurrence:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{url_data.get('occurrence', 'N/A')}{Style.RESET_ALL}\n"
else:
formatted_output += f"{Fore.LIGHTCYAN_EX}No client URLs available.{Style.RESET_ALL}\n"

elif title == 'IP Data':
formatted_output += f"{Fore.GREEN}Message:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{data.get('message', 'No message available')}{Style.RESET_ALL}\n"
if data.get('stealers'):
for i, stealer in enumerate(data.get('stealers', []), 1):
formatted_output += f"\n{Fore.GREEN}--- STEALER {i} ---{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Computer Name:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('computer_name', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}OS:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('operating_system', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Date Compromised:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('date_compromised', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Malware Path:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('malware_path', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}IP:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{stealer.get('ip', 'Not Found')}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Passwords:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_passwords', []))}{Style.RESET_ALL}\n"
formatted_output += f"{Fore.GREEN}Top Logins:{Style.RESET_ALL} {Fore.LIGHTCYAN_EX}{', '.join(stealer.get('top_logins', []))}{Style.RESET_ALL}\n"
formatted_output += "\n"

if 'email' in results:
format_section('Email Data', results['email'])
if 'username' in results:
format_section('Username Data', results['username'])
if 'domain' in results:
format_section('Domain Data', results['domain'])
if 'urls_by_domain' in results:
format_section('Attack Surface Data', results['urls_by_domain'])
if 'ip' in results:
format_section('IP Data', results['ip'])

print(formatted_output)
return formatted_output
Binary file modified apis/api_keys.db
Binary file not shown.
Binary file modified apis/api_keys_reference.db
Binary file not shown.
Loading