Skip to content

Commit a1912b6

Browse files
committed
Update framewalk
1 parent d534300 commit a1912b6

File tree

8 files changed

+229
-179
lines changed

8 files changed

+229
-179
lines changed

core/_dbops_/db/vmnf.db

-468 KB
Binary file not shown.

core/vmnf_sessions_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def abduct_items(**vfres):
4444
}
4545

4646
print(f"\t ⠞⠓⠊⠎ Abducting {cl(siddhi.lower(), 'red', attrs=['bold'])}: {cl(brief,'white')} ...")
47-
sleep(0.15)
47+
sleep(0.1)
4848

4949
for k,v in vfres.items():
5050
print("\033c", end="")

core/vmnf_shared_args.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ def args(self):
166166
vmnf_shared_parser.add_argument("--target-exceptions", action="store", dest='target_exceptions',default=False)
167167
vmnf_shared_parser.add_argument("--skip-exception", action="store", dest='skip_exception',default=False)
168168
vmnf_shared_parser.add_argument("--skip-exceptions", action="store", dest='skip_exceptions',default=False)
169+
vmnf_shared_parser.add_argument("--exception-count", action="store", type=int, dest='exception_count',default=False)
169170
# -------------------------------------------------------------------------------
170171
# > Connection setting - [ proxy options ]
171172
# -------------------------------------------------------------------------------

core/vmnf_smng.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def load_siddhis(self):
6767

6868
for s in os.scandir(f'{os.getcwd()}/siddhis/'):
6969
print(f"\tLoading {s.name}...")
70-
sleep(0.1)
70+
#sleep(0.1)
7171

7272
if (s.is_dir() and not s.name.startswith('_')):
7373
plugin_docs = f"{s.path}/{s.name}.yaml"

siddhis/d4m8/engines/_d4m8_engine.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ def record(self):
583583
scan_template['has_issues'] = True
584584

585585
try:
586+
self.handler['framework'] = 'Django'
587+
self.handler['framework_version'] = self.handler['django_version']
586588
cves,cves_table = prana(**self.handler).get_cves_for_version()
587589
# TypeError: cannot unpack non-iterable bool object
588590
except TypeError:
@@ -701,4 +703,3 @@ def closed(self,reason):
701703
self.record()
702704
reactor.stop()
703705
os._exit(os.EX_OK)
704-

siddhis/framewalk/detectors/sanic.py

Lines changed: 105 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# \/imana 2016
44
# [|-ramewørk
55
#
6-
#
76
# Author: s4dhu
87
# Email: <s4dhul4bs[at]prontonmail[dot]ch
98
# Git: @s4dhulabs
@@ -17,230 +16,176 @@
1716

1817
from .base import BaseDetector
1918

20-
2119
class SanicDetector(BaseDetector):
22-
"""Sanic-specific detection methods"""
20+
"""Sanic-specific detection methods (improved for specificity)"""
2321

2422
FRAMEWORK = "Sanic"
2523

26-
# Common Sanic paths to check
2724
COMMON_PATHS = [
2825
'/api/status',
29-
'/about',
3026
'/error',
27+
'/about',
3128
'/health',
3229
'/metrics',
3330
'/docs',
3431
'/openapi.json',
3532
'/api/docs',
3633
]
3734

38-
# Sanic error patterns
3935
ERROR_PATTERNS = [
40-
# Pattern, Description, Confidence
41-
(r'⚠️ \d+ — [^=]+', 'Sanic error page format', 25),
42-
(r'Traceback of \w+_test_app', 'Sanic test app traceback', 30),
43-
(r'Exception: [^=]+ while handling path', 'Sanic exception handling', 25),
44-
(r'File /usr/local/lib/python3\.9/site-packages/sanic/app\.py', 'Sanic app.py reference', 35),
45-
(r'==============================', 'Sanic error separator', 15),
36+
(r'SanicException', 'SanicException in error page', 30),
37+
(r'sanic_test_app', 'Sanic test app traceback', 30),
38+
(r'Sanic\s+\d+\.\d+\.\d+', 'Sanic version in error', 20),
39+
(r'sanic/app\.py', 'Sanic app.py in traceback', 25),
40+
(r'sanic.server', 'Sanic server in traceback', 20),
4641
(r'Exception: Test error for framework detection', 'Sanic test error', 20),
42+
(r'(?i)sanic', 'Sanic reference in error', 10),
4743
]
4844

