Skip to content

Commit 606d19a

Browse files
committed
Update framewalk
1 parent a1912b6 commit 606d19a

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

core/vmnf_smng.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def load_siddhis(self):
8888
# No need for global path tracking - just use relative paths
8989
vimana_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
9090

91+
9192
self.load_tools()
9293
self.list_siddhis()
9394

@@ -254,7 +255,7 @@ def list_siddhis(self):
254255
return False
255256

256257
#case_header()
257-
#print("\033c", end="")
258+
print("\033c", end="")
258259
vimana_version = cl(f'Vimana v{_version_}', 77,attrs=['bold'])
259260
vimana_desc = cl('(Security & Automation Tools for Python Web Frameworks)', 77,attrs=['bold'])
260261
plugin_catalog = cl('Plugin Catalog', 15) # or 97 for bright white

siddhis/framewalk/framewalk.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ description: |
5454
- FastAPI
5555
- Pyramid
5656
- Bottle
57+
- Sanic
58+
- Tornado
59+
- Starlette
5760
- And more...
5861
references:
5962
links:
@@ -62,6 +65,9 @@ references:
6265
- https://fastapi.tiangolo.com/
6366
- https://trypyramid.com/
6467
- https://bottlepy.org/
68+
- https://sanic.dev/
69+
- https://www.tornadoweb.org/
70+
- https://www.starlette.io/
6571
cwe:
6672
- CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor
6773
- CWE-209 - Generation of Error Message Containing Sensitive Information

siddhis/framewalk/orchestrator/fwalk_orchestrator.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,57 @@ def run(self, args=None) -> Dict[str, Any]:
364364

365365
start_time = time.time()
366366

367+
# Calculate global timeout: (timeout + retry_delay) * max_retries * estimated_requests
368+
# Estimated requests: 6 engines + 9 detectors = ~15 components, each making ~2-3 requests
369+
estimated_requests = 45 # Conservative estimate
370+
timeout_per_request = self.config.get('timeout', 10)
371+
max_retries = self.config.get('max_retries', 3)
372+
retry_delay = min(0.5, timeout_per_request / 2)
373+
374+
# Global timeout: (timeout + retry_delay) * (max_retries + 1) * estimated_requests
375+
global_timeout = (timeout_per_request + retry_delay) * (max_retries + 1) * estimated_requests
376+
377+
# Add a reasonable cap to prevent extremely long scans
378+
global_timeout = min(global_timeout, 300) # Max 5 minutes
379+
367380
summary_only = self.config.get('summary_only', False)
368381
verbose_mode = self.config.get('verbose', False)
369382

370383
if not summary_only and hasattr(self.presenter, 'print_status'):
371384
self.presenter.print_status(f"Starting analysis of {self.request_manager.target_url}")
385+
if verbose_mode:
386+
self.presenter.print_status(f"Global timeout set to {global_timeout:.1f} seconds")
387+
388+
# Early connectivity check
389+
if not summary_only and hasattr(self.presenter, 'print_status'):
390+
self.presenter.print_status(" Performing connectivity check...")
391+
392+
connectivity_response = self.request_manager.make_request()
393+
if not connectivity_response:
394+
if not summary_only and hasattr(self.presenter, 'print_status'):
395+
self.presenter.print_status(" Target is unreachable, stopping scan")
396+
397+
# Return early with minimal results
398+
elapsed = time.time() - start_time
399+
results = {
400+
'target_url': self.request_manager.target_url,
401+
'scan_time': elapsed,
402+
'frameworks': [],
403+
'security_headers': [],
404+
'server_info': {},
405+
'error': 'Target is unreachable'
406+
}
407+
408+
# Register the scan in the database
409+
self._record_scan(results, elapsed)
410+
411+
if not summary_only:
412+
self.presenter.print_results(results)
413+
414+
return results
415+
416+
if not summary_only and hasattr(self.presenter, 'print_status'):
417+
self.presenter.print_status(" Target is reachable, proceeding with analysis...")
372418

