Merge pull request #147 from ail-project/typo

Integration of the typo-squatting tracker
This commit is contained in:
Thirion Aurélien 2022-06-24 16:34:48 +02:00 committed by GitHub
commit a597eece83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 242 additions and 29 deletions

View file

@ -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"

View file

@ -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)

View file

@ -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

View 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()

View file

@ -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

View file

@ -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'])

View file

@ -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();
} }
}); });

View file

@ -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 %}

View file

@ -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>

View file

@ -42,6 +42,12 @@
<span class="bg-danger text-white font-weight-bold" style="font-size: 120%">&nbsp;{ </span> <span class="bg-danger text-white font-weight-bold" style="font-size: 120%">&nbsp;{ </span>
<span>&nbsp;YARA</span> <span>&nbsp;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">