Skip to content

Commit

Permalink
Added metasploit import
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Shaposhnikov committed Dec 5, 2021
1 parent a77ed7f commit f18d635
Show file tree
Hide file tree
Showing 7 changed files with 416 additions and 6 deletions.
284 changes: 279 additions & 5 deletions routes/ui/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,13 +529,10 @@ def nikto_page_form(project_id, current_project, current_user):
# json files
for file in form.json_files.data:
if file.filename:
json_report_data = file.read().decode('charmap').replace(',]',
']').replace(
',}', '}')
json_report_data = file.read().decode('charmap').replace(',]', ']').replace(',}', '}')
scan_result = json.loads(json_report_data)
host = scan_result['ip']
hostname = scan_result['host'] if scan_result['ip'] != \
scan_result['host'] else ''
hostname = scan_result['host'] if scan_result['ip'] != scan_result['host'] else ''
issues = scan_result['vulnerabilities']
port = int(scan_result['port'])
protocol = 'https' if '443' in str(port) else 'http'
Expand Down Expand Up @@ -4733,6 +4730,7 @@ def theharvester_page(project_id, current_project, current_user):
@check_session
@check_project_access
@send_log_data
@check_project_archived
def theharvester_page_form(project_id, current_project, current_user):
form = theHarvesterForm()
form.validate()
Expand Down Expand Up @@ -4773,3 +4771,279 @@ def theharvester_page_form(project_id, current_project, current_user):
current_project=current_project,
tab_name='theHarvester',
errors=errors)


@routes.route('/project/<uuid:project_id>/tools/metasploit/', methods=['GET'])
@requires_authorization
@check_session
@check_project_access
@send_log_data
def metasploit_page(project_id, current_project, current_user):
return render_template('project/tools/import/metasploit.html',
current_project=current_project,
tab_name='Metasploit')


@routes.route('/project/<uuid:project_id>/tools/metasploit/', methods=['POST'])
@requires_authorization
@check_session
@check_project_access
@send_log_data
@check_project_archived
def metasploit_page_form(project_id, current_project, current_user):
form = MetasploitForm()
form.validate()
errors = []
if form.errors:
for field in form.errors:
for error in form.errors[field]:
errors.append(error)

'''
<MetasploitV5>
1. <hosts> - hosts info (domain/ip) - ignore <vulns>
2. <events> - ignoring
3. <web_sites>
4. <web_pages> - ignoring
5. <web_forms> - ignoring
6. <web_vuln>
Steps:
1. Add hosts
2. Add sites
3. Add site vulns
'''

if not errors:
for file in form.xml_files.data:
if file.filename:
soup = BeautifulSoup(file.read(), "html.parser")

# Add hosts & ports
hosts_obj = soup.find('hosts')

scan_result = hosts_obj.findAll('host')

hosts_dict = {}
ports_dict = {}

for host_row in scan_result:
host_report_id = host_row.find('id').text
host_ip = host_row.find('address').text
host_mac = host_row.find('mac').text
host_state = host_row.find('state').text
host_os = host_row.find('os-name').text # Linux
host_os_flavor = host_row.find('os-flavor').text # ???
host_os_version = host_row.find('os-sp').text # 2.6.X
host_os_lang = host_row.find('os-lang').text # ???
host_os_arch = host_row.find('arch').text # x86_64
host_os_detected_arch = host_row.find('detected-arch').text # x86_64
host_os_family = host_row.find('os-family').text # Linux
host_type = host_row.find('purpose').text # device
host_info = host_row.find('info').text
host_comments = host_row.find('comments').text

# create Host OS string
host_os_full = ''
if host_os:
host_os_full += host_os
if host_os_family and host_os_family != host_os:
host_os_full += '({})'.format(host_os_family)
if host_os_flavor:
host_os_full += ' ' + host_os_flavor
if host_os_version:
host_os_full += ' ' + host_os_version
if host_os_lang:
host_os_full += ' Lang:{}'.format(host_os_lang)
if host_os_arch:
host_os_full += ' Arch:{}'.format(host_os_arch)
if host_os_detected_arch and host_os_detected_arch != host_os_arch:
host_os_full += ' Arch detected:{}'.format(host_os_detected_arch)

