aiptx 2.0.7__py3-none-any.whl

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 (187) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +46 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/exploit_agent.py +688 -0
  8. aipt_v2/agents/ptt.py +406 -0
  9. aipt_v2/agents/state.py +168 -0
  10. aipt_v2/app.py +957 -0
  11. aipt_v2/browser/__init__.py +31 -0
  12. aipt_v2/browser/automation.py +458 -0
  13. aipt_v2/browser/crawler.py +453 -0
  14. aipt_v2/cli.py +2933 -0
  15. aipt_v2/compliance/__init__.py +71 -0
  16. aipt_v2/compliance/compliance_report.py +449 -0
  17. aipt_v2/compliance/framework_mapper.py +424 -0
  18. aipt_v2/compliance/nist_mapping.py +345 -0
  19. aipt_v2/compliance/owasp_mapping.py +330 -0
  20. aipt_v2/compliance/pci_mapping.py +297 -0
  21. aipt_v2/config.py +341 -0
  22. aipt_v2/core/__init__.py +43 -0
  23. aipt_v2/core/agent.py +630 -0
  24. aipt_v2/core/llm.py +395 -0
  25. aipt_v2/core/memory.py +305 -0
  26. aipt_v2/core/ptt.py +329 -0
  27. aipt_v2/database/__init__.py +14 -0
  28. aipt_v2/database/models.py +232 -0
  29. aipt_v2/database/repository.py +384 -0
  30. aipt_v2/docker/__init__.py +23 -0
  31. aipt_v2/docker/builder.py +260 -0
  32. aipt_v2/docker/manager.py +222 -0
  33. aipt_v2/docker/sandbox.py +371 -0
  34. aipt_v2/evasion/__init__.py +58 -0
  35. aipt_v2/evasion/request_obfuscator.py +272 -0
  36. aipt_v2/evasion/tls_fingerprint.py +285 -0
  37. aipt_v2/evasion/ua_rotator.py +301 -0
  38. aipt_v2/evasion/waf_bypass.py +439 -0
  39. aipt_v2/execution/__init__.py +23 -0
  40. aipt_v2/execution/executor.py +302 -0
  41. aipt_v2/execution/parser.py +544 -0
  42. aipt_v2/execution/terminal.py +337 -0
  43. aipt_v2/health.py +437 -0
  44. aipt_v2/intelligence/__init__.py +194 -0
  45. aipt_v2/intelligence/adaptation.py +474 -0
  46. aipt_v2/intelligence/auth.py +520 -0
  47. aipt_v2/intelligence/chaining.py +775 -0
  48. aipt_v2/intelligence/correlation.py +536 -0
  49. aipt_v2/intelligence/cve_aipt.py +334 -0
  50. aipt_v2/intelligence/cve_info.py +1111 -0
  51. aipt_v2/intelligence/knowledge_graph.py +590 -0
  52. aipt_v2/intelligence/learning.py +626 -0
  53. aipt_v2/intelligence/llm_analyzer.py +502 -0
  54. aipt_v2/intelligence/llm_tool_selector.py +518 -0
  55. aipt_v2/intelligence/payload_generator.py +562 -0
  56. aipt_v2/intelligence/rag.py +239 -0
  57. aipt_v2/intelligence/scope.py +442 -0
  58. aipt_v2/intelligence/searchers/__init__.py +5 -0
  59. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  60. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  61. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  62. aipt_v2/intelligence/tools.json +443 -0
  63. aipt_v2/intelligence/triage.py +670 -0
  64. aipt_v2/interactive_shell.py +559 -0
  65. aipt_v2/interface/__init__.py +5 -0
  66. aipt_v2/interface/cli.py +230 -0
  67. aipt_v2/interface/main.py +501 -0
  68. aipt_v2/interface/tui.py +1276 -0
  69. aipt_v2/interface/utils.py +583 -0
  70. aipt_v2/llm/__init__.py +39 -0
  71. aipt_v2/llm/config.py +26 -0
  72. aipt_v2/llm/llm.py +514 -0
  73. aipt_v2/llm/memory.py +214 -0
  74. aipt_v2/llm/request_queue.py +89 -0
  75. aipt_v2/llm/utils.py +89 -0
  76. aipt_v2/local_tool_installer.py +1467 -0
  77. aipt_v2/models/__init__.py +15 -0
  78. aipt_v2/models/findings.py +295 -0
  79. aipt_v2/models/phase_result.py +224 -0
  80. aipt_v2/models/scan_config.py +207 -0
  81. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  82. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  83. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  84. aipt_v2/monitoring/prometheus.yml +60 -0
  85. aipt_v2/orchestration/__init__.py +52 -0
  86. aipt_v2/orchestration/pipeline.py +398 -0
  87. aipt_v2/orchestration/progress.py +300 -0
  88. aipt_v2/orchestration/scheduler.py +296 -0
  89. aipt_v2/orchestrator.py +2427 -0
  90. aipt_v2/payloads/__init__.py +27 -0
  91. aipt_v2/payloads/cmdi.py +150 -0
  92. aipt_v2/payloads/sqli.py +263 -0
  93. aipt_v2/payloads/ssrf.py +204 -0
  94. aipt_v2/payloads/templates.py +222 -0
  95. aipt_v2/payloads/traversal.py +166 -0
  96. aipt_v2/payloads/xss.py +204 -0
  97. aipt_v2/prompts/__init__.py +60 -0
  98. aipt_v2/proxy/__init__.py +29 -0
  99. aipt_v2/proxy/history.py +352 -0
  100. aipt_v2/proxy/interceptor.py +452 -0
  101. aipt_v2/recon/__init__.py +44 -0
  102. aipt_v2/recon/dns.py +241 -0
  103. aipt_v2/recon/osint.py +367 -0
  104. aipt_v2/recon/subdomain.py +372 -0
  105. aipt_v2/recon/tech_detect.py +311 -0
  106. aipt_v2/reports/__init__.py +17 -0
  107. aipt_v2/reports/generator.py +313 -0
  108. aipt_v2/reports/html_report.py +378 -0
  109. aipt_v2/runtime/__init__.py +53 -0
  110. aipt_v2/runtime/base.py +30 -0
  111. aipt_v2/runtime/docker.py +401 -0
  112. aipt_v2/runtime/local.py +346 -0
  113. aipt_v2/runtime/tool_server.py +205 -0
  114. aipt_v2/runtime/vps.py +830 -0
  115. aipt_v2/scanners/__init__.py +28 -0
  116. aipt_v2/scanners/base.py +273 -0
  117. aipt_v2/scanners/nikto.py +244 -0
  118. aipt_v2/scanners/nmap.py +402 -0
  119. aipt_v2/scanners/nuclei.py +273 -0
  120. aipt_v2/scanners/web.py +454 -0
  121. aipt_v2/scripts/security_audit.py +366 -0
  122. aipt_v2/setup_wizard.py +941 -0
  123. aipt_v2/skills/__init__.py +80 -0
  124. aipt_v2/skills/agents/__init__.py +14 -0
  125. aipt_v2/skills/agents/api_tester.py +706 -0
  126. aipt_v2/skills/agents/base.py +477 -0
  127. aipt_v2/skills/agents/code_review.py +459 -0
  128. aipt_v2/skills/agents/security_agent.py +336 -0
  129. aipt_v2/skills/agents/web_pentest.py +818 -0
  130. aipt_v2/skills/prompts/__init__.py +647 -0
  131. aipt_v2/system_detector.py +539 -0
  132. aipt_v2/telemetry/__init__.py +7 -0
  133. aipt_v2/telemetry/tracer.py +347 -0
  134. aipt_v2/terminal/__init__.py +28 -0
  135. aipt_v2/terminal/executor.py +400 -0
  136. aipt_v2/terminal/sandbox.py +350 -0
  137. aipt_v2/tools/__init__.py +44 -0
  138. aipt_v2/tools/active_directory/__init__.py +78 -0
  139. aipt_v2/tools/active_directory/ad_config.py +238 -0
  140. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  141. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  142. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  143. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  144. aipt_v2/tools/agents_graph/__init__.py +19 -0
  145. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  146. aipt_v2/tools/api_security/__init__.py +76 -0
  147. aipt_v2/tools/api_security/api_discovery.py +608 -0
  148. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  149. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  150. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  151. aipt_v2/tools/browser/__init__.py +5 -0
  152. aipt_v2/tools/browser/browser_actions.py +238 -0
  153. aipt_v2/tools/browser/browser_instance.py +535 -0
  154. aipt_v2/tools/browser/tab_manager.py +344 -0
  155. aipt_v2/tools/cloud/__init__.py +70 -0
  156. aipt_v2/tools/cloud/cloud_config.py +273 -0
  157. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  158. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  159. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  160. aipt_v2/tools/executor.py +307 -0
  161. aipt_v2/tools/parser.py +408 -0
  162. aipt_v2/tools/proxy/__init__.py +5 -0
  163. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  164. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  165. aipt_v2/tools/registry.py +196 -0
  166. aipt_v2/tools/scanners/__init__.py +343 -0
  167. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  168. aipt_v2/tools/scanners/burp_tool.py +631 -0
  169. aipt_v2/tools/scanners/config.py +156 -0
  170. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  171. aipt_v2/tools/scanners/zap_tool.py +612 -0
  172. aipt_v2/tools/terminal/__init__.py +5 -0
  173. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  174. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  175. aipt_v2/tools/terminal/terminal_session.py +449 -0
  176. aipt_v2/tools/tool_processing.py +108 -0
  177. aipt_v2/utils/__init__.py +17 -0
  178. aipt_v2/utils/logging.py +202 -0
  179. aipt_v2/utils/model_manager.py +187 -0
  180. aipt_v2/utils/searchers/__init__.py +269 -0
  181. aipt_v2/verify_install.py +793 -0
  182. aiptx-2.0.7.dist-info/METADATA +345 -0
  183. aiptx-2.0.7.dist-info/RECORD +187 -0
  184. aiptx-2.0.7.dist-info/WHEEL +5 -0
  185. aiptx-2.0.7.dist-info/entry_points.txt +7 -0
  186. aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
  187. aiptx-2.0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,272 @@
