subsurfer 0.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. subsurfer-0.1.8/LICENSE +21 -0
  2. subsurfer-0.1.8/MANIFEST.in +4 -0
  3. subsurfer-0.1.8/PKG-INFO +242 -0
  4. subsurfer-0.1.8/README.md +198 -0
  5. subsurfer-0.1.8/setup.cfg +4 -0
  6. subsurfer-0.1.8/setup.py +51 -0
  7. subsurfer-0.1.8/subsurfer/__init__.py +5 -0
  8. subsurfer-0.1.8/subsurfer/__main__.py +16 -0
  9. subsurfer-0.1.8/subsurfer/core/__init__.py +1 -0
  10. subsurfer-0.1.8/subsurfer/core/cli/__init__.py +1 -0
  11. subsurfer-0.1.8/subsurfer/core/cli/cli.py +147 -0
  12. subsurfer-0.1.8/subsurfer/core/cli/parser.py +47 -0
  13. subsurfer-0.1.8/subsurfer/core/config/__init__.py +1 -0
  14. subsurfer-0.1.8/subsurfer/core/config/config.yaml +18 -0
  15. subsurfer-0.1.8/subsurfer/core/controller/__init__.py +0 -0
  16. subsurfer-0.1.8/subsurfer/core/controller/controller.py +215 -0
  17. subsurfer-0.1.8/subsurfer/core/handler/__init__.py +0 -0
  18. subsurfer-0.1.8/subsurfer/core/handler/active/srv.py +89 -0
  19. subsurfer-0.1.8/subsurfer/core/handler/active/sweep.py +120 -0
  20. subsurfer-0.1.8/subsurfer/core/handler/active/zone.py +102 -0
  21. subsurfer-0.1.8/subsurfer/core/handler/active_handler.py +88 -0
  22. subsurfer-0.1.8/subsurfer/core/handler/passive/abuseipdb.py +60 -0
  23. subsurfer-0.1.8/subsurfer/core/handler/passive/alienvault.py +52 -0
  24. subsurfer-0.1.8/subsurfer/core/handler/passive/anubisdb.py +73 -0
  25. subsurfer-0.1.8/subsurfer/core/handler/passive/bufferover.py +99 -0
  26. subsurfer-0.1.8/subsurfer/core/handler/passive/crtsh.py +46 -0
  27. subsurfer-0.1.8/subsurfer/core/handler/passive/digitorus.py +95 -0
  28. subsurfer-0.1.8/subsurfer/core/handler/passive/hackertarget.py +56 -0
  29. subsurfer-0.1.8/subsurfer/core/handler/passive/myssl.py +74 -0
  30. subsurfer-0.1.8/subsurfer/core/handler/passive/shrewdeye.py +52 -0
  31. subsurfer-0.1.8/subsurfer/core/handler/passive/subdomaincenter.py +53 -0
  32. subsurfer-0.1.8/subsurfer/core/handler/passive/urlscan.py +55 -0
  33. subsurfer-0.1.8/subsurfer/core/handler/passive_handler.py +103 -0
  34. subsurfer-0.1.8/subsurfer/core/handler/web/web_scanner.py +136 -0
  35. subsurfer-0.1.8/subsurfer/subsurfer.py +68 -0
  36. subsurfer-0.1.8/subsurfer.egg-info/PKG-INFO +242 -0
  37. subsurfer-0.1.8/subsurfer.egg-info/SOURCES.txt +46 -0
  38. subsurfer-0.1.8/subsurfer.egg-info/dependency_links.txt +1 -0
  39. subsurfer-0.1.8/subsurfer.egg-info/entry_points.txt +2 -0
  40. subsurfer-0.1.8/subsurfer.egg-info/requires.txt +9 -0
  41. subsurfer-0.1.8/subsurfer.egg-info/top_level.txt +1 -0
  42. subsurfer-0.1.8/tests/__init__.py +0 -0
  43. subsurfer-0.1.8/tests/cli/__init__.py +0 -0
  44. subsurfer-0.1.8/tests/cli/test_cli.py +0 -0
  45. subsurfer-0.1.8/tests/config/config.yaml +18 -0
  46. subsurfer-0.1.8/tests/handlers/__init__.py +0 -0
  47. subsurfer-0.1.8/tests/handlers/test_active_handler.py +78 -0
  48. subsurfer-0.1.8/tests/handlers/test_passive_handler.py +176 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 arrester
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include subsurfer/core/config/config.yaml
3
+ recursive-include subsurfer *
4
+ recursive-include tests *
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.2
2
+ Name: subsurfer
3
+ Version: 0.1.8
4
+ Summary: Red Teaming and Web Bug Bounty Fast Asset Identification Tool
5
+ Home-page: https://github.com/arrester/subsurfer
6
+ Author: arrester
7
+ Author-email: arresterloyal@gmail.com
8
+ Project-URL: Bug Reports, https://github.com/arrester/subsurfer/issues
9
+ Project-URL: Source, https://github.com/arrester/subsurfer
10
+ Project-URL: Documentation, https://github.com/arrester/subsurfer#readme
11
+ Keywords: security,subdomain enumeration,bug bounty,red team,web security
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Topic :: Security
16
+ Classifier: Topic :: Internet :: WWW/HTTP
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: rich>=13.7.0
25
+ Requires-Dist: aiohttp>=3.9.1
26
+ Requires-Dist: beautifulsoup4>=4.12.2
27
+ Requires-Dist: dnspython>=2.4.2
28
+ Requires-Dist: pyyaml>=6.0.1
29
+ Requires-Dist: asyncio>=3.4.3
30
+ Requires-Dist: pytest>=7.4.3
31
+ Requires-Dist: pytest-asyncio>=0.23.2
32
+ Requires-Dist: python-Wappalyzer>=0.3.1
33
+ Dynamic: author
34
+ Dynamic: author-email
35
+ Dynamic: classifier
36
+ Dynamic: description
37
+ Dynamic: description-content-type
38
+ Dynamic: home-page
39
+ Dynamic: keywords
40
+ Dynamic: project-url
41
+ Dynamic: requires-dist
42
+ Dynamic: requires-python
43
+ Dynamic: summary
44
+
45
+ # πŸ„β€β™‚οΈ SubSurfer
46
+
47
+ ![Python Version](https://img.shields.io/badge/python-3.13%2B-blue)
48
+ ![License](https://img.shields.io/badge/license-MIT-green)
49
+ ![Version](https://img.shields.io/badge/version-0.1-orange)
50
+
51
+ SubSurferλŠ” λΉ λ₯΄κ³  효율적인 μ„œλΈŒλ„λ©”μΈ μ—΄κ±° 및 μ›Ή μžμ‚° 식별 λ„κ΅¬μž…λ‹ˆλ‹€.
52
+
53
+ <br>
54
+
55
+ ## 🌟 νŠΉμ§•
56
+ - **λ ˆλ“œνŒ€/λ²„κ·Έλ°”μš΄ν‹° 지원**: λ ˆλ“œνŒ€ μž‘μ „κ³Ό μ›Ή λ²„κ·Έλ°”μš΄ν‹° ν”„λ‘œμ νŠΈ λͺ¨λ‘μ—μ„œ ν™œμš© κ°€λŠ₯
57
+ - **κ³ μ„±λŠ₯ μŠ€μΊ”**: 비동기 및 병렬 처리λ₯Ό ν†΅ν•œ λΉ λ₯Έ μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
58
+ - **포트 μŠ€μΊ”**: μ‚¬μš©μž μ •μ˜ 포트 λ²”μœ„λ‘œ μžμ‚° μŠ€μΊ” λ²”μœ„ ν™•μž₯
59
+ - **μ›Ή μ„œλΉ„μŠ€ 식별**: μ›Ή μ„œλ²„, 기술 μŠ€νƒ λ“± ν™˜κ²½ 정보 μˆ˜μ§‘
60
+ - **νŒŒμ΄ν”„λΌμΈ 지원**: `-pipeweb`, `-pipesub` μ˜΅μ…˜μœΌλ‘œ λ‹€λ₯Έ λ„κ΅¬μ™€μ˜ 연계 κ°€λŠ₯
61
+ - **λͺ¨λ“ˆν˜• 섀계**: Python λͺ¨λ“ˆλ‘œ importν•˜μ—¬ μ‚¬μš© κ°€λŠ₯
62
+ - **지속적 μ—…λ°μ΄νŠΈ**: μƒˆλ‘œμš΄ passive/active λͺ¨λ“ˆ 지속 μΆ”κ°€ μ˜ˆμ •
63
+
64
+ <br>
65
+
66
+ ## πŸš€ μ„€μΉ˜
67
+ <b>bash</b>
68
+ ```bash
69
+ git clone https://github.com/arrester/subsurfer.git
70
+ cd subsurfer
71
+ ```
72
+
73
+ or <br>
74
+
75
+ <b>Python</b>
76
+ ```bash
77
+ pip install -r requirements.txt
78
+ ```
79
+
80
+ <br>
81
+
82
+ ## πŸ“– μ‚¬μš©λ²•
83
+ ### CLI λͺ¨λ“œ
84
+ <b>κΈ°λ³Έ μŠ€μΊ”</b><br>
85
+ `subsurfer -t vulnweb.com`
86
+
87
+ <b>μ•‘ν‹°λΈŒ μŠ€μΊ” ν™œμ„±ν™”</b><br>
88
+ `subsurfer -t vulnweb.com -a`
89
+
90
+ <b>포트 μŠ€μΊ” 포함</b><br>
91
+ `subsurfer -t vulnweb.com -dp` # 기본 포트 <br>
92
+ `subsurfer -t vulnweb.com -p 80,443,8080-8090` # μ‚¬μš©μž μ •μ˜ 포트
93
+
94
+ <b>νŒŒμ΄ν”„λΌμΈ 좜λ ₯</b><br>
95
+ `subsurfer -t vulnweb.com -pipeweb` # μ›Ή μ„œλ²„ 결과만 좜λ ₯ <br>
96
+ `subsurfer -t vulnweb.com -pipesub` # μ„œλΈŒλ„λ©”μΈ 결과만 좜λ ₯
97
+
98
+ ### Python λͺ¨λ“ˆλ‘œ μ‚¬μš©
99
+ <b>Subdomain Scan</b><br>
100
+ ```python
101
+ from subsurfer.core.controller.controller import SubSurferController
102
+ import asyncio
103
+
104
+ async def main():
105
+ controller = SubSurferController(
106
+ target="vulnweb.com",
107
+ verbose=1,
108
+ active=False # Active Scan Option
109
+ )
110
+
111
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
112
+ subdomains = await controller.collect_subdomains()
113
+
114
+ # κ²°κ³Ό 좜λ ₯
115
+ print(f"발견된 μ„œλΈŒλ„λ©”μΈ: {len(subdomains)}개")
116
+ for subdomain in sorted(subdomains):
117
+ print(subdomain)
118
+
119
+ if __name__ == "__main__":
120
+ asyncio.run(main())
121
+ ```
122
+
123
+ <br>
124
+
125
+ <b>Port Scan</b><br>
126
+ ```python
127
+ from subsurfer.core.controller.controller import SubSurferController
128
+ import asyncio
129
+
130
+ async def main():
131
+ controller = SubSurferController(
132
+ target="vulnweb.com",
133
+ verbose=1
134
+ )
135
+
136
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
137
+ subdomains = await controller.collect_subdomains()
138
+
139
+ # κΈ°λ³Έ 80, 443 μŠ€μΊ” μ„€μ •
140
+ ports = None
141
+
142
+ # 포트 μŠ€μΊ” μ„€μ •
143
+ # ports = controller.parse_ports() # 기본 포트
144
+ # λ˜λŠ” μ‚¬μš©μž μ§€μ • 포트
145
+ # ports = controller.parse_ports("80,443,8080-8090")
146
+
147
+ # μ›Ή μ„œλΉ„μŠ€ μŠ€μΊ”
148
+ web_services = await controller.scan_web_services(subdomains, ports)
149
+
150
+ # μ›Ή μ„œλ²„ 좜λ ₯
151
+ print("\nμ›Ή μ„œλ²„:")
152
+ for server in sorted(web_services['web_servers']):
153
+ print(f"https://{server}")
154
+
155
+ # ν™œμ„±ν™”λœ μ„œλΉ„μŠ€ 좜λ ₯
156
+ print("\nν™œμ„±ν™”λœ μ„œλΉ„μŠ€:")
157
+ for service in sorted(web_services['enabled_services']):
158
+ print(service)
159
+
160
+ # URLκ³Ό 포트 정보 좜λ ₯
161
+ print("\n발견된 URL:")
162
+ for subdomain, urls in web_services['all_urls'].items():
163
+ for url, port in urls:
164
+ print(f"{url}:{port}")
165
+
166
+ if __name__ == "__main__":
167
+ asyncio.run(main())
168
+ ```
169
+
170
+ <br>
171
+
172
+ <b>Result Save</b><br>
173
+ ```python
174
+ from subsurfer.core.controller.controller import SubSurferController
175
+ import asyncio
176
+
177
+ async def main():
178
+ controller = SubSurferController("vulnweb.com")
179
+
180
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘ 및 μ›Ή μ„œλΉ„μŠ€ μŠ€μΊ”
181
+ subdomains = await controller.collect_subdomains()
182
+ web_services = await controller.scan_web_services(subdomains)
183
+
184
+ # κ²°κ³Ό μ €μž₯
185
+ results_dict = {
186
+ 'subdomains': subdomains,
187
+ 'web_services': web_services.get('web_services', {}),
188
+ 'web_servers': web_services.get('web_servers', set()),
189
+ 'enabled_services': web_services.get('enabled_services', set()),
190
+ 'all_urls': web_services.get('all_urls', {}) # URLκ³Ό 포트 정보 포함
191
+ }
192
+
193
+ # κΈ°λ³Έ κ²°κ³Ό 파일 경둜 생성 (results 디렉토리에 μ €μž₯)
194
+ output_path = controller.get_output_path()
195
+ controller.save_results(results_dict, output_path)
196
+
197
+ if __name__ == "__main__":
198
+ asyncio.run(main())
199
+ ```
200
+
201
+ <br>
202
+
203
+ ## πŸ§ͺ ν…ŒμŠ€νŠΈ
204
+ ### νŒ¨μ‹œλΈŒ ν•Έλ“€λŸ¬ ν…ŒμŠ€νŠΈ
205
+ `pytest tests/handlers/test_passive_handler.py -v`
206
+
207
+ <br>
208
+
209
+ ### μ•‘ν‹°λΈŒ ν•Έλ“€λŸ¬ ν…ŒμŠ€νŠΈ
210
+ `pytest tests/handlers/test_active_handler.py -v`
211
+
212
+ <br>
213
+
214
+ ## πŸ—ΊοΈ ToDo
215
+ ### 0.2 버전
216
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
217
+
218
+ ### 0.3 버전
219
+ - JSON κ²°κ³Ό 좜λ ₯ μ˜΅μ…˜ μΆ”κ°€
220
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
221
+ - 기타 κΈ°λŠ₯ μ—…λ°μ΄νŠΈ
222
+
223
+ ### 0.4 버전
224
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
225
+ - μ„œλΈŒλ„λ©”μΈ νƒˆμ·¨ 검사 κΈ°λŠ₯
226
+
227
+ ### 0.5 버전
228
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
229
+ - μƒˆλ‘œμš΄ μ•‘ν‹°λΈŒ λͺ¨λ“ˆ μΆ”κ°€
230
+
231
+ ## πŸ“‹ μš”κ΅¬μ‚¬ν•­
232
+
233
+ - Python 3.13.0 이상 ꢌμž₯
234
+ - aiohttp
235
+ - rich
236
+ - pytest (ν…ŒμŠ€νŠΈμš©)
237
+
238
+ ## πŸ“ λΌμ΄μ„ μŠ€
239
+ MIT License
240
+
241
+ ## 🀝 κΈ°μ—¬
242
+ Bug Report, Feature Suggestions, Pull Request
@@ -0,0 +1,198 @@
1
+ # πŸ„β€β™‚οΈ SubSurfer
2
+
3
+ ![Python Version](https://img.shields.io/badge/python-3.13%2B-blue)
4
+ ![License](https://img.shields.io/badge/license-MIT-green)
5
+ ![Version](https://img.shields.io/badge/version-0.1-orange)
6
+
7
+ SubSurferλŠ” λΉ λ₯΄κ³  효율적인 μ„œλΈŒλ„λ©”μΈ μ—΄κ±° 및 μ›Ή μžμ‚° 식별 λ„κ΅¬μž…λ‹ˆλ‹€.
8
+
9
+ <br>
10
+
11
+ ## 🌟 νŠΉμ§•
12
+ - **λ ˆλ“œνŒ€/λ²„κ·Έλ°”μš΄ν‹° 지원**: λ ˆλ“œνŒ€ μž‘μ „κ³Ό μ›Ή λ²„κ·Έλ°”μš΄ν‹° ν”„λ‘œμ νŠΈ λͺ¨λ‘μ—μ„œ ν™œμš© κ°€λŠ₯
13
+ - **κ³ μ„±λŠ₯ μŠ€μΊ”**: 비동기 및 병렬 처리λ₯Ό ν†΅ν•œ λΉ λ₯Έ μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
14
+ - **포트 μŠ€μΊ”**: μ‚¬μš©μž μ •μ˜ 포트 λ²”μœ„λ‘œ μžμ‚° μŠ€μΊ” λ²”μœ„ ν™•μž₯
15
+ - **μ›Ή μ„œλΉ„μŠ€ 식별**: μ›Ή μ„œλ²„, 기술 μŠ€νƒ λ“± ν™˜κ²½ 정보 μˆ˜μ§‘
16
+ - **νŒŒμ΄ν”„λΌμΈ 지원**: `-pipeweb`, `-pipesub` μ˜΅μ…˜μœΌλ‘œ λ‹€λ₯Έ λ„κ΅¬μ™€μ˜ 연계 κ°€λŠ₯
17
+ - **λͺ¨λ“ˆν˜• 섀계**: Python λͺ¨λ“ˆλ‘œ importν•˜μ—¬ μ‚¬μš© κ°€λŠ₯
18
+ - **지속적 μ—…λ°μ΄νŠΈ**: μƒˆλ‘œμš΄ passive/active λͺ¨λ“ˆ 지속 μΆ”κ°€ μ˜ˆμ •
19
+
20
+ <br>
21
+
22
+ ## πŸš€ μ„€μΉ˜
23
+ <b>bash</b>
24
+ ```bash
25
+ git clone https://github.com/arrester/subsurfer.git
26
+ cd subsurfer
27
+ ```
28
+
29
+ or <br>
30
+
31
+ <b>Python</b>
32
+ ```bash
33
+ pip install -r requirements.txt
34
+ ```
35
+
36
+ <br>
37
+
38
+ ## πŸ“– μ‚¬μš©λ²•
39
+ ### CLI λͺ¨λ“œ
40
+ <b>κΈ°λ³Έ μŠ€μΊ”</b><br>
41
+ `subsurfer -t vulnweb.com`
42
+
43
+ <b>μ•‘ν‹°λΈŒ μŠ€μΊ” ν™œμ„±ν™”</b><br>
44
+ `subsurfer -t vulnweb.com -a`
45
+
46
+ <b>포트 μŠ€μΊ” 포함</b><br>
47
+ `subsurfer -t vulnweb.com -dp` # 기본 포트 <br>
48
+ `subsurfer -t vulnweb.com -p 80,443,8080-8090` # μ‚¬μš©μž μ •μ˜ 포트
49
+
50
+ <b>νŒŒμ΄ν”„λΌμΈ 좜λ ₯</b><br>
51
+ `subsurfer -t vulnweb.com -pipeweb` # μ›Ή μ„œλ²„ 결과만 좜λ ₯ <br>
52
+ `subsurfer -t vulnweb.com -pipesub` # μ„œλΈŒλ„λ©”μΈ 결과만 좜λ ₯
53
+
54
+ ### Python λͺ¨λ“ˆλ‘œ μ‚¬μš©
55
+ <b>Subdomain Scan</b><br>
56
+ ```python
57
+ from subsurfer.core.controller.controller import SubSurferController
58
+ import asyncio
59
+
60
+ async def main():
61
+ controller = SubSurferController(
62
+ target="vulnweb.com",
63
+ verbose=1,
64
+ active=False # Active Scan Option
65
+ )
66
+
67
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
68
+ subdomains = await controller.collect_subdomains()
69
+
70
+ # κ²°κ³Ό 좜λ ₯
71
+ print(f"발견된 μ„œλΈŒλ„λ©”μΈ: {len(subdomains)}개")
72
+ for subdomain in sorted(subdomains):
73
+ print(subdomain)
74
+
75
+ if __name__ == "__main__":
76
+ asyncio.run(main())
77
+ ```
78
+
79
+ <br>
80
+
81
+ <b>Port Scan</b><br>
82
+ ```python
83
+ from subsurfer.core.controller.controller import SubSurferController
84
+ import asyncio
85
+
86
+ async def main():
87
+ controller = SubSurferController(
88
+ target="vulnweb.com",
89
+ verbose=1
90
+ )
91
+
92
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘
93
+ subdomains = await controller.collect_subdomains()
94
+
95
+ # κΈ°λ³Έ 80, 443 μŠ€μΊ” μ„€μ •
96
+ ports = None
97
+
98
+ # 포트 μŠ€μΊ” μ„€μ •
99
+ # ports = controller.parse_ports() # 기본 포트
100
+ # λ˜λŠ” μ‚¬μš©μž μ§€μ • 포트
101
+ # ports = controller.parse_ports("80,443,8080-8090")
102
+
103
+ # μ›Ή μ„œλΉ„μŠ€ μŠ€μΊ”
104
+ web_services = await controller.scan_web_services(subdomains, ports)
105
+
106
+ # μ›Ή μ„œλ²„ 좜λ ₯
107
+ print("\nμ›Ή μ„œλ²„:")
108
+ for server in sorted(web_services['web_servers']):
109
+ print(f"https://{server}")
110
+
111
+ # ν™œμ„±ν™”λœ μ„œλΉ„μŠ€ 좜λ ₯
112
+ print("\nν™œμ„±ν™”λœ μ„œλΉ„μŠ€:")
113
+ for service in sorted(web_services['enabled_services']):
114
+ print(service)
115
+
116
+ # URLκ³Ό 포트 정보 좜λ ₯
117
+ print("\n발견된 URL:")
118
+ for subdomain, urls in web_services['all_urls'].items():
119
+ for url, port in urls:
120
+ print(f"{url}:{port}")
121
+
122
+ if __name__ == "__main__":
123
+ asyncio.run(main())
124
+ ```
125
+
126
+ <br>
127
+
128
+ <b>Result Save</b><br>
129
+ ```python
130
+ from subsurfer.core.controller.controller import SubSurferController
131
+ import asyncio
132
+
133
+ async def main():
134
+ controller = SubSurferController("vulnweb.com")
135
+
136
+ # μ„œλΈŒλ„λ©”μΈ μˆ˜μ§‘ 및 μ›Ή μ„œλΉ„μŠ€ μŠ€μΊ”
137
+ subdomains = await controller.collect_subdomains()
138
+ web_services = await controller.scan_web_services(subdomains)
139
+
140
+ # κ²°κ³Ό μ €μž₯
141
+ results_dict = {
142
+ 'subdomains': subdomains,
143
+ 'web_services': web_services.get('web_services', {}),
144
+ 'web_servers': web_services.get('web_servers', set()),
145
+ 'enabled_services': web_services.get('enabled_services', set()),
146
+ 'all_urls': web_services.get('all_urls', {}) # URLκ³Ό 포트 정보 포함
147
+ }
148
+
149
+ # κΈ°λ³Έ κ²°κ³Ό 파일 경둜 생성 (results 디렉토리에 μ €μž₯)
150
+ output_path = controller.get_output_path()
151
+ controller.save_results(results_dict, output_path)
152
+
153
+ if __name__ == "__main__":
154
+ asyncio.run(main())
155
+ ```
156
+
157
+ <br>
158
+
159
+ ## πŸ§ͺ ν…ŒμŠ€νŠΈ
160
+ ### νŒ¨μ‹œλΈŒ ν•Έλ“€λŸ¬ ν…ŒμŠ€νŠΈ
161
+ `pytest tests/handlers/test_passive_handler.py -v`
162
+
163
+ <br>
164
+
165
+ ### μ•‘ν‹°λΈŒ ν•Έλ“€λŸ¬ ν…ŒμŠ€νŠΈ
166
+ `pytest tests/handlers/test_active_handler.py -v`
167
+
168
+ <br>
169
+
170
+ ## πŸ—ΊοΈ ToDo
171
+ ### 0.2 버전
172
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
173
+
174
+ ### 0.3 버전
175
+ - JSON κ²°κ³Ό 좜λ ₯ μ˜΅μ…˜ μΆ”κ°€
176
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
177
+ - 기타 κΈ°λŠ₯ μ—…λ°μ΄νŠΈ
178
+
179
+ ### 0.4 버전
180
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
181
+ - μ„œλΈŒλ„λ©”μΈ νƒˆμ·¨ 검사 κΈ°λŠ₯
182
+
183
+ ### 0.5 버전
184
+ - μƒˆλ‘œμš΄ νŒ¨μ‹œλΈŒ λͺ¨λ“ˆ μΆ”κ°€
185
+ - μƒˆλ‘œμš΄ μ•‘ν‹°λΈŒ λͺ¨λ“ˆ μΆ”κ°€
186
+
187
+ ## πŸ“‹ μš”κ΅¬μ‚¬ν•­
188
+
189
+ - Python 3.13.0 이상 ꢌμž₯
190
+ - aiohttp
191
+ - rich
192
+ - pytest (ν…ŒμŠ€νŠΈμš©)
193
+
194
+ ## πŸ“ λΌμ΄μ„ μŠ€
195
+ MIT License
196
+
197
+ ## 🀝 κΈ°μ—¬
198
+ Bug Report, Feature Suggestions, Pull Request
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,51 @@
1
+ from setuptools import setup, find_namespace_packages
2
+
3
+ setup(
4
+ name="subsurfer",
5
+ version="0.1.8",
6
+ description="Red Teaming and Web Bug Bounty Fast Asset Identification Tool",
7
+ long_description=open('README.md').read(),
8
+ long_description_content_type="text/markdown",
9
+ author="arrester",
10
+ author_email="arresterloyal@gmail.com",
11
+ url="https://github.com/arrester/subsurfer",
12
+ packages=find_namespace_packages(include=['subsurfer*']),
13
+ package_data={
14
+ 'subsurfer': ['core/config/*.yaml'],
15
+ },
16
+ include_package_data=True,
17
+ install_requires=[
18
+ 'rich>=13.7.0',
19
+ 'aiohttp>=3.9.1',
20
+ 'beautifulsoup4>=4.12.2',
21
+ 'dnspython>=2.4.2',
22
+ 'pyyaml>=6.0.1',
23
+ 'asyncio>=3.4.3',
24
+ 'pytest>=7.4.3',
25
+ 'pytest-asyncio>=0.23.2',
26
+ 'python-Wappalyzer>=0.3.1'
27
+ ],
28
+ entry_points={
29
+ 'console_scripts': [
30
+ 'subsurfer=subsurfer.__main__:run_main',
31
+ ],
32
+ },
33
+ python_requires='>=3.9',
34
+ classifiers=[
35
+ 'Development Status :: 3 - Alpha',
36
+ 'Intended Audience :: Information Technology',
37
+ 'Intended Audience :: System Administrators',
38
+ 'Topic :: Security',
39
+ 'Topic :: Internet :: WWW/HTTP',
40
+ 'License :: OSI Approved :: MIT License',
41
+ 'Programming Language :: Python :: 3',
42
+ 'Programming Language :: Python :: 3.13',
43
+ 'Operating System :: OS Independent',
44
+ ],
45
+ keywords='security, subdomain enumeration, bug bounty, red team, web security',
46
+ project_urls={
47
+ 'Bug Reports': 'https://github.com/arrester/subsurfer/issues',
48
+ 'Source': 'https://github.com/arrester/subsurfer',
49
+ 'Documentation': 'https://github.com/arrester/subsurfer#readme',
50
+ },
51
+ )
@@ -0,0 +1,5 @@
1
+ """
2
+ SubSurfer - Red Teaming and Web Bug Bounty Fast Asset Identification Tool
3
+ """
4
+
5
+ __version__ = "0.1.8"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ SubSurfer main entry point
6
+ """
7
+
8
+ from subsurfer.subsurfer import main
9
+ import asyncio
10
+
11
+ def run_main():
12
+ """Wrapper function to run the async main"""
13
+ asyncio.run(main())
14
+
15
+ if __name__ == "__main__":
16
+ run_main()
@@ -0,0 +1 @@
1
+ # Empty file to make the directory a Python package
@@ -0,0 +1 @@
1
+ # Empty file to make the directory a Python package
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ CLI utilities module
6
+ """
7
+
8
+ import sys
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.table import Table
12
+ from rich.text import Text
13
+ from rich.box import ROUNDED
14
+
15
+ console = Console()
16
+
17
+ def is_cli_mode():
18
+ """Check if running in CLI mode"""
19
+ return sys.stdin.isatty()
20
+
21
+ def print_banner(force=False):
22
+ """Print banner only in CLI mode unless forced"""
23
+ if not is_cli_mode() and not force:
24
+ return
25
+
26
+ banner = r"""
27
+ πŸ„β€β™‚οΈ SubSurfer 🌊
28
+ ----------------------
29
+ _____ _ _____ __
30
+ / ___| | | / ___| / _|
31
+ \ `--. _ _ | |__ \ `--. _ _ _ __ | |_ ___ _ __
32
+ `--. \| | | || '_ \ `--. \| | | || '__|| _| / _ \| '__|
33
+ /\__/ /| |_| || |_) |/\__/ /| |_| || | | | | __/| |
34
+ \____/ \__,_||_.__/ \____/ \__,_||_| |_| \___||_| v0.1
35
+ """
36
+
37
+ # λ°°λ„ˆ νŒ¨λ„ 생성
38
+ banner_panel = Panel(
39
+ banner,
40
+ title="[bold cyan]Red Teaming and Web Bug Bounty Fast Asset Identification Tool[/]",
41
+ subtitle="[bold blue]by. arrester (https://github.com/arrester/subsurfer)[/]",
42
+ style="bold blue",
43
+ box=ROUNDED
44
+ )
45
+ console.print(banner_panel)
46
+
47
+ def print_usage():
48
+ """Print usage information"""
49
+ usage_table = Table(
50
+ title="[bold cyan]SubSurfer Usage Guide[/]",
51
+ box=ROUNDED,
52
+ show_header=True,
53
+ header_style="bold magenta"
54
+ )
55
+
56
+ # ν…Œμ΄λΈ” 컬럼 μ„€μ •
57
+ usage_table.add_column("Command", style="cyan", justify="left")
58
+ usage_table.add_column("Description", style="white", justify="left")
59
+ usage_table.add_column("Example", style="green", justify="left")
60
+
61
+ # μ‚¬μš©λ²• μΆ”κ°€
62
+ usage_table.add_row(
63
+ "subsurfer -t <domain>",
64
+ "Scan single domain",
65
+ "subsurfer -t vulnweb.com"
66
+ )
67
+ usage_table.add_row(
68
+ "subsurfer -t <domain> -o <file>",
69
+ "Save results to file",
70
+ "subsurfer -t vulnweb.com -o results.txt"
71
+ )
72
+ usage_table.add_row(
73
+ "subsurfer -t <domain> -a",
74
+ "Enable active scanning",
75
+ "subsurfer -t vulnweb.com -a"
76
+ )
77
+ usage_table.add_row(
78
+ "subsurfer -t <domain> -v",
79
+ "Increase output verbosity",
80
+ "subsurfer -t vulnweb.com -v"
81
+ )
82
+
83
+ # μ˜΅μ…˜ ν…Œμ΄λΈ” 생성
84
+ options_table = Table(
85
+ title="[bold cyan]Available Options[/]",
86
+ box=ROUNDED,
87
+ show_header=True,
88
+ header_style="bold magenta"
89
+ )
90
+
91
+ # μ˜΅μ…˜ ν…Œμ΄λΈ” 컬럼 μ„€μ •
92
+ options_table.add_column("Option", style="cyan", justify="left")
93
+ options_table.add_column("Description", style="white", justify="left")
94
+
95
+ # μ˜΅μ…˜ μΆ”κ°€ (ν˜„μž¬ κ΅¬ν˜„λœ μ˜΅μ…˜λ“€λ§Œ)
96
+ options_table.add_row("-h, --help", "Show this help message")
97
+ options_table.add_row("-t, --target", "Target domain (e.g. vulnweb.com)")
98
+ options_table.add_row("-o, --output", "Output file to save results")
99
+ options_table.add_row("-v, --verbose", "Increase output verbosity (-v, -vv, -vvv)")
100
+ options_table.add_row("-a, --active", "Enable active scanning (default: passive only)")
101
+ options_table.add_row("-dp, --default-ports", "Scan default ports")
102
+ options_table.add_row("-p, --port", "Custom port range (e.g. 1-65535)")
103
+ options_table.add_row("-pipeweb", "Output web server results for pipeline")
104
+ options_table.add_row("-pipesub", "Output subdomain results for pipeline")
105
+ options_table.add_row("-to, --takeover", "[Coming Soon] Subdomain takeover detection")
106
+
107
+ # 좜λ ₯
108
+ console.print("\n[bold cyan]Description:[/]")
109
+ console.print("SubSurfer is a fast subdomain enumeration tool that combines both passive and active scanning techniques to discover subdomains of a target domain.\n")
110
+
111
+ console.print(usage_table)
112
+ console.print("\n")
113
+ console.print(options_table)
114
+ console.print("\n[bold cyan]Note:[/] Some scanners may require API keys. Configure them in config.yaml")
115
+ console.print("[bold yellow]Coming Soon:[/] Subdomain takeover detection will be available in the next version!\n")
116
+
117
+ def print_status(message, status="info", cli_only=True):
118
+ """Print status messages with color coding"""
119
+ if cli_only and not is_cli_mode():
120
+ return
121
+
122
+ colors = {
123
+ "info": "blue",
124
+ "success": "green",
125
+ "warning": "yellow",
126
+ "error": "red"
127
+ }
128
+
129
+ # μƒνƒœ μ•„μ΄μ½˜ μΆ”κ°€
130
+ icons = {
131
+ "info": "ℹ️",
132
+ "success": "βœ…",
133
+ "warning": "⚠️",
134
+ "error": "❌"
135
+ }
136
+
137
+ console.print(f"[bold {colors[status]}]{icons[status]} {message}[/]")
138
+
139
+ def main():
140
+ """Main entry point for CLI"""
141
+ if len(sys.argv) == 1:
142
+ print_banner(force=True)
143
+ print_usage()
144
+ sys.exit(0)
145
+
146
+ if __name__ == "__main__":
147
+ main()