🏄♂️ SubSurfer
SubSurfer is a fast and efficient subdomain enumeration and web property identification tool.
🌟 Features
- Red Team/Bug Bounty Support: Useful for both red team operations and web bug bounty projects
- High-Performance Scanning: Fast subdomain enumeration using asynchronous and parallel processing
- Port Scanning: Expand asset scanning range with customizable port selection
- Web Service Identification: Gather environmental details such as web servers and technology stacks
- Pipeline Integration: Supports integration with other tools using
-pipeweband-pipesuboptions - Modular Design: Can be imported and used as a Python module
- Continuous Updates: - Continuous Updates: New passive/active modules will continue to be added
🚀 Installation
bash
git clone https://github.com/arrester/subsurfer.git
cd subsurfer
or
Python
pip install subsurfer
📖 Usage
CLI Mode
Basic Scan
subsurfer -t vulnweb.com
Enable Active Scanning
subsurfer -t vulnweb.com -a
Include Port Scanning
subsurfer -t vulnweb.com -dp # Default Port
subsurfer -t vulnweb.com -p 80,443,8080-8090 # Custom ports
Pipeline Output
subsurfer -t vulnweb.com -pipeweb # Output only web server
subsurfer -t vulnweb.com -pipesub # Output only subdomain results
Using as a Python Module
Subdomain Scan
from subsurfer.core.controller.controller import SubSurferController
import asyncio
async def main():
controller = SubSurferController(
target="vulnweb.com",
verbose=1,
active=False # Active Scan Option
)
# Collect subdomains
subdomains = await controller.collect_subdomains()
# Print results
print(f"Discovered Subdomains: {len(subdomains)}개")
for subdomain in sorted(subdomains):
print(subdomain)
if __name__ == "__main__":
asyncio.run(main())
Port Scan
from subsurfer.core.controller.controller import SubSurferController
import asyncio
async def main():
controller = SubSurferController(
target="vulnweb.com",
verbose=1
)
# Collect subdomains
subdomains = await controller.collect_subdomains()
# Default ports (80, 443)
ports = None
# Set port scan options
# ports = controller.parse_ports() # Default ports
# Or specify custom ports
# ports = controller.parse_ports("80,443,8080-8090")
# Web service scanning
web_services = await controller.scan_web_services(subdomains, ports)
# Print web servers
print("\n웹 서버:")
for server in sorted(web_services['web_servers']):
print(f"https://{server}")
# Print active services
print("\n활성화된 서비스:")
for service in sorted(web_services['enabled_services']):
print(service)
# Print discovered URLs and ports
print("\n발견된 URL:")
for subdomain, urls in web_services['all_urls'].items():
for url, port in urls:
print(f"{url}:{port}")
if __name__ == "__main__":
asyncio.run(main())
Result Save
from subsurfer.core.controller.controller import SubSurferController
import asyncio
async def main():
controller = SubSurferController("vulnweb.com")
# Collect subdomains and scan web services
subdomains = await controller.collect_subdomains()
web_services = await controller.scan_web_services(subdomains)
# Save results
results_dict = {
'subdomains': subdomains,
'web_services': web_services.get('web_services', {}),
'web_servers': web_services.get('web_servers', set()),
'enabled_services': web_services.get('enabled_services', set()),
'all_urls': web_services.get('all_urls', {}) # Includes URL and port information
}
# Generate default result file path (stored in the "results" directory)
output_path = controller.get_output_path()
controller.save_results(results_dict, output_path)
if __name__ == "__main__":
asyncio.run(main())
🧪 Testing
Passive Handler Test
pytest tests/handlers/test_passive_handler.py -v
Active Handler Test
pytest tests/handlers/test_active_handler.py -v
🗺️ To-Do List
Version 1.5
- Add new passive modules
- Add Cloud Detect modules
Version 2.0
- Add AI Recon Model
📋 Requirements
- Recommended: Python 3.13.0 or later
- aiohttp
- rich
- pytest (for testing)
📝 License
MIT License
🤝 Contributions
Bug Report, Feature Suggestions, Issue Report
Metadata
Release files for subsurfer 1.2.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| subsurfer-1.2.7.tar.gz | 34.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| subsurfer-1.2.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 86.6 kB
Release files / subsurfer-1.2.7.tar.gz
| Download URL | subsurfer-1.2.7.tar.gz |
|---|---|
| Size | 34.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0d1792cd6f7310288d5eff071240a59f19bd1dba32ed82f67a89adc1cc3ac2e
|
|
BLAKE2b-256 checksum How to use checksums |
6d5a5fb6309f714f65e7ea18c2de4ca5521eb02002e2050b11281fb6b8f4c800
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 12, 2026.
Transparency logRelease files / subsurfer-1.2.7-py3-none-any.whl
| Download URL | subsurfer-1.2.7-py3-none-any.whl |
|---|---|
| Size | 52.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06c0c1f64221b5b8210da6cb118a6370b3f7bb801ff188881166aa3c86a93149
|
|
BLAKE2b-256 checksum How to use checksums |
8644cc3cd6f8a16576d1decb8d6035e81056537ca94823b756959415f69417f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 12, 2026.
Transparency log