1
+ """
2
+ Request Obfuscator
3
+
4
+ Mutates HTTP requests to evade detection:
5
+ - Header manipulation
6
+ - Parameter encoding
7
+ - Request body obfuscation
8
+ - HTTP method alternatives
9
+
10
+ Usage:
11
+ from aipt_v2.evasion import RequestObfuscator
12
+
13
+ obfuscator = RequestObfuscator()
14
+ modified = obfuscator.obfuscate(request)
15
+ """
16
+
17
+ import random
18
+ import string
19
+ import urllib.parse
20
+ from dataclasses import dataclass, field
21
+ from typing import Dict, List, Optional, Any
22
+
23
+
24
+ @dataclass
25
+ class ObfuscationConfig:
26
+ """Configuration for request obfuscation."""
27
+ encode_parameters: bool = True
28
+ randomize_case: bool = True
29
+ add_junk_headers: bool = True
30
+ add_junk_parameters: bool = False
31
+ pad_content_length: bool = False
32
+ use_http_methods_override: bool = False
33
+
34
+
35
+ @dataclass
36
+ class ObfuscatedRequest:
37
+ """Obfuscated HTTP request."""
38
+ method: str
39
+ url: str
40
+ headers: Dict[str, str]
41
+ body: Optional[str]
42
+ params: Dict[str, str]
43
+ modifications: List[str]
44
+
45
+
46
+ class RequestObfuscator:
47
+ """
48
+ HTTP Request Obfuscator.
49
+
50
+ Applies various obfuscation techniques to HTTP requests
51
+ to evade detection and bypass security controls.
52
+ """
53
+
54
+ # Junk headers that are typically ignored
55
+ JUNK_HEADERS = [
56
+ "X-Forwarded-For", "X-Real-IP", "X-Originating-IP",
57
+ "X-Client-IP", "CF-Connecting-IP", "True-Client-IP",
58
+ "X-Custom-Header", "X-Debug", "X-Request-ID",
59
+ "X-Correlation-ID", "X-Trace-ID"
60
+ ]
61
+
62
+ # Content-Type variations
63
+ CONTENT_TYPES = [
64
+ "application/json",
65
+ "application/x-www-form-urlencoded",
66
+ "text/plain",
67
+ "application/xml",
68
+ "multipart/form-data"
69
+ ]
70
+
71
+ def __init__(self, config: Optional[ObfuscationConfig] = None):
72
+ """Initialize obfuscator."""
73
+ self.config = config or ObfuscationConfig()
74
+
75
+ def _random_string(self, length: int = 8) -> str:
76
+ """Generate random string."""
77
+ return "".join(random.choices(string.ascii_letters + string.digits, k=length))
78
+
79
+ def _random_ip(self) -> str:
80
+ """Generate random IP address."""
81
+ return ".".join(str(random.randint(1, 254)) for _ in range(4))
82
+
83
+ def encode_parameter(self, value: str, encoding: str = "url") -> str:
84
+ """
85
+ Encode parameter value.
86
+
87
+ Args:
88
+ value: Original value
89
+ encoding: Encoding type (url, double_url, unicode)
90
+
91
+ Returns:
92
+ Encoded value
93
+ """
94
+ if encoding == "url":
95
+ return urllib.parse.quote(value, safe="")
96
+ elif encoding == "double_url":
97
+ return urllib.parse.quote(urllib.parse.quote(value, safe=""), safe="")
98
+ elif encoding == "unicode":
99
+ return "".join(f"%u00{ord(c):02x}" if c.isalpha() else c for c in value)
100
+ return value
101
+
102
+ def randomize_header_case(self, headers: Dict[str, str]) -> Dict[str, str]:
103
+ """Randomize header name case."""
104
+ new_headers = {}
105
+ for name, value in headers.items():
106
+ # Random case for header name
107
+ new_name = "".join(
108
+ c.upper() if random.random() > 0.5 else c.lower()
109
+ for c in name
110
+ )
111
+ new_headers[new_name] = value
112
+ return new_headers
113
+
114
+ def add_junk_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
115
+ """Add junk/decoy headers."""
116
+ new_headers = headers.copy()
117
+
118
+ # Add random IP headers
119
+ ip_headers = ["X-Forwarded-For", "X-Real-IP", "X-Client-IP"]
120
+ for header in random.sample(ip_headers, random.randint(1, 2)):
121
+ new_headers[header] = self._random_ip()
122
+
123
+ # Add random custom headers
124
+ for _ in range(random.randint(1, 3)):
125
+ header_name = f"X-{self._random_string(6)}"
126
+ new_headers[header_name] = self._random_string(12)
127
+
128
+ return new_headers
129
+
130
+ def add_junk_parameters(self, params: Dict[str, str]) -> Dict[str, str]:
131
+ """Add junk parameters to request."""
132
+ new_params = params.copy()
133
+
134
+ for _ in range(random.randint(1, 3)):
135
+ param_name = self._random_string(6)
136
+ new_params[param_name] = self._random_string(8)
137
+
138
+ return new_params
139
+
140
+ def obfuscate_url(self, url: str) -> str:
141
+ """Obfuscate URL path."""
142
+ # Add path segments that resolve to same path
143
+ path_tricks = [
144
+ "/./", # Current directory
145
+ "/../..", # Parent then back
146
+ "//", # Double slash
147
+ ]
148
+
149
+ # Random insertion point
150
+ if "/" in url:
151
+ parts = url.split("/")
152
+ if len(parts) > 2:
153
+ insert_idx = random.randint(1, len(parts) - 1)
154
+ trick = random.choice(path_tricks)
155
+ parts.insert(insert_idx, trick.strip("/"))
156
+ url = "/".join(parts)
157
+
158
+ return url
159
+
160
+ def use_method_override(
161
+ self,
162
+ method: str,
163
+ headers: Dict[str, str]
164
+ ) -> tuple:
165
+ """
166
+ Use HTTP method override headers.
167
+
168
+ Some applications accept X-HTTP-Method-Override
169
+ to change the actual method.
170
+ """
171
+ override_headers = [
172
+ "X-HTTP-Method-Override",
173
+ "X-HTTP-Method",
174
+ "X-Method-Override",
175
+ "_method"
176
+ ]
177
+
178
+ new_headers = headers.copy()
179
+
180
+ # Use POST with override header
181
+ header_name = random.choice(override_headers)
182
+ new_headers[header_name] = method
183
+
184
+ return "POST", new_headers
185
+
186
+ def obfuscate(
187
+ self,
188
+ method: str,
189
+ url: str,
190
+ headers: Dict[str, str] = None,
191
+ params: Dict[str, str] = None,
192
+ body: str = None
193
+ ) -> ObfuscatedRequest:
194
+ """
195
+ Obfuscate HTTP request.
196
+
197
+ Args:
198
+ method: HTTP method
199
+ url: Request URL
200
+ headers: Request headers
201
+ params: Query parameters
202
+ body: Request body
203
+
204
+ Returns:
205
+ ObfuscatedRequest
206
+ """
207
+ headers = headers or {}
208
+ params = params or {}
209
+ modifications = []
210
+
211
+ # Encode parameters
212
+ if self.config.encode_parameters and params:
213
+ encoded_params = {}
214
+ for key, value in params.items():
215
+ encoding = random.choice(["url", "double_url", "unicode"])
216
+ encoded_params[key] = self.encode_parameter(value, encoding)
217
+ params = encoded_params
218
+ modifications.append("parameter_encoding")
219
+
220
+ # Randomize header case
221
+ if self.config.randomize_case:
222
+ headers = self.randomize_header_case(headers)
223
+ modifications.append("header_case_randomization")
224
+
225
+ # Add junk headers
226
+ if self.config.add_junk_headers:
227
+ headers = self.add_junk_headers(headers)
228
+ modifications.append("junk_headers_added")
229
+
230
+ # Add junk parameters
231
+ if self.config.add_junk_parameters:
232
+ params = self.add_junk_parameters(params)
233
+ modifications.append("junk_parameters_added")
234
+
235
+ # Method override
236
+ if self.config.use_http_methods_override and method in ["PUT", "DELETE", "PATCH"]:
237
+ method, headers = self.use_method_override(method, headers)
238
+ modifications.append("method_override")
239
+
240
+ return ObfuscatedRequest(
241
+ method=method,
242
+ url=url,
243
+ headers=headers,
244
+ body=body,
245
+ params=params,
246
+ modifications=modifications
247
+ )
248
+
249
+
250
+ # Convenience function
251
+ def obfuscate_request(
252
+ method: str,
253
+ url: str,
254
+ headers: Dict[str, str] = None,
255
+ params: Dict[str, str] = None,
256
+ body: str = None
257
+ ) -> ObfuscatedRequest:
258
+ """
259
+ Obfuscate HTTP request.
260
+
261
+ Args:
262
+ method: HTTP method
263
+ url: Request URL
264
+ headers: Request headers
265
+ params: Query parameters
266
+ body: Request body
267
+
268
+ Returns:
269
+ ObfuscatedRequest
270
+ """
271
+ obfuscator = RequestObfuscator()
272
+ return obfuscator.obfuscate(method, url, headers, params, body)
@@ -0,0 +1,285 @@
1
+ """
2
+ TLS Fingerprint Randomization
3
+
4
+ Randomizes TLS fingerprint (JA3/JA3S) to evade detection:
5
+ - Cipher suite ordering
6
+ - TLS extension manipulation
7
+ - ALPN protocol ordering
8
+ - Supported versions randomization
9
+
10
+ Usage:
11
+ from aipt_v2.evasion import TLSFingerprint
12
+
13
+ tls = TLSFingerprint()
14
+ context = tls.get_randomized_context()
15
+ """
16
+
17
+ import ssl
18
+ import random
19
+ from dataclasses import dataclass
20
+ from typing import List, Optional, Dict, Any
21
+
22
+
23
+ @dataclass
24
+ class TLSProfile:
25
+ """TLS connection profile."""
26
+ name: str
27
+ ciphers: List[str]
28
+ protocols: List[str]
29
+ extensions: List[str]
30
+ alpn: List[str]
31
+ ja3_hash: str = ""
32
+
33
+
34
+ class TLSFingerprint:
35
+ """
36
+ TLS Fingerprint Randomization.
37
+
38
+ Modifies TLS connection parameters to evade
39
+ JA3/JA3S fingerprint detection.
40
+ """
41
+
42
+ # Common cipher suites
43
+ CIPHER_SUITES = [
44
+ "TLS_AES_128_GCM_SHA256",
45
+ "TLS_AES_256_GCM_SHA384",
46
+ "TLS_CHACHA20_POLY1305_SHA256",
47
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
48
+ "ECDHE-RSA-AES128-GCM-SHA256",
49
+ "ECDHE-ECDSA-AES256-GCM-SHA384",
50
+ "ECDHE-RSA-AES256-GCM-SHA384",
51
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
52
+ "ECDHE-RSA-CHACHA20-POLY1305",
53
+ "ECDHE-RSA-AES128-SHA",
54
+ "ECDHE-RSA-AES256-SHA",
55
+ "AES128-GCM-SHA256",
56
+ "AES256-GCM-SHA384",
57
+ "AES128-SHA",
58
+ "AES256-SHA",
59
+ ]
60
+
61
+ # Browser-like cipher ordering
62
+ BROWSER_PROFILES = {
63
+ "chrome": [
64
+ "TLS_AES_128_GCM_SHA256",
65
+ "TLS_AES_256_GCM_SHA384",
66
+ "TLS_CHACHA20_POLY1305_SHA256",
67
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
68
+ "ECDHE-RSA-AES128-GCM-SHA256",
69
+ "ECDHE-ECDSA-AES256-GCM-SHA384",
70
+ "ECDHE-RSA-AES256-GCM-SHA384",
71
+ ],
72
+ "firefox": [
73
+ "TLS_AES_128_GCM_SHA256",
74
+ "TLS_CHACHA20_POLY1305_SHA256",
75
+ "TLS_AES_256_GCM_SHA384",
76
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
77
+ "ECDHE-RSA-AES128-GCM-SHA256",
78
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
79
+ "ECDHE-RSA-CHACHA20-POLY1305",
80
+ ],
81
+ "safari": [
82
+ "TLS_AES_128_GCM_SHA256",
83
+ "TLS_AES_256_GCM_SHA384",
84
+ "TLS_CHACHA20_POLY1305_SHA256",
85
+ "ECDHE-ECDSA-AES256-GCM-SHA384",
86
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
87
+ "ECDHE-RSA-AES256-GCM-SHA384",
88
+ "ECDHE-RSA-AES128-GCM-SHA256",
89
+ ],
90
+ }
91
+
92
+ # ALPN protocols
93
+ ALPN_PROTOCOLS = ["h2", "http/1.1"]
94
+
95
+ def __init__(self):
96
+ """Initialize TLS fingerprint handler."""
97
+ self.profiles = self._create_profiles()
98
+
99
+ def _create_profiles(self) -> Dict[str, TLSProfile]:
100
+ """Create TLS profiles for different browsers."""
101
+ return {
102
+ "chrome": TLSProfile(
103
+ name="Chrome",
104
+ ciphers=self.BROWSER_PROFILES["chrome"],
105
+ protocols=["TLSv1.2", "TLSv1.3"],
106
+ extensions=["server_name", "ec_point_formats", "supported_groups"],
107
+ alpn=["h2", "http/1.1"]
108
+ ),
109
+ "firefox": TLSProfile(
110
+ name="Firefox",
111
+ ciphers=self.BROWSER_PROFILES["firefox"],
112
+ protocols=["TLSv1.2", "TLSv1.3"],
113
+ extensions=["server_name", "supported_groups", "ec_point_formats"],
114
+ alpn=["h2", "http/1.1"]
115
+ ),
116
+ "safari": TLSProfile(
117
+ name="Safari",
118
+ ciphers=self.BROWSER_PROFILES["safari"],
119
+ protocols=["TLSv1.2", "TLSv1.3"],
120
+ extensions=["server_name", "ec_point_formats", "supported_groups"],
121
+ alpn=["h2", "http/1.1"]
122
+ ),
123
+ "random": TLSProfile(
124
+ name="Random",
125
+ ciphers=self.CIPHER_SUITES.copy(),
126
+ protocols=["TLSv1.2", "TLSv1.3"],
127
+ extensions=["server_name"],
128
+ alpn=["h2", "http/1.1"]
129
+ ),
130
+ }
131
+
132
+ def get_profile(self, name: str = "random") -> TLSProfile:
133
+ """
134
+ Get TLS profile.
135
+
136
+ Args:
137
+ name: Profile name (chrome, firefox, safari, random)
138
+
139
+ Returns:
140
+ TLSProfile
141
+ """
142
+ return self.profiles.get(name, self.profiles["random"])
143
+
144
+ def randomize_ciphers(self, base_ciphers: List[str] = None) -> List[str]:
145
+ """
146
+ Randomize cipher suite order.
147
+
148
+ Args:
149
+ base_ciphers: Base cipher list
150
+
151
+ Returns:
152
+ Randomized cipher list
153
+ """
154
+ ciphers = base_ciphers or self.CIPHER_SUITES.copy()
155
+
156
+ # Keep TLS 1.3 ciphers at top but shuffle others
157
+ tls13_ciphers = [c for c in ciphers if c.startswith("TLS_")]
158
+ other_ciphers = [c for c in ciphers if not c.startswith("TLS_")]
159
+
160
+ random.shuffle(other_ciphers)
161
+
162
+ return tls13_ciphers + other_ciphers
163
+
164
+ def randomize_alpn(self) -> List[str]:
165
+ """
166
+ Randomize ALPN protocol order.
167
+
168
+ Returns:
169
+ Randomized ALPN list
170
+ """
171
+ alpn = self.ALPN_PROTOCOLS.copy()
172
+ if random.random() > 0.5:
173
+ alpn.reverse()
174
+ return alpn
175
+
176
+ def create_ssl_context(
177
+ self,
178
+ profile: str = "random",
179
+ verify: bool = True
180
+ ) -> ssl.SSLContext:
181
+ """
182
+ Create SSL context with randomized fingerprint.
183
+
184
+ Args:
185
+ profile: TLS profile to use
186
+ verify: Verify certificates
187
+
188
+ Returns:
189
+ Configured SSLContext
190
+ """
191
+ context = ssl.create_default_context()
192
+
193
+ if not verify:
194
+ context.check_hostname = False
195
+ context.verify_mode = ssl.CERT_NONE
196
+
197
+ # Get profile
198
+ tls_profile = self.get_profile(profile)
199
+
200
+ # Set ciphers
201
+ if profile == "random":
202
+ ciphers = self.randomize_ciphers(tls_profile.ciphers)
203
+ else:
204
+ ciphers = tls_profile.ciphers
205
+
206
+ try:
207
+ cipher_string = ":".join(ciphers)
208
+ context.set_ciphers(cipher_string)
209
+ except ssl.SSLError:
210
+ # Fall back to default if cipher setting fails
211
+ pass
212
+
213
+ # Set minimum TLS version
214
+ context.minimum_version = ssl.TLSVersion.TLSv1_2
215
+
216
+ # Set ALPN protocols
217
+ try:
218
+ alpn = self.randomize_alpn() if profile == "random" else tls_profile.alpn
219
+ context.set_alpn_protocols(alpn)
220
+ except (ssl.SSLError, AttributeError):
221
+ pass
222
+
223
+ return context
224
+
225
+ def get_randomized_context(self, verify: bool = True) -> ssl.SSLContext:
226
+ """
227
+ Get SSL context with randomized fingerprint.
228
+
229
+ Args:
230
+ verify: Verify certificates
231
+
232
+ Returns:
233
+ Randomized SSLContext
234
+ """
235
+ # Randomly pick a browser profile
236
+ profile = random.choice(["chrome", "firefox", "safari", "random"])
237
+ return self.create_ssl_context(profile, verify)
238
+
239
+ def get_cipher_string(self, profile: str = "random") -> str:
240
+ """
241
+ Get cipher string for requests/urllib3.
242
+
243
+ Args:
244
+ profile: TLS profile
245
+
246
+ Returns:
247
+ Cipher string
248
+ """
249
+ tls_profile = self.get_profile(profile)
250
+
251
+ if profile == "random":
252
+ ciphers = self.randomize_ciphers(tls_profile.ciphers)
253
+ else:
254
+ ciphers = tls_profile.ciphers
255
+
256
+ return ":".join(ciphers)
257
+
258
+
259
+ def randomize_tls(verify: bool = True) -> ssl.SSLContext:
260
+ """
261
+ Get randomized TLS context.
262
+
263
+ Args:
264
+ verify: Verify certificates
265
+
266
+ Returns:
267
+ Randomized SSLContext
268
+ """
269
+ tls = TLSFingerprint()
270
+ return tls.get_randomized_context(verify)
271
+
272
+
273
+ def get_browser_tls(browser: str = "chrome", verify: bool = True) -> ssl.SSLContext:
274
+ """
275
+ Get browser-like TLS context.
276
+
277
+ Args:
278
+ browser: Browser name (chrome, firefox, safari)
279
+ verify: Verify certificates
280
+
281
+ Returns:
282
+ Browser-like SSLContext
283
+ """
284
+ tls = TLSFingerprint()
285
+ return tls.create_ssl_context(browser, verify)