Skip to content

Commit 2fddd4b

Browse files
author
s4dhul4bs
committed
General improvements
1 parent a721421 commit 2fddd4b

File tree

3 files changed

+252
-46
lines changed

3 files changed

+252
-46
lines changed

core/vmnf_shared_args.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ def args(self):
8686
vmnf_shared_parser.add_argument("--debug",action="store_true",default=False)
8787
vmnf_shared_parser.add_argument("--verbose", '-v', action='count', default=False)
8888
vmnf_shared_parser.add_argument("--random", action="store_true",default=False)
89-
vmnf_shared_parser.add_argument("--wait", action="store", type=int, default=0) # not in use yet
89+
vmnf_shared_parser.add_argument("--wait", action="store", default=False)
9090
vmnf_shared_parser.add_argument("--threads",action="store", type=int, default=3)
9191
vmnf_shared_parser.add_argument("--timeout", action="store", type=int, default=5)
92-
vmnf_shared_parser.add_argument("--pause-steps", action="store_true",default=False) # not in use yet
93-
vmnf_shared_parser.add_argument("--auto", action="store_true",default=False) # not in use yet
92+
vmnf_shared_parser.add_argument("--pause-steps", action="store_true",default=False)
93+
vmnf_shared_parser.add_argument("--auto", action="store_true",default=False)
9494
# -------------------------------------------------------------------------------
9595
# > Scope setting - [ scope parser options ]
9696
# -------------------------------------------------------------------------------
@@ -109,7 +109,7 @@ def args(self):
109109
def shared_help(self):
110110

111111
'''
112-
target
112+
[target]
113113
114114
--target defines a single target scope
115115
--file defines a file with a target list
@@ -118,14 +118,14 @@ def shared_help(self):
118118
--target-list defines a target list (comma-separeted) scope
119119
--nmap-xml defines the result of the nmap xml as a scope
120120
121-
port
121+
[port]
122122
123123
--port sets a single port scope
124124
--port-list sets a port list scope
125125
--port-range sets port range scope
126126
--ignore-state ignore port status
127127
128-
general
128+
[general]
129129
130130
--debug enables debug information
131131
--verbose enables verbose mode (incremental)
@@ -136,10 +136,11 @@ def shared_help(self):
136136
--pause-steps pause between steps
137137
--auto assume yes for all subtasks
138138
139-
proxy
139+
[proxy]
140140
141-
--set-proxy enables the default proxy for all requests: SOCKS5: //127.0.0.1: 9055
141+
--set-proxy enables the default proxy for all requests: SOCKS5://127.0.0.1:9050
142142
--proxy configures the proxy specified by the ip:port string
143143
--proxy-type specifies the proxy protocol to be used (required --proxy option)
144+
144145
'''
145146

resources/vmnf_banners.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def default_vmn_banner(mode_uvb = False):
184184
if not mode_uvb:
185185
print("\033c", end="")
186186

