mirror of
https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
synced 2026-10-11 22:50:09 +00:00
228 lines
7.4 KiB
Python
228 lines
7.4 KiB
Python
# -*- coding: utf_8 -*-
|
|
# Module for Malware Analysis
|
|
import io
|
|
import logging
|
|
import re
|
|
from pathlib import Path
|
|
from socket import (
|
|
gaierror,
|
|
gethostbyname,
|
|
)
|
|
from urllib.parse import urlparse
|
|
|
|
from django.conf import settings
|
|
|
|
import IP2Location
|
|
|
|
from mobsf.MobSF.utils import (
|
|
is_internet_available,
|
|
update_local_db,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
IP2Loc = IP2Location.IP2Location()
|
|
|
|
|
|
class MalwareDomainCheck:
|
|
|
|
def __init__(self):
|
|
self.sig_dir = Path(settings.SIGNATURE_DIR)
|
|
self.malwaredomainlist = self.sig_dir / 'malwaredomainlist'
|
|
self.maltrail = self.sig_dir / 'maltrail-malware-domains.txt'
|
|
self.iplocbin = self.sig_dir / 'IP2LOCATION-LITE-DB5.IPV6.BIN'
|
|
self.result = {}
|
|
self.domainlist = None
|
|
|
|
def update_malware_db(self):
|
|
"""Check for update in malware DB."""
|
|
try:
|
|
mal_db = self.malwaredomainlist
|
|
resp = update_local_db('Malware', settings.MALWARE_DB_URL, mal_db)
|
|
if not resp:
|
|
return
|
|
# DB needs update
|
|
# Check2: DB Syntax Changed
|
|
line = resp.decode('utf-8', 'ignore').split('\n')[0]
|
|
lst = line.split('",')
|
|
if len(lst) == 10:
|
|
# DB Format is not changed. Let's update DB
|
|
logger.info('Updating Malware Database')
|
|
with open(mal_db, 'wb') as wfp:
|
|
wfp.write(resp)
|
|
else:
|
|
logger.warning('Unable to Update Malware DB')
|
|
except Exception:
|
|
logger.exception('[ERROR] Malware DB Update')
|
|
|
|
def update_maltrail_db(self):
|
|
"""Check for update in maltrail DB."""
|
|
try:
|
|
mal_db = self.maltrail
|
|
resp = update_local_db(
|
|
'Maltrail',
|
|
settings.MALTRAIL_DB_URL, mal_db)
|
|
if not resp:
|
|
return
|
|
# DB needs update
|
|
# Check2: DB Syntax Changed
|
|
lines = resp.decode('utf-8', 'ignore').splitlines()
|
|
if len(lines) > 100:
|
|
logger.info('Updating Maltrail Database')
|
|
with open(mal_db, 'wb') as wfp:
|
|
wfp.write(resp)
|
|
else:
|
|
logger.warning('Unable to Update Maltrail DB')
|
|
except Exception:
|
|
logger.exception('[ERROR] Maltrail DB Update')
|
|
|
|
def gelocation(self):
|
|
"""Perform Geolocation."""
|
|
try:
|
|
IP2Loc.open(self.iplocbin)
|
|
for domain in self.domainlist:
|
|
# Tag Good Domains
|
|
if domain not in self.result:
|
|
tmp_d = {}
|
|
tmp_d['bad'] = 'no'
|
|
self.result[domain] = tmp_d
|
|
# GeoIP
|
|
ip = None
|
|
try:
|
|
ip = gethostbyname(domain)
|
|
except (gaierror, UnicodeError):
|
|
pass
|
|
if ip:
|
|
rec = IP2Loc.get_all(ip)
|
|
self.result[domain]['geolocation'] = rec.__dict__
|
|
else:
|
|
self.result[domain]['geolocation'] = None
|
|
except Exception:
|
|
logger.exception('Failed to Perform Geolocation')
|
|
finally:
|
|
if IP2Loc:
|
|
IP2Loc.close()
|
|
|
|
def malware_check(self):
|
|
try:
|
|
mal_db = self.malwaredomainlist
|
|
with io.open(mal_db,
|
|
mode='r',
|
|
encoding='utf8',
|
|
errors='ignore') as flip:
|
|
entry_list = flip.readlines()
|
|
for entry in entry_list:
|
|
enlist = entry.split('","')
|
|
if len(enlist) > 5:
|
|
details_dict = {}
|
|
details_dict['domain_or_url'] = enlist[1]
|
|
details_dict['ip'] = enlist[2]
|
|
details_dict['desc'] = enlist[4]
|
|
details_dict['bad'] = 'yes'
|
|
dmn_url = details_dict['domain_or_url']
|
|
for domain in self.domainlist:
|
|
dmn_neturl = get_netloc(dmn_url)
|
|
if (((dmn_neturl == domain or dmn_neturl == domain[4:])
|
|
and (len(dmn_url) > 1))
|
|
or details_dict['ip'].startswith(domain)):
|
|
self.result[domain] = details_dict
|
|
except Exception:
|
|
logger.exception('[ERROR] Performing Malware Check')
|
|
|
|
def maltrail_check(self):
|
|
try:
|
|
mal_db = self.maltrail
|
|
with io.open(mal_db,
|
|
mode='r',
|
|
encoding='utf8',
|
|
errors='ignore') as flip:
|
|
entry_list = flip.read().splitlines()
|
|
for domain in self.domainlist:
|
|
if domain in entry_list:
|
|
self.result[domain] = {
|
|
'domain_or_url': domain,
|
|
'ip': 'N/A',
|
|
'desc': 'Malicious Domain tagged by Maltrail',
|
|
'bad': 'yes',
|
|
}
|
|
except Exception:
|
|
logger.exception('[ERROR] Performing Maltrail Check')
|
|
|
|
def update(self):
|
|
if is_internet_available():
|
|
self.update_malware_db()
|
|
self.update_maltrail_db()
|
|
else:
|
|
logger.warning('Internet not available. '
|
|
'Skipping Malware Database Update.')
|
|
|
|
def scan(self, urls):
|
|
if not settings.DOMAIN_MALWARE_SCAN:
|
|
logger.info('Domain Malware Check disabled in settings')
|
|
return self.result
|
|
self.domainlist = get_domains(urls)
|
|
if self.domainlist:
|
|
self.update()
|
|
self.malware_check()
|
|
self.maltrail_check()
|
|
self.gelocation()
|
|
return self.result
|
|
|
|
|
|
# Helper Functions
|
|
|
|
def verify_domain(checkeddom):
|
|
try:
|
|
if (len(checkeddom) > 2
|
|
and '.' in checkeddom
|
|
and (checkeddom.endswith('.') is False
|
|
and re.search('[a-zA-Z0-9]', checkeddom))):
|
|
return True
|
|
else:
|
|
return False
|
|
except Exception:
|
|
logger.exception('[ERROR] Verifying Domain')
|
|
|
|
|
|
def get_netloc(url):
|
|
"""Get Domain."""
|
|
try:
|
|
domain = ''
|
|
parse_uri = urlparse(url)
|
|
if not parse_uri.scheme:
|
|
url = '//' + url
|
|
parse_uri = urlparse(url)
|
|
domain = '{uri.netloc}'.format(uri=parse_uri)
|
|
if verify_domain(domain):
|
|
return domain
|
|
except Exception:
|
|
logger.exception('[ERROR] Extracting Domain form URL')
|
|
|
|
|
|
def sanitize_domain(domain):
|
|
"""Sanitize domain to be RFC1034 compliant."""
|
|
domain = domain.split('_')[0]
|
|
domain = re.sub(r'[^\w^\.^\-]', '', domain)
|
|
if domain.startswith('-'):
|
|
domain = sanitize_domain(domain[1:])
|
|
elif domain.endswith('-'):
|
|
domain = sanitize_domain(domain[:-1])
|
|
return domain
|
|
|
|
|
|
def get_domains(urls):
|
|
"""Get Domains."""
|
|
try:
|
|
domains = set()
|
|
for url in urls:
|
|
parse_uri = urlparse(url)
|
|
if not parse_uri.scheme:
|
|
url = '//' + url
|
|
parse_uri = urlparse(url)
|
|
domain = sanitize_domain(
|
|
'{uri.hostname}'.format(uri=parse_uri))
|
|
if verify_domain(domain):
|
|
domains.add(domain)
|
|
return domains
|
|
except Exception:
|
|
logger.exception('[ERROR] Extracting Domain form URL')
|