373419
try:
374420
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
@@ -378,12 +424,26 @@ def run(self, args=None) -> Dict[str, Any]:
378424
engine_name = engine.__class__.__name__
379425
if not summary_only and hasattr(self.presenter, 'print_status'):
380426
self.presenter.print_status(f" Running {engine_name}")
427+
428+
# Check global timeout before each engine
429+
if time.time() - start_time > global_timeout:
430+
if not summary_only and hasattr(self.presenter, 'print_status'):
431+
self.presenter.print_status(f" Global timeout reached, stopping scan")
432+
break
433+
381434
engine.analyze()
382435

383436
for detector in self.detectors:
384437
detector_name = detector.__class__.__name__
385438
if not summary_only and hasattr(self.presenter, 'print_status'):
386439
self.presenter.print_status(f" Running {detector_name}")
440+
441+
# Check global timeout before each detector
442+
if time.time() - start_time > global_timeout:
443+
if not summary_only and hasattr(self.presenter, 'print_status'):
444+
self.presenter.print_status(f" Global timeout reached, stopping scan")
445+
break
446+
387447
detector.detect()
388448
else:
389449
progress = Progress(
@@ -399,6 +459,11 @@ def run(self, args=None) -> Dict[str, Any]:
399459
engine_task = progress.add_task(f"Running engines", total=len(self.engines))
400460

401461
for i, engine in enumerate(self.engines):
462+
# Check global timeout
463+
if time.time() - start_time > global_timeout:
464+
progress.update(engine_task, description="Global timeout reached")
465+
break
466+
402467
engine_name = engine.__class__.__name__
403468
progress.update(engine_task, description=f"Running engine: {engine_name}")
404469
engine.analyze()
@@ -409,6 +474,11 @@ def run(self, args=None) -> Dict[str, Any]:
409474
detector_task = progress.add_task(f"Running detectors", total=len(self.detectors))
410475

411476
for i, detector in enumerate(self.detectors):
477+
# Check global timeout
478+
if time.time() - start_time > global_timeout:
479+
progress.update(detector_task, description="Global timeout reached")
480+
break
481+
412482
detector_name = detector.__class__.__name__
413483
framework_name = detector.FRAMEWORK if hasattr(detector, 'FRAMEWORK') else "Unknown"
414484
progress.update(detector_task, description=f"Running {framework_name}Detector")
@@ -419,12 +489,24 @@ def run(self, args=None) -> Dict[str, Any]:
419489

420490
except ImportError:
421491
for i, engine in enumerate(self.engines, 1):
492+
# Check global timeout
493+
if time.time() - start_time > global_timeout:
494+
if not summary_only:
495+
print("Global timeout reached, stopping scan")
496+
break
497+
422498
engine_name = engine.__class__.__name__
423499
if not summary_only:
424500
print(f"Running engine: {engine_name} ({i}/{len(self.engines)})")
425501
engine.analyze()
426502

427503
for i, detector in enumerate(self.detectors, 1):
504+
# Check global timeout
505+
if time.time() - start_time > global_timeout:
506+
if not summary_only:
507+
print("Global timeout reached, stopping scan")
508+
break
509+
428510
print(detector)
429511
detector_name = detector.__class__.__name__
430512
framework_name = detector.FRAMEWORK if hasattr(detector, 'FRAMEWORK') else "Unknown"

siddhis/framewalk/utils/http.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,10 @@ def make_request(self,
160160
return response
161161

162162
except (Timeout, RequestException) as e:
163-
# Implement retry logic with exponential backoff
163+
# Implement retry logic with shorter backoff
164164
if retry_count < self.max_retries:
165-
backoff_time = 1 * (2 ** retry_count)
165+
# Use a shorter backoff: min(0.5 seconds, timeout/2)
166+
backoff_time = min(0.5, self.timeout / 2)
166167
time.sleep(backoff_time)
167168
return self.make_request(
168169
path, method, data, headers, allow_redirects, retry_count + 1, cache

0 commit comments

Comments
 (0)