49-
# Sanic content patterns
5045
CONTENT_PATTERNS = [
51-
# Pattern, Description, Confidence
5246
(r'Hello from Sanic!', 'Sanic greeting in content', 20),
5347
(r'<title>Sanic Test App</title>', 'Sanic test app title', 25),
5448
(r'<h1>Hello from Sanic!</h1>', 'Sanic heading in content', 20),
55-
(r'This is a minimal Sanic application', 'Sanic app description', 15),
56-
(r'<a href="/api/status">API Status</a>', 'Sanic API status link', 10),
57-
(r'<a href="/about">About</a>', 'Sanic about link', 10),
49+
(r'Sanic Framework Detection Test', 'Sanic detection test string', 20),
50+
(r'Sanic is a Python 3.7\+ web server', 'Sanic description', 15),
51+
(r'(?i)sanic', 'Sanic reference in HTML', 10),
5852
]
5953

60-
# Sanic header patterns (though Sanic doesn't have many unique headers)
6154
HEADER_PATTERNS = [
62-
# Header name, Pattern, Description, Confidence
63-
('content-type', r'text/plain; charset=utf-8', 'Sanic plain text response', 5),
64-
('Allow', r'GET', 'Sanic GET method allowance', 3),
55+
('server', r'uvicorn', 'Uvicorn server header (common for Sanic)', 5),
56+
('content-type', r'application/json', 'JSON API response', 3),
6557
]
6658

67-
# Sanic API response patterns
6859
API_PATTERNS = [
69-
# Pattern, Description, Confidence
70-
(r'"status": "running"', 'Sanic API status response', 20),
71-
(r'"framework": "sanic"', 'Sanic framework identification', 25),
72-
(r'"version": "\d+\.\d+\.\d+"', 'Sanic version in API', 15),
60+
(r'"framework": ?"sanic"', 'Sanic framework in API response', 30),
61+
(r'"status": ?"running"', 'Status running in API response', 10),
62+
(r'"version": ?"[0-9.]+"', 'Version in API response', 10),
7363
]
7464