# create host description string
host_description_full = ''
if host_mac:
host_description_full += '\nMAC: {}'.format(host_mac)
if host_state:
host_description_full += '\nState: {}'.format(host_state)
if host_type:
host_description_full += '\nType: {}'.format(host_type)
if host_info:
host_description_full += '\nInfo: {}'.format(host_info)
if host_comments:
host_description_full += '\nComments: {}'.format(host_comments)

# check if ip correct
ipaddress.ip_address(host_ip)

hosts_dict[host_report_id] = {
'ip': host_ip,
'description': host_description_full.strip(' \t\n\r'),
'os': host_os_full
}

# add ports
services_object = host_row.find('services')
services_arr = services_object.findAll('service')

# add all ports to ports_dict
for port_row in services_arr:
port_report_id = port_row.find('id').text
port_num = int(port_row.find('port').text) # 80
port_is_tcp = port_row.find('proto').text == 'tcp'
port_state = port_row.find('state').text # open closed filtered TODO: add option which port to add
port_service = port_row.find('name').text # ftp
port_info = port_row.find('info').text # vsftpd 2.3.4
if port_num > 0 and port_num < 65536:
ports_dict[port_report_id] = {
'port': port_num,
'is_tcp': port_is_tcp,
'state': port_state,
'service': port_service,
'info': port_info,
'host_report_id': host_report_id
}

# add notes to port objects - nmap scripts
if form.add_nmap_scripts.data:
notes_object = host_row.find('notes')
notes_arr = notes_object.findAll('note')
for note_row in notes_arr:
script_name = note_row.find('ntype').text # nmap.nse.smb-os-discovery.host
if script_name not in ['host.comments', 'host.info', 'host.os.nmap_fingerprint', 'host.name']:
host_report_id = note_row.find('host-id').text
script_critical = note_row.find('critical').text # ???
service_report_id = note_row.find('service-id').text
try:
script_data = base64.b64decode(note_row.find('data').text)[16:].decode('charmap').strip(' \n\t\r')
except Exception as e:
script_data = note_row.find('data').text.strip(' \n\t\r')
while ' ' in script_data:
script_data = script_data.replace(' ', ' ')
note_full = 'Script: {}'.format(script_name)
if script_critical:
note_full += '\nCritical: {}'.format(script_critical)
if script_data:
note_full += '\nOutput:\n\n{}\n\n'.format(script_data)

note_full = note_full.strip(' \t\n\r')

if service_report_id:
ports_dict[service_report_id]['info'] += '\n' + note_full
elif host_report_id:
hosts_dict[host_report_id]['description'] += '\n' + note_full

# add hosts
for host_obj in hosts_dict:
current_host = db.select_project_host_by_ip(current_project['id'], hosts_dict[host_obj]['ip'])
if current_host:
host_id = current_host[0]['id']
if hosts_dict[host_obj]['description']:
db.update_host_description(host_id, hosts_dict[host_obj]['description'])
if hosts_dict[host_obj]['os']:
db.update_host_os(host_id, hosts_dict[host_obj]['os'])
else:
host_id = db.insert_host(current_project['id'], hosts_dict[host_obj]['ip'], current_user['id'],
hosts_dict[host_obj]['description'], os=hosts_dict[host_obj]['os'])
hosts_dict[host_obj]['pcf_id'] = host_id

# add ports
for port_obj in ports_dict:
current_port = db.select_host_port(hosts_dict[ports_dict[port_obj]['host_report_id']]['pcf_id'],
ports_dict[port_obj]['port'],
ports_dict[port_obj]['is_tcp'])
if current_port:
port_id = current_port[0]['id']
db.update_port_proto_description(port_id, ports_dict[port_obj]['service'], ports_dict[port_obj]['info'])
else:
port_id = db.insert_host_port(hosts_dict[ports_dict[port_obj]['host_report_id']]['pcf_id'],
ports_dict[port_obj]['port'], ports_dict[port_obj]['is_tcp'], ports_dict[port_obj]['service'],
ports_dict[port_obj]['info'], current_user['id'], current_project['id'])
ports_dict[port_obj]['pcf_id'] = port_id

# ignoring websites due to it is connected with services which were added earlier

if not form.only_nmap.data:
# create websites_dict

web_dict = {}

websites_obj = soup.find('web_sites')