187-
banner = colored('VIMANA FR4MEWORK', 'green', attrs=['bold','blink'])
187+
banner = colored('VIMANA FR4MEWORK', 'blue', attrs=['blink'])
188188
print(r"""{}
189189
*
190190
_^_ .

siddhis/dmt/dmt.py

Lines changed: 242 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515

1616
from . _dmt_report import resultParser
1717
from core.vmnf_shared_args import VimanaSharedArgs
18-
from core.vmnf_thread_handler import ThreadPool
19-
from core.vmnf_thread_handler import Worker
20-
from core.vmnf_thread_handler import ThreadPool
2118

2219
from resources.session.vmnf_sessions import createSession
2320
from resources.vmnf_validators import get_tool_scope
@@ -30,6 +27,7 @@
3027
from pygments.lexers import PythonLexer
3128
from pygments import highlight
3229

30+
import concurrent.futures
3331
import sys, re, os, random, string, platform
3432
from lxml.html.soupparser import fromstring
3533
from termcolor import colored, cprint
@@ -96,12 +94,23 @@ class siddhi:
9694
def __init__(self, **vmnf_handler):
9795

9896
self.vmnf_handler = vmnf_handler
97+
self.wait = 0.02
98+
if vmnf_handler['wait']:
99+
try:
100+
self.wait = int(vmnf_handler['wait'].strip())
101+
except ValueError:
102+
self.wait = float(vmnf_handler['wait'].strip())
103+
104+
self.auto_mode = vmnf_handler['auto']
99105
self.threads = vmnf_handler['threads']
100106
self.debug = vmnf_handler['debug']
101-
self.auto_mode = vmnf_handler['auto']
102-
self.num_threads = self.threads if self.threads <= 10 else 10
107+
self.timeout = vmnf_handler['timeout']
108+
self.max_workers = 5
109+
self.num_threads = self.threads \
110+
if self.threads <= self.max_workers \
111+
else self.max_workers
112+
103113
self.fuzz_mode = False
104-
self.pool = ThreadPool(self.num_threads)
105114

106115
# root URL patterns
107116
self.xlp_tbl = PrettyTable()
@@ -432,8 +441,7 @@ def djmimic(self):
432441
print(colored(" url(r'^{0}',\n views.{1},\n name='{2}'),".format(
433442
url, view, name), 'white')
434443
)
435-
sleep(0.07)
436-
444+
sleep(self.wait)
437445
print("\n]")
438446
#sleep(1)
439447

@@ -464,44 +472,241 @@ def expand_UP(self, up_fuzz_scope=False):
464472

465473
url_model = {}
466474
trick_name = colors.bn_c + 'NoReverseMatch' + colors.D_c
475+
476+
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
477+
for x_pattern in self.root_url_patterns:
478+
if x_pattern.endswith('/'):
479+
x_pattern = x_pattern[:-1].strip()
480+
self.x_pattern = x_pattern
481+
482+
app_name = ("app_name = '" + x_pattern + "'")
483+
expanded_pattern = '{}/{}/_._x'.format(self.dmt_start_base_r, x_pattern)
484+
485+
sys.stdout.write("\r{0} Mapping URL pattern via {1} ({2}/{3}) -> {4}".format(
486+
colors.Gn_c + "⠿⠥" + colors.C_c,
487+
trick_name,
488+
up_c, n_up,
489+
colors.Y_c + x_pattern + colors.D_c,
490+
colors.Y_c + app_name + colors.D_c
491+
)
492+
)
493+
sys.stdout.flush()
494+
sleep(self.wait)
467495

468-
for x_pattern in self.root_url_patterns:
469-
self.x_pattern = x_pattern
470-
if x_pattern.endswith('/'):
471-
x_pattern = x_pattern[:-1].strip()
496+
self.vmnf_handler['target_url'] = expanded_pattern
497+
future = executor.submit(createSession, **self.vmnf_handler)
498+
up_c += 1
472499

473-
app_name = ("app_name = '" + x_pattern + "'")
474-
expanded_pattern = '{}/{}/_._x'.format(self.dmt_start_base_r, x_pattern)
475-
476-
sys.stdout.write("\r{0} Mapping URL pattern via {1} ({2}/{3}) -> {4}".format(
477-
colors.Gn_c + "⠿⠥" + colors.C_c,
478-
trick_name,
479-
up_c, n_up,
480-
colors.Y_c + x_pattern + colors.D_c,
481-
colors.Y_c + app_name + colors.D_c
482-
)
500+
response = (future.result())
501+
self.expanded_response = self.get_unescape_html(response.text)
502+
response_status = response.status_code
503+
504+
if self.expanded_response:
505+
if response_status == 404:
506+
self.get_url_patterns()
507+
if self.vmnf_handler['debug']:
508+
self.djmimic()
509+
elif response_status == 500:
510+
self.dxt_parser(self.expanded_response, False, True)
511+
512+
print()
513+
print(self.xlp_tbl_x)
514+
515+
return self.expanded_patterns
516+
517+
def parse_args(self):
518+
''' ~ siddhi needs only shared arguments from VimanaSharedArgs() ~'''
519+
parser = argparse.ArgumentParser(
520+
add_help=False,
521+
parents=[VimanaSharedArgs().args()]
522+
)
523+
return parser
524+
525+
def issues_presentation(self):
526+
# create instance of dmt reporter
527+
result = resultParser(
528+
self.xlp_tbl_x,
529+
self.mu_patterns,
530+
self.fuzz_result,
531+
**self.vmnf_handler
532+
)
533+
# call reporter
534+
result.show_issues()
535+
536+
def start(self):
537+
538+
_scope_ = {}
539+
target_list = []
540+
port_list = []
541+
invalid_targets = []
542+
port_step = ''
543+
544+
dmt_handler= argparse.Namespace(
545+
ignore_state = False, # ignore state - disable IP and port state verification
546+
single_target = False, # single target scope
547+
scope = False, # file with a list of targets
548+
range = False, # ip range, 192.168.12.0-20
549+
cidr = False, # cidr range: 192.168.32.0/26
550+
port = False, # single port verification
551+
single_port = None, # single port verification
552+
portr = False, # port range: 8000-8010
553+
portl = False, # port list: 8999, 5001, 9000, 7120
554+
debug = False # debug mode
555+
)
556+
557+
options = self.parse_args()
558+
dmt_handler.args = options.parse_known_args(
559+
namespace=dmt_handler)[1]
560+
561+
if not self.vmnf_handler['scope']:
562+
print(VimanaSharedArgs().shared_help.__doc__)
563+
sys.exit(1)
564+
565+
# here we just need to get a list of valid scope
566+
targets_ports_set = get_tool_scope(**self.vmnf_handler)
567+
self.tps = targets_ports_set
568+
569+
ports = []
570+
for p in targets_ports_set:
571+
ports.append(p.split(':')[1].strip())
572+
573+
self.last_step = False
574+
self.debug = dmt_handler.debug
575+
self.exp_mode = False
576+
start = True
577+
last_step = False
578+
server_flag_found = False
579+
request_fail = 0
580+
581+
for entry in targets_ports_set:
582+
''' have to change this to auto choose the right scheme'''
583+
self.target = 'http://' + entry
584+
port = entry.split(':')[1].strip()
585+
586+
dmt_start = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
587+
c_target = colored(self.target,'green')
588+
cprint("[{0}] Starting DMT against {1}...".format(datetime.now(),c_target), 'cyan')
589+
sleep(1)
590+
591+
xvals = ['_','.','','^','~','-']
592+
fakefile = "/{}{}".format(
593+
random.choice(xvals),
594+
self.random_value(random.choice(range(1,6)))
483595
)
484-
sys.stdout.flush()
485-
sleep(self.vmnf_handler['wait'])
486-
up_c += 1
487-
488-
# up request
489-
self.vmnf_handler['target_url'] = expanded_pattern
596+
base_r = self.target
597+
payload_ = base_r + fakefile
598+
599+
self.vmnf_handler['target_url'] = payload_
490600
response = createSession(**self.vmnf_handler)
491-
self.expanded_response = self.get_unescape_html(response.text)
601+
602+
if response is None:
603+
# because with target --port will be just one port, doesnt need such control like request_fail
604+
605+
if not self.vmnf_handler['single_port']:
606+
# control request fails to improve consistence of module
607+
request_fail += 1
608+
if request_fail > 3:
609+
request_fail = 0
610+
print("\nHi, sadhu! Too many fails in this process, try to discovery host before!")
611+
612+
cprint('''[{}] DMT did not receive a valid response from the target, nothing to do.
613+
'''.format(datetime.now()), 'red', attrs=[])
614+
615+
# to continue testing other ports
616+
if (len(targets_ports_set) > 1):
617+
continue
618+
else:
619+
break
620+
621+
current_response = self.get_unescape_html(response.text)
492622
response_status = response.status_code
623+
found_exception_flag = True if 'Exception Type' \
624+
in current_response else False
625+
626+
if start or not server_flag_found:
627+
'''just to check if there is any known django/python keyword in response headers'''
493628

494-
if self.expanded_response:
495-
if response_status == 404:
629+
start = False
630+
# just a test to blackbox fingerprint...
631+
flags = [
632+
'Python','WSGIServer', 'CPython',
633+
'Django', 'CherryPy', 'gunicorn',
634+
'Flask','web2py', 'mod_wsgi', 'APACHE'
635+
]
636+
637+
for header in response.headers:
638+
for flag in flags:
639+
flag = flag.lower()
640+
try:
641+
value = (response.headers[header])
642+
except KeyError:
643+
continue
644+
645+
if flag in header.lower() or flag in value.lower():
646+
server_flag_found = True
647+
header = str(' → ' + header + ": ")
648+
print("\n")
649+
self.print_it(header, value)
650+
651+
self.expanded_response = current_response
652+
self.dmt_start_request = current_response
653+
self.dmt_start_base_r = base_r
654+
self.dmt_start_port = port
655+
self.dmt_start_last_step= last_step
656+
657+
if response_status == 400:
658+
if found_exception_flag:
659+
self.handle_discovery_xt()
660+
else:
661+
print('''\n[dmt: {}]: The target does not appear to be vulnerable.
662+
\rMake sure that the analysis settings are correct:\n'''.format(
663+
datetime.now()
664+
)
665+
)
666+
for set_k, set_v in (self.vmnf_handler.items()):
667+
if set_k != 'scope' and set_v:
668+
print('{}{}:\t{}'.format(
669+
(' ' * int(5-len(set_k) + 10)),set_k,
670+
colored(set_v, 'blue')
671+
)
672+
)
673+
sys.exit(1)
674+
675+
if response_status == 404:
676+
# Check if last step
677+
if (targets_ports_set.index(entry) + 1) == (len(targets_ports_set)):
678+
last_step = True
679+
680+
if self.debug_is_true():
681+
'''status is 404 and DEBUG is True so run another tests'''
682+
683+
# Basic DMT actions
496684
self.get_url_patterns()
685+
self.expand_UP()
686+
self.check_api_auth_points()
687+
self.check_django_adm()
688+
689+
# extending DMT: Call DJunch fuzzer and create instances of object result
690+
# this result, a list of dictionaries (2) will be used to resultParser
691+
self.fuzz_result = Djunch(
692+
base_r, self.expanded_patterns,
693+
**self.vmnf_handler).start()
497694

498-
if self.vmnf_handler['debug']:
499-
self.djmimic()
500-
elif response_status == 500:
501-
self.dxt_parser(self.expanded_response, False, True)
695+
response = (future.result())
696+
self.expanded_response = self.get_unescape_html(response.text)
697+
response_status = response.status_code
698+
699+
# print("\nThreaded time:", time.time() - threaded_start)
700+
if self.expanded_response:
701+
if response_status == 404:
702+
self.get_url_patterns()
703+
if self.vmnf_handler['debug']:
704+
self.djmimic()
705+
elif response_status == 500:
706+
self.dxt_parser(self.expanded_response, False, True)
502707

503-
print()
504-
print(self.xlp_tbl_x)
708+
print()
709+
print(self.xlp_tbl_x)
505710

506711
return self.expanded_patterns
507712

0 commit comments

Comments
 (0)