mirror of
https://github.com/ail-project/ail-framework.git
synced 2024-11-27 00:07:16 +00:00
Merge pull request #147 from ail-project/typo
Integration of the typo-squatting tracker
This commit is contained in:
commit
a597eece83
12 changed files with 242 additions and 29 deletions
|
@ -226,6 +226,8 @@ function launching_scripts {
|
||||||
##################################
|
##################################
|
||||||
# TRACKERS MODULES #
|
# TRACKERS MODULES #
|
||||||
##################################
|
##################################
|
||||||
|
screen -S "Script_AIL" -X screen -t "Tracker_Typo_Squatting" bash -c "cd ${AIL_BIN}/trackers; ${ENV_PY} ./Tracker_Typo_Squatting.py; read x"
|
||||||
|
sleep 0.1
|
||||||
screen -S "Script_AIL" -X screen -t "Tracker_Term" bash -c "cd ${AIL_BIN}/trackers; ${ENV_PY} ./Tracker_Term.py; read x"
|
screen -S "Script_AIL" -X screen -t "Tracker_Term" bash -c "cd ${AIL_BIN}/trackers; ${ENV_PY} ./Tracker_Term.py; read x"
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
screen -S "Script_AIL" -X screen -t "Tracker_Regex" bash -c "cd ${AIL_BIN}/trackers; ${ENV_PY} ./Tracker_Regex.py; read x"
|
screen -S "Script_AIL" -X screen -t "Tracker_Regex" bash -c "cd ${AIL_BIN}/trackers; ${ENV_PY} ./Tracker_Regex.py; read x"
|
||||||
|
|
|
@ -11,6 +11,9 @@ import yara
|
||||||
import datetime
|
import datetime
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
from ail_typo_squatting import runAll
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
from flask import escape
|
from flask import escape
|
||||||
|
|
||||||
|
@ -80,8 +83,8 @@ def get_all_tracker_type():
|
||||||
def get_all_tracker_uuid():
|
def get_all_tracker_uuid():
|
||||||
return r_serv_tracker.smembers(f'trackers:all')
|
return r_serv_tracker.smembers(f'trackers:all')
|
||||||
|
|
||||||
def get_all_tracker_by_type(tracker_type):
|
def get_all_tracker_uuid_by_type(tracker_type):
|
||||||
r_serv_tracker.smembers(f'trackers:all:{tracker_type}')
|
return r_serv_tracker.smembers(f'trackers:all:{tracker_type}')
|
||||||
|
|
||||||
# def get_all_tracker():
|
# def get_all_tracker():
|
||||||
# l_keys_name = []
|
# l_keys_name = []
|
||||||
|
@ -216,6 +219,20 @@ def get_tracker_items_by_daterange(tracker_uuid, date_from, date_to):
|
||||||
all_item_id |= r_serv_tracker.smembers(f'tracker:item:{tracker_uuid}:{date_day}')
|
all_item_id |= r_serv_tracker.smembers(f'tracker:item:{tracker_uuid}:{date_day}')
|
||||||
return all_item_id
|
return all_item_id
|
||||||
|
|
||||||
|
def get_tracker_typosquatting_domains(tracker_uuid):
|
||||||
|
return r_serv_tracker.smembers(f'tracker:typosquatting:{tracker_uuid}')
|
||||||
|
|
||||||
|
def get_typosquatting_tracked_words_list():
|
||||||
|
all_typo = dict()
|
||||||
|
typos_uuid = get_all_tracker_uuid_by_type("typosquatting")
|
||||||
|
|
||||||
|
for typo_uuid in typos_uuid:
|
||||||
|
tracker = get_tracker_by_uuid(typo_uuid)
|
||||||
|
all_typo[tracker] = get_tracker_typosquatting_domains(typo_uuid)
|
||||||
|
|
||||||
|
return all_typo
|
||||||
|
|
||||||
|
|
||||||
def add_tracked_item(tracker_uuid, item_id):
|
def add_tracked_item(tracker_uuid, item_id):
|
||||||
item_date = item_basic.get_item_date(item_id)
|
item_date = item_basic.get_item_date(item_id)
|
||||||
# track item
|
# track item
|
||||||
|
@ -409,6 +426,15 @@ def api_validate_tracker_to_add(tracker , tracker_type, nb_words=1):
|
||||||
|
|
||||||
tracker = ",".join(words_set)
|
tracker = ",".join(words_set)
|
||||||
tracker = "{};{}".format(tracker, nb_words)
|
tracker = "{};{}".format(tracker, nb_words)
|
||||||
|
elif tracker_type == 'typosquatting':
|
||||||
|
tracker = tracker.lower()
|
||||||
|
# Take only the first term
|
||||||
|
domain = tracker.split(" ")
|
||||||
|
if len(domain) > 1:
|
||||||
|
return {"status": "error", "reason": "Only one domain is accepted at a time"}, 400
|
||||||
|
if not "." in tracker:
|
||||||
|
return {"status": "error", "reason": "Invalid domain name"}, 400
|
||||||
|
|
||||||
|
|
||||||
elif tracker_type=='yara_custom':
|
elif tracker_type=='yara_custom':
|
||||||
if not is_valid_yara_rule(tracker):
|
if not is_valid_yara_rule(tracker):
|
||||||
|
@ -449,6 +475,12 @@ def create_tracker(tracker, tracker_type, user_id, level, tags, mails, descripti
|
||||||
tracker = save_yara_rule(tracker_type, tracker, tracker_uuid=tracker_uuid)
|
tracker = save_yara_rule(tracker_type, tracker, tracker_uuid=tracker_uuid)
|
||||||
tracker_type = 'yara'
|
tracker_type = 'yara'
|
||||||
|
|
||||||
|
elif tracker_type == 'typosquatting':
|
||||||
|
domain = tracker.split(" ")[0]
|
||||||
|
typo_generation = runAll(domain=domain, limit=math.inf, formatoutput="text", pathOutput="-", verbose=False)
|
||||||
|
for typo in typo_generation:
|
||||||
|
r_serv_tracker.sadd(f'tracker:typosquatting:{tracker_uuid}', typo)
|
||||||
|
|
||||||
# create metadata
|
# create metadata
|
||||||
r_serv_tracker.hset('tracker:{}'.format(tracker_uuid), 'tracked', tracker)
|
r_serv_tracker.hset('tracker:{}'.format(tracker_uuid), 'tracked', tracker)
|
||||||
r_serv_tracker.hset('tracker:{}'.format(tracker_uuid), 'type', tracker_type)
|
r_serv_tracker.hset('tracker:{}'.format(tracker_uuid), 'type', tracker_type)
|
||||||
|
|
|
@ -37,6 +37,10 @@ subscribe = Redis_D4_client
|
||||||
subscribe = Redis
|
subscribe = Redis
|
||||||
publish = Redis_Tags
|
publish = Redis_Tags
|
||||||
|
|
||||||
|
[Tracker_Typo_Squatting]
|
||||||
|
subscribe = Redis_Host
|
||||||
|
publish = Redis_Tags
|
||||||
|
|
||||||
[Tracker_Term]
|
[Tracker_Term]
|
||||||
subscribe = Redis_Global
|
subscribe = Redis_Global
|
||||||
publish = Redis_Tags
|
publish = Redis_Tags
|
||||||
|
|
116
bin/trackers/Tracker_Typo_Squatting.py
Normal file
116
bin/trackers/Tracker_Typo_Squatting.py
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*-coding:UTF-8 -*
|
||||||
|
"""
|
||||||
|
The Tracker_Typo_Squatting Module
|
||||||
|
===================
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# Import External packages
|
||||||
|
##################################
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
sys.path.append(os.environ['AIL_BIN'])
|
||||||
|
##################################
|
||||||
|
# Import Project packages
|
||||||
|
##################################
|
||||||
|
from modules.abstract_module import AbstractModule
|
||||||
|
import NotificationHelper
|
||||||
|
from packages.Item import Item
|
||||||
|
from packages import Term
|
||||||
|
from lib import Tracker
|
||||||
|
|
||||||
|
class Tracker_Typo_Squatting(AbstractModule):
|
||||||
|
mail_body_template = "AIL Framework,\nNew occurrence for tracked Typo: {}\nitem id: {}\nurl: {}{}"
|
||||||
|
|
||||||
|
"""
|
||||||
|
Tracker_Typo_Squatting module for AIL framework
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Tracker_Typo_Squatting, self).__init__()
|
||||||
|
|
||||||
|
self.pending_seconds = 5
|
||||||
|
|
||||||
|
self.full_item_url = self.process.config.get("Notifications", "ail_domain") + "/object/item?id="
|
||||||
|
|
||||||
|
# loads typosquatting
|
||||||
|
self.typosquat_tracked_words_list = Tracker.get_typosquatting_tracked_words_list()
|
||||||
|
self.last_refresh_typosquat = time.time()
|
||||||
|
|
||||||
|
self.redis_logger.info(f"Module: {self.module_name} Launched")
|
||||||
|
|
||||||
|
def compute(self, message):
|
||||||
|
# refresh Tracked typo
|
||||||
|
if self.last_refresh_typosquat < Term.get_tracked_term_last_updated_by_type('typosquatting'):
|
||||||
|
self.typosquat_tracked_words_list = Tracker.get_typosquatting_tracked_words_list()
|
||||||
|
self.last_refresh_typosquat = time.time()
|
||||||
|
self.redis_logger.debug('Tracked typosquatting refreshed')
|
||||||
|
print('Tracked typosquatting refreshed')
|
||||||
|
|
||||||
|
host, id = message.split()
|
||||||
|
item = Item(id)
|
||||||
|
|
||||||
|
# Cast message as Item
|
||||||
|
for key in self.typosquat_tracked_words_list.keys():
|
||||||
|
#print(key)
|
||||||
|
if host in self.typosquat_tracked_words_list[key]:
|
||||||
|
self.new_term_found(key, 'typosquatting', item)
|
||||||
|
|
||||||
|
def new_term_found(self, term, term_type, item):
|
||||||
|
uuid_list = Term.get_term_uuid_list(term, term_type)
|
||||||
|
|
||||||
|
item_id = item.get_id()
|
||||||
|
item_date = item.get_date()
|
||||||
|
item_source = item.get_source()
|
||||||
|
self.redis_logger.info(f'new tracked typo found: {term} in {item_id}')
|
||||||
|
print(f'new tracked typo found: {term} in {item_id}')
|
||||||
|
for term_uuid in uuid_list:
|
||||||
|
tracker_sources = Tracker.get_tracker_uuid_sources(term_uuid)
|
||||||
|
if not tracker_sources or item_source in tracker_sources:
|
||||||
|
Tracker.add_tracked_item(term_uuid, item_id)
|
||||||
|
|
||||||
|
tags_to_add = Term.get_term_tags(term_uuid)
|
||||||
|
for tag in tags_to_add:
|
||||||
|
msg = '{};{}'.format(tag, item_id)
|
||||||
|
self.send_message_to_queue(msg, 'Tags')
|
||||||
|
|
||||||
|
mail_to_notify = Term.get_term_mails(term_uuid)
|
||||||
|
if mail_to_notify:
|
||||||
|
mail_subject = Tracker.get_email_subject(term_uuid)
|
||||||
|
mail_body = Tracker_Typo_Squatting.mail_body_template.format(term, item_id, self.full_item_url, item_id)
|
||||||
|
for mail in mail_to_notify:
|
||||||
|
self.redis_logger.debug(f'Send Mail {mail_subject}')
|
||||||
|
print(f'S print(item_content)end Mail {mail_subject}')
|
||||||
|
NotificationHelper.sendEmailNotification(mail, mail_subject, mail_body)
|
||||||
|
|
||||||
|
# Webhook
|
||||||
|
webhook_to_post = Term.get_term_webhook(term_uuid)
|
||||||
|
if webhook_to_post:
|
||||||
|
json_request = {"trackerId": term_uuid,
|
||||||
|
"itemId": item_id,
|
||||||
|
"itemURL": self.full_item_url + item_id,
|
||||||
|
"term": term,
|
||||||
|
"itemSource": item_source,
|
||||||
|
"itemDate": item_date,
|
||||||
|
"tags": tags_to_add,
|
||||||
|
"emailNotification": f'{mail_to_notify}',
|
||||||
|
"trackerType": term_type
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
response = requests.post(webhook_to_post, json=json_request)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
self.redis_logger.error(f"Webhook request failed for {webhook_to_post}\nReason: {response.reason}")
|
||||||
|
except:
|
||||||
|
self.redis_logger.error(f"Webhook request failed for {webhook_to_post}\nReason: Something went wrong")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
module = Tracker_Typo_Squatting()
|
||||||
|
module.run()
|
|
@ -70,6 +70,8 @@ flask>=1.1.4
|
||||||
flask-login
|
flask-login
|
||||||
bcrypt>3.1.6
|
bcrypt>3.1.6
|
||||||
|
|
||||||
|
# Ail typo squatting
|
||||||
|
ail_typo_squatting
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
nose>=1.3.7
|
nose>=1.3.7
|
||||||
|
|
|
@ -85,6 +85,16 @@ def tracked_menu_yara():
|
||||||
global_term = Term.get_all_global_tracked_terms(filter_type=filter_type)
|
global_term = Term.get_all_global_tracked_terms(filter_type=filter_type)
|
||||||
return render_template("trackersManagement.html", user_term=user_term, global_term=global_term, bootstrap_label=bootstrap_label, filter_type=filter_type)
|
return render_template("trackersManagement.html", user_term=user_term, global_term=global_term, bootstrap_label=bootstrap_label, filter_type=filter_type)
|
||||||
|
|
||||||
|
@hunter.route("/trackers/typosquatting")
|
||||||
|
@login_required
|
||||||
|
@login_read_only
|
||||||
|
def tracked_menu_typosquatting():
|
||||||
|
filter_type = 'typosquatting'
|
||||||
|
user_id = current_user.get_id()
|
||||||
|
user_term = Term.get_all_user_tracked_terms(user_id, filter_type=filter_type)
|
||||||
|
global_term = Term.get_all_global_tracked_terms(filter_type=filter_type)
|
||||||
|
return render_template("trackersManagement.html", user_term=user_term, global_term=global_term, bootstrap_label=bootstrap_label, filter_type=filter_type)
|
||||||
|
|
||||||
|
|
||||||
@hunter.route("/tracker/add", methods=['GET', 'POST'])
|
@hunter.route("/tracker/add", methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -208,6 +218,13 @@ def show_tracker():
|
||||||
else:
|
else:
|
||||||
yara_rule_content = None
|
yara_rule_content = None
|
||||||
|
|
||||||
|
if tracker_metadata['type'] == 'typosquatting':
|
||||||
|
typo_squatting = list(Tracker.get_tracker_typosquatting_domains(tracker_uuid))
|
||||||
|
typo_squatting.sort()
|
||||||
|
else:
|
||||||
|
typo_squatting = None
|
||||||
|
|
||||||
|
|
||||||
if date_from:
|
if date_from:
|
||||||
res = Term.parse_get_tracker_term_item({'uuid': tracker_uuid, 'date_from': date_from, 'date_to': date_to}, user_id)
|
res = Term.parse_get_tracker_term_item({'uuid': tracker_uuid, 'date_from': date_from, 'date_to': date_to}, user_id)
|
||||||
if res[1] !=200:
|
if res[1] !=200:
|
||||||
|
@ -224,6 +241,7 @@ def show_tracker():
|
||||||
|
|
||||||
return render_template("showTracker.html", tracker_metadata=tracker_metadata,
|
return render_template("showTracker.html", tracker_metadata=tracker_metadata,
|
||||||
yara_rule_content=yara_rule_content,
|
yara_rule_content=yara_rule_content,
|
||||||
|
typo_squatting=typo_squatting,
|
||||||
bootstrap_label=bootstrap_label)
|
bootstrap_label=bootstrap_label)
|
||||||
|
|
||||||
@hunter.route("/tracker/update_tracker_description", methods=['POST'])
|
@hunter.route("/tracker/update_tracker_description", methods=['POST'])
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
<option value="set">Set</option>
|
<option value="set">Set</option>
|
||||||
<option value="regex">Regex</option>
|
<option value="regex">Regex</option>
|
||||||
<option value="yara">YARA rule</option>
|
<option value="yara">YARA rule</option>
|
||||||
|
<option value="typosquatting">Typo-squatting</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<p id="tracker_desc">Terms to track (space separated)</p>
|
<p id="tracker_desc">Terms to track (space separated)</p>
|
||||||
|
@ -199,6 +200,12 @@ $(document).ready(function(){
|
||||||
$("#tracker").hide();
|
$("#tracker").hide();
|
||||||
$("#nb_word").hide();
|
$("#nb_word").hide();
|
||||||
$("#yara_rule").show();
|
$("#yara_rule").show();
|
||||||
|
} else if (tracker_type=="typosquatting") {
|
||||||
|
$("#tracker_desc").text("Generation of variation for domain name. Only one domain name at a time.");
|
||||||
|
$("#tracker_desc").show();
|
||||||
|
$("#tracker").show();
|
||||||
|
$("#nb_word").hide();
|
||||||
|
$("#yara_rule").hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,25 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ tracker_metadata['type'] }}</td>
|
<td>{{ tracker_metadata['type'] }}</td>
|
||||||
|
{% if tracker_metadata['type'] == 'typosquatting' %}
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-primary" data-toggle="collapse" href="#collapseTypo" role="button" aria-expanded="false" aria-controls="collapseTypo">
|
||||||
|
{{ tracker_metadata['tracker'].split(",")[0] }}
|
||||||
|
</a>
|
||||||
|
<div class="collapse" id="collapseTypo">
|
||||||
|
<div class="card card-body">
|
||||||
|
{% if typo_squatting %}
|
||||||
|
{% for typo in typo_squatting %}
|
||||||
|
{{typo}}
|
||||||
|
<br/>
|
||||||
|
{% endfor %}
|
||||||
|
{%endif%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{% else %}
|
||||||
<td>{{ tracker_metadata['tracker'] }}</td>
|
<td>{{ tracker_metadata['tracker'] }}</td>
|
||||||
|
{% endif %}
|
||||||
<td>{{ tracker_metadata['date'][0:4] }}/{{ tracker_metadata['date'][4:6] }}/{{ tracker_metadata['date'][6:8] }}</td>
|
<td>{{ tracker_metadata['date'][0:4] }}/{{ tracker_metadata['date'][4:6] }}/{{ tracker_metadata['date'][6:8] }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if tracker_metadata['level'] == 0 %}
|
{% if tracker_metadata['level'] == 0 %}
|
||||||
|
|
|
@ -70,12 +70,16 @@
|
||||||
<span>
|
<span>
|
||||||
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||||
{% if dict_uuid['term'] %}
|
{% if dict_uuid['term'] %}
|
||||||
{% if dict_uuid['term']|length > 256 %}
|
{% if dict_uuid['term']|length > 2000 %}
|
||||||
{{ dict_uuid['term'][0:256] }}...
|
{{ dict_uuid['term'][0:50] }}...
|
||||||
|
{% else %}
|
||||||
|
{% if dict_uuid['term']|length > 100 %}
|
||||||
|
{{ dict_uuid['term'][0:100] }}...
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ dict_uuid['term'] }}
|
{{ dict_uuid['term'] }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
|
@ -135,12 +139,16 @@
|
||||||
<span>
|
<span>
|
||||||
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
<a target="_blank" href="{{ url_for('hunter.show_tracker') }}?uuid={{ dict_uuid['uuid'] }}">
|
||||||
{% if dict_uuid['term'] %}
|
{% if dict_uuid['term'] %}
|
||||||
{% if dict_uuid['term']|length > 256 %}
|
{% if dict_uuid['term']|length > 2000 %}
|
||||||
{{ dict_uuid['term'][0:256] }}...
|
{{ dict_uuid['term'][0:50] }}...
|
||||||
|
{% else %}
|
||||||
|
{% if dict_uuid['term']|length > 100 %}
|
||||||
|
{{ dict_uuid['term'][0:100] }}...
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ dict_uuid['term'] }}
|
{{ dict_uuid['term'] }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -42,6 +42,12 @@
|
||||||
<span class="bg-danger text-white font-weight-bold" style="font-size: 120%"> { </span>
|
<span class="bg-danger text-white font-weight-bold" style="font-size: 120%"> { </span>
|
||||||
<span> YARA</span>
|
<span> YARA</span>
|
||||||
</a>
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{url_for('hunter.tracked_menu_typosquatting')}}" id="nav_tracker_typosquatting">
|
||||||
|
<i class="fa fa-clone"></i>
|
||||||
|
<span>Typo-squatting</span>
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h5 class="d-flex text-muted w-100" id="nav_title_retro_hunt">
|
<h5 class="d-flex text-muted w-100" id="nav_title_retro_hunt">
|
||||||
|
|
Loading…
Reference in a new issue