website_row = websites_obj.findAll('web_site')

for website_obj in website_row:
web_id = website_obj.find('id').text
service_id = website_obj.find('service-id').text
vhost = website_obj.find('vhost').text
pcf_port_id = ports_dict[service_id]['pcf_id']
pcf_host_id = hosts_dict[ports_dict[service_id]['host_report_id']]['pcf_id']
pcf_hostname_id = 0
if vhost:
current_hostname = db.select_ip_hostname(pcf_host_id, vhost)
if current_hostname:
hostname_id = current_hostname[0]['id']
else:
hostname_id = db.insert_hostname(pcf_host_id, vhost, form.hostnames_description.data, current_user['id'])
pcf_hostname_id = hostname_id

web_dict[web_id] = {
'pcf_port_id': pcf_port_id,
'pcf_host_id': pcf_host_id,
'pcf_hostname_id': pcf_hostname_id
}
# Add web vulns
vulns_obj = soup.find('web_vulns')

vuln_row = vulns_obj.findAll('web_vuln')

for vuln_obj in vuln_row:
vuln_url = vuln_obj.find('path').text
vuln_method = vuln_obj.find('method').text
vuln_param = vuln_obj.find('pname').text
vuln_params = base64.b64decode(vuln_obj.find('params').text).decode('charmap')[4:] # i dont know how to parse better
vuln_description = vuln_obj.find('description').text
vuln_payload = vuln_obj.find('payload').text
vuln_website_id = vuln_obj.find('web-site-id').text
vuln_cvss = float(vuln_obj.find('risk').text)
vuln_name = 'Metasploit: {}'.format(vuln_obj.find('name').text)
vuln_poc_str = vuln_obj.find('proof').text
vuln_query = vuln_obj.find('query').text

vuln_description_full = vuln_description
if vuln_poc_str:
vuln_description_full += '\nPoC: {}'.format(vuln_poc_str)
if vuln_query:
vuln_description_full += '\nQuery: {}'.format(vuln_query)
if vuln_params:
vuln_description_full += '\nParams: {}'.format(vuln_params)
if vuln_payload:
vuln_description_full += '\nPayload: {}'.format(vuln_payload)

vuln_param_full = '({}) {}'.format(vuln_method, vuln_param)

if vuln_cvss < 0 or vuln_cvss > 10:
vuln_cvss = 0

services = {web_dict[vuln_website_id]['pcf_port_id']: [web_dict[vuln_website_id]['pcf_hostname_id']]}

issue_id = db.insert_new_issue_no_dublicate(vuln_name,
vuln_description_full,
vuln_url,
vuln_cvss,
current_user['id'],
services,
'Need to recheck',
current_project['id'],
cve='',
cwe='',
issue_type='web',
fix='',
param=vuln_param_full
)

return render_template('project/tools/import/metasploit.html',
current_project=current_project,
tab_name='Metasploit',
errors=errors)
Binary file added static/images/metasploit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions system/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,17 @@ def update_host_description(self, host_id, comment):
'Updated host {} description'.format(current_host['ip']))
return

def update_host_description(self, host_id, comment):
self.execute(
'''UPDATE Hosts SET comment=? WHERE id=? ''',
(comment, host_id)
)
self.conn.commit()
current_host = self.select_host(host_id)[0]
self.insert_log(
'Updated host {} description'.format(current_host['ip']))
return

def select_project_chats(self, project_id, js=False):
self.cursor.close()
self.cursor = self.conn.cursor()
Expand Down
8 changes: 8 additions & 0 deletions system/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1163,3 +1163,11 @@ class theHarvesterForm(FlaskForm):
xml_files = MultipleFileField('xml_files')
hosts_description = StringField('hosts_description', default='Added from theHarvester scan')
hostnames_description = StringField('hostnames_description', default='Added from theHarvester scan')


class MetasploitForm(FlaskForm):
xml_files = MultipleFileField('xml_files')
ports_description = StringField('ports_description', default='Added from Metasploit scan')
hostnames_description = StringField('hostnames_description', default='Added from Metasploit scan')
add_nmap_scripts = IntegerField('add_nmap_scripts', default=0)
only_nmap = IntegerField('only_nmap', default=0)
Loading

0 comments on commit f18d635

Please sign in to comment.