7565
def detect(self) -> None:
76-
"""Run Sanic detection methods"""
77-
self._check_headers()
78-
self._check_content_patterns()
79-
self._check_error_patterns()
80-
self._check_api_endpoints()
81-
self._check_common_paths()
66+
evidence = set()
67+
evidence_types = set()
68+
# Check error page for Sanic-specific patterns
69+
if self._check_error_patterns(evidence, evidence_types):
70+
pass
71+
# Check API status endpoint for Sanic-specific JSON
72+
if self._check_api_status(evidence, evidence_types):
73+
pass
74+
# Check main page and about for Sanic content
75+
if self._check_content_patterns(evidence, evidence_types):
76+
pass
77+
# Check headers for Uvicorn and JSON
78+
if self._check_headers(evidence, evidence_types):
79+
pass
80+
# Check common paths for 200 OK (low confidence)
81+
self._check_common_paths(evidence, evidence_types)
82+
# Assign confidence based on evidence
83+
self._score_evidence(evidence, evidence_types)
8284
self.detect_version()
83-
84-
def _add_score(self,
85-
points: int,
86-
evidence_type: str,
87-
detail: str,
88-
raw_data: Optional[Dict[str, Any]] = None) -> None:
89-
"""Add score for Sanic"""
85+
86+
def _add_score(self, points: int, evidence_type: str, detail: str, raw_data: Optional[Dict[str, Any]] = None) -> None:
9087
self.result_manager.add_score(self.FRAMEWORK, points, evidence_type, detail, raw_data)
91-
92-
def _add_version_hint(self,
93-
version: str,
94-
confidence: int,
95-
evidence: str) -> None:
96-
"""Add version hint for Sanic"""
88+
89+
def _add_version_hint(self, version: str, confidence: int, evidence: str) -> None:
9790
self.result_manager.add_version_hint(self.FRAMEWORK, version, confidence, evidence)
98-
99-
def _add_component(self,
100-
component: str,
101-
evidence: str) -> None:
102-
"""Add component for Sanic"""
91+
92+
def _add_component(self, component: str, evidence: str) -> None:
10393
self.result_manager.add_component(self.FRAMEWORK, component, evidence)
104-
105-
def _check_headers(self) -> None:
106-
"""Check for Sanic-specific headers"""
94+
95+
def _check_headers(self, evidence, evidence_types) -> bool:
10796
response = self.request_manager.make_request()
10897
if not response:
109-
return
110-
98+
return False
11199
headers = response.headers
112-
113-
# Check header patterns
100+
found = False
114101
for header_name, pattern, description, confidence in self.HEADER_PATTERNS:
115102
if header_name in headers:
116103
header_value = headers[header_name]
117104
if re.search(pattern, header_value, re.IGNORECASE):
118-
self._add_score(
119-
confidence,
120-
'Header',
121-
f"{description}: {header_name}: {header_value}"
122-
)
123-
124-
# Check for 405 Method Not Allowed (common in Sanic for HEAD requests)
125-
if response.status_code == 405:
126-
self._add_score(
127-
10,
128-
'Header',
129-
f"405 Method Not Allowed response (common in Sanic)"
130-
)
131-
132-
def _check_content_patterns(self) -> None:
133-
"""Check for Sanic content patterns"""
105+
evidence.add(f"Header: {description}")
106+
evidence_types.add('header')
107+
found = True
108+
return found
109+
110+
def _check_content_patterns(self, evidence, evidence_types) -> bool:
134111
response = self.request_manager.make_request()
135112
if not response:
136-
return
137-
138-
# Check content patterns
113+
return False
114+
found = False
139115
for pattern, description, confidence in self.CONTENT_PATTERNS:
140116
if re.search(pattern, response.text, re.IGNORECASE):
141-
self._add_score(
142-
confidence,
143-
'Content',
144-
f"{description}: {pattern}"
145-
)
146-
147-
def _check_error_patterns(self) -> None:
148-
"""Check for Sanic error patterns"""
117+
evidence.add(f"Content: {description}")
118+
evidence_types.add('content')
119+
found = True
120+
return found
121+
122+
def _check_error_patterns(self, evidence, evidence_types) -> bool:
149123
base_url = self.request_manager.target_url.rstrip('/')
150124
error_url = urljoin(base_url, '/error')
151-
152125
response = self.request_manager.make_request(error_url)
153126
if not response:
154-
return
155-
156-
# Check error patterns in response text
127+
return False
128+
found = False
157129
for pattern, description, confidence in self.ERROR_PATTERNS:
158130
if re.search(pattern, response.text, re.IGNORECASE):
159-
self._add_score(
160-
confidence,
161-
'Error',
162-
f"{description}: {pattern}"
163-
)
164-
165-
def _check_api_endpoints(self) -> None:
166-
"""Check for Sanic API endpoints"""
131+
evidence.add(f"Error: {description}")
132+
evidence_types.add('error')
133+
found = True
134+
return found
135+
136+
def _check_api_status(self, evidence, evidence_types) -> bool:
167137
base_url = self.request_manager.target_url.rstrip('/')
168138
api_url = urljoin(base_url, '/api/status')
169-
170139
response = self.request_manager.make_request(api_url)
171140
if not response:
172-
return
173-
174-
# Check API response patterns
141+
return False
142+
found = False
175143
for pattern, description, confidence in self.API_PATTERNS:
176144
if re.search(pattern, response.text, re.IGNORECASE):
177-
self._add_score(
178-
confidence,
179-
'API',
180-
f"{description}: {pattern}"
181-
)
182-
183-
# Check for JSON response
145+
evidence.add(f"API: {description}")
146+
evidence_types.add('api')
147+
found = True
184148
if response.headers.get('content-type', '').startswith('application/json'):
185-
self._add_score(
186-
15,
187-
'API',
188-
"JSON API response detected"
189-
)
190-
191-
def _check_common_paths(self) -> None:
192-
"""Check for Sanic-specific paths"""
149+
evidence.add("API: JSON API response detected")
150+
evidence_types.add('api')
151+
found = True
152+
return found
153+
154+
def _check_common_paths(self, evidence, evidence_types):
193155
base_url = self.request_manager.target_url.rstrip('/')
194-
195156
for path in self.COMMON_PATHS:
196157
url = urljoin(base_url, path)
197158
response = self.request_manager.make_request(url)
198-
199-
if response:
200-
# Check for successful responses
201-
if response.status_code == 200:
202-
self._add_score(
203-
10,
204-
'Endpoint',
205-
f"{path} returns 200 OK"
206-
)
207-
208-
# Check for 405 responses (common in Sanic)
209-
elif response.status_code == 405:
210-
self._add_score(
211-
8,
212-
'Endpoint',
213-
f"{path} returns 405 Method Not Allowed (Sanic behavior)"
214-
)
215-
159+
if response and response.status_code == 200:
160+
# Only add as low confidence evidence
161+
evidence.add(f"Endpoint: {path} returns 200 OK")
162+
evidence_types.add('endpoint')
163+
164+
def _score_evidence(self, evidence, evidence_types):
165+
# High confidence: at least 2 unique types of strong evidence
166+
strong_types = {'error', 'api', 'content'}
167+
strong_evidence = strong_types.intersection(evidence_types)
168+
if len(strong_evidence) >= 2:
169+
self._add_score(90, 'Composite', f"Sanic detected by: {sorted(strong_evidence)} | {sorted(evidence)}")
170+
elif 'error' in evidence_types and 'api' in evidence_types:
171+
self._add_score(70, 'Composite', f"Sanic error and API evidence: {sorted(evidence)}")
172+
elif 'error' in evidence_types:
173+
self._add_score(30, 'Error', f"Sanic error evidence: {sorted(evidence)}")
174+
elif 'api' in evidence_types:
175+
self._add_score(30, 'API', f"Sanic API evidence: {sorted(evidence)}")
176+
elif 'content' in evidence_types:
177+
self._add_score(20, 'Content', f"Sanic content evidence: {sorted(evidence)}")
178+
elif 'header' in evidence_types:
179+
self._add_score(10, 'Header', f"Sanic header evidence: {sorted(evidence)}")
180+
elif 'endpoint' in evidence_types:
181+
self._add_score(5, 'Endpoint', f"Sanic endpoint evidence: {sorted(evidence)}")
182+
216183
def detect_version(self) -> None:
217-
"""Attempt to detect Sanic version"""
218-
# Check error page for version hints
219184
base_url = self.request_manager.target_url.rstrip('/')
220-
error_url = urljoin(base_url, '/error')
221-
222-
response = self.request_manager.make_request(error_url)
223-
if not response:
224-
return
225-
226-
# Look for version in error traceback
227-
version_match = re.search(r'sanic/app\.py', response.text)
228-
if version_match:
229-
self._add_version_hint(
230-
"Unknown",
231-
50,
232-
"Sanic app.py referenced in error traceback"
233-
)
234-
235-
# Check API endpoint for version
236185
api_url = urljoin(base_url, '/api/status')
237-
api_response = self.request_manager.make_request(api_url)
238-
if api_response:
239-
version_match = re.search(r'"version": "(\d+\.\d+\.\d+)"', api_response.text)
186+
response = self.request_manager.make_request(api_url)
187+
if response:
188+
version_match = re.search(r'"version": ?"([0-9.]+)"', response.text)
240189
if version_match:
241190
version = version_match.group(1)
242-
self._add_version_hint(
243-
version,
244-
80,
245-
f"Sanic version detected in API response: {version}"
246-
)
191+
self._add_version_hint(version, 80, f"Sanic version detected in API response: {version}")

0 commit comments

Comments
 (0)