Skip to content
This repository was archived by the owner on Nov 2, 2024. It is now read-only.

Commit 5daf4ad

Browse files
g4zeg4ze
authored andcommitted
ailtyposquatting (intelowlproject#2341)
* ailtyposquatting * restore a file that was deleted * fix * fix * changes * tests * no files * logs * files * variables * test * test * enum * tests * tests * dns_resolve * migration * a log :p --------- Co-authored-by: g4ze <[email protected]>
1 parent 523a348 commit 5daf4ad

File tree

4 files changed

+220
-1
lines changed

4 files changed

+220
-1
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from django.db import migrations
2+
from django.db.models.fields.related_descriptors import (
3+
ForwardManyToOneDescriptor,
4+
ForwardOneToOneDescriptor,
5+
ManyToManyDescriptor,
6+
)
7+
8+
plugin = {
9+
"python_module": {
10+
"health_check_schedule": None,
11+
"update_schedule": None,
12+
"module": "ailtyposquatting.AilTypoSquatting",
13+
"base_path": "api_app.analyzers_manager.observable_analyzers",
14+
},
15+
"name": "AILTypoSquatting",
16+
"description": "[AILTypoSquatting](https://github.com/typosquatter/ail-typo-squatting) is a Python library to generate list of potential typo squatting domains with domain name permutation engine to feed AIL and other systems.",
17+
"disabled": False,
18+
"soft_time_limit": 60,
19+
"routing_key": "default",
20+
"health_check_status": True,
21+
"type": "observable",
22+
"docker_based": False,
23+
"maximum_tlp": "RED",
24+
"observable_supported": ["domain"],
25+
"supported_filetypes": [],
26+
"run_hash": False,
27+
"run_hash_type": "",
28+
"not_supported_filetypes": [],
29+
"model": "analyzers_manager.AnalyzerConfig",
30+
}
31+
32+
params = [
33+
{
34+
"python_module": {
35+
"module": "ailtyposquatting.AilTypoSquatting",
36+
"base_path": "api_app.analyzers_manager.observable_analyzers",
37+
},
38+
"name": "dns_resolving",
39+
"type": "bool",
40+
"description": "dns_resolving for AilTypoSquatting; only works for TLP CLEAR",
41+
"is_secret": False,
42+
"required": False,
43+
},
44+
]
45+
values = [
46+
{
47+
"parameter": {
48+
"python_module": {
49+
"module": "ailtyposquatting.AilTypoSquatting",
50+
"base_path": "api_app.analyzers_manager.observable_analyzers",
51+
},
52+
"name": "dns_resolving",
53+
"type": "bool",
54+
"description": "dns_resolving for AilTypoSquatting; only works for TLP CLEAR",
55+
"is_secret": False,
56+
"required": False,
57+
},
58+
"analyzer_config": "AILTypoSquatting",
59+
"connector_config": None,
60+
"visualizer_config": None,
61+
"ingestor_config": None,
62+
"pivot_config": None,
63+
"for_organization": False,
64+
"value": False,
65+
"updated_at": "2024-05-26T00:10:15.236358Z",
66+
"owner": None,
67+
},
68+
]
69+
70+
71+
def _get_real_obj(Model, field, value):
72+
def _get_obj(Model, other_model, value):
73+
if isinstance(value, dict):
74+
real_vals = {}
75+
for key, real_val in value.items():
76+
real_vals[key] = _get_real_obj(other_model, key, real_val)
77+
value = other_model.objects.get_or_create(**real_vals)[0]
78+
# it is just the primary key serialized
79+
else:
80+
if isinstance(value, int):
81+
if Model.__name__ == "PluginConfig":
82+
value = other_model.objects.get(name=plugin["name"])
83+
else:
84+
value = other_model.objects.get(pk=value)
85+
else:
86+
value = other_model.objects.get(name=value)
87+
return value
88+
89+
if (
90+
type(getattr(Model, field))
91+
in [ForwardManyToOneDescriptor, ForwardOneToOneDescriptor]
92+
and value
93+
):
94+
other_model = getattr(Model, field).get_queryset().model
95+
value = _get_obj(Model, other_model, value)
96+
elif type(getattr(Model, field)) in [ManyToManyDescriptor] and value:
97+
other_model = getattr(Model, field).rel.model
98+
value = [_get_obj(Model, other_model, val) for val in value]
99+
return value
100+
101+
102+
def _create_object(Model, data):
103+
mtm, no_mtm = {}, {}
104+
for field, value in data.items():
105+
value = _get_real_obj(Model, field, value)
106+
if type(getattr(Model, field)) is ManyToManyDescriptor:
107+
mtm[field] = value
108+
else:
109+
no_mtm[field] = value
110+
try:
111+
o = Model.objects.get(**no_mtm)
112+
except Model.DoesNotExist:
113+
o = Model(**no_mtm)
114+
o.full_clean()
115+
o.save()
116+
for field, value in mtm.items():
117+
attribute = getattr(o, field)
118+
if value is not None:
119+
attribute.set(value)
120+
return False
121+
return True
122+
123+
124+
def migrate(apps, schema_editor):
125+
Parameter = apps.get_model("api_app", "Parameter")
126+
PluginConfig = apps.get_model("api_app", "PluginConfig")
127+
python_path = plugin.pop("model")
128+
Model = apps.get_model(*python_path.split("."))
129+
if not Model.objects.filter(name=plugin["name"]).exists():
130+
exists = _create_object(Model, plugin)
131+
if not exists:
132+
for param in params:
133+
_create_object(Parameter, param)
134+
for value in values:
135+
_create_object(PluginConfig, value)
136+
137+
138+
def reverse_migrate(apps, schema_editor):
139+
python_path = plugin.pop("model")
140+
Model = apps.get_model(*python_path.split("."))
141+
Model.objects.get(name=plugin["name"]).delete()
142+
143+
144+
class Migration(migrations.Migration):
145+
atomic = False
146+
dependencies = [
147+
("api_app", "0062_alter_parameter_python_module"),
148+
("analyzers_manager", "0092_alter_validin_desc"),
149+
]
150+
151+
operations = [migrations.RunPython(migrate, reverse_migrate)]
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import logging
2+
import math
3+
4+
from ail_typo_squatting import typo
5+
from ail_typo_squatting.dns_local import resolving
6+
7+
from api_app.analyzers_manager import classes
8+
from tests.mock_utils import if_mock_connections, patch
9+
10+
logger = logging.getLogger(__name__)
11+
12+
13+
class AilTypoSquatting(classes.ObservableAnalyzer):
14+
"""
15+
wrapper for https://github.com/typosquatter/ail-typo-squatting
16+
"""
17+
18+
dns_resolving: bool = False
19+
20+
def update(self) -> bool:
21+
pass
22+
23+
def run(self):
24+
response = {}
25+
logger.info(
26+
f"""running AilTypoSquatting on {self.observable_name}
27+
with tlp {self._job.tlp}
28+
and dns resolving {self.dns_resolving}"""
29+
)
30+
31+
response["algorithms"] = typo.runAll(
32+
domain=self.observable_name,
33+
limit=math.inf,
34+
formatoutput="text",
35+
pathOutput=None,
36+
)
37+
if self._job.tlp == self._job.TLP.CLEAR.value and self.dns_resolving:
38+
# for "x.com", response["algorithms"][0]=".com"
39+
# which is not valid for look up
40+
if len(self.observable_name.split(".")[0]) == 1:
41+
logger.info(
42+
f"""running dns resolving on {self.observable_name}
43+
excluding {response['algorithms'][0]}"""
44+
)
45+
response["dnsResolving"] = resolving.dnsResolving(
46+
resultList=response["algorithms"][1:],
47+
domain=self.observable_name,
48+
pathOutput=None,
49+
)
50+
else:
51+
response["dnsResolving"] = resolving.dnsResolving(
52+
resultList=response["algorithms"],
53+
domain=self.observable_name,
54+
pathOutput=None,
55+
)
56+
57+
return response
58+
59+
@classmethod
60+
def _monkeypatch(cls):
61+
patches = [
62+
if_mock_connections(
63+
patch.object(typo, "runAll", return_value=None),
64+
patch.object(resolving, "dnsResolving", return_value=None),
65+
)
66+
]
67+
return super()._monkeypatch(patches=patches)

docs/source/Usage.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ The following is the list of the available analyzers you can run out-of-the-box.
256256
* `HudsonRock`: [Hudson Rock](https://cavalier.hudsonrock.com/docs) provides its clients the ability to query a database of over 27,541,128 computers which were compromised through global info-stealer campaigns performed by threat actors.
257257
* `CyCat`: [CyCat](https://cycat.org/) or the CYbersecurity Resource CATalogue aims at mapping and documenting, in a single formalism and catalogue available cybersecurity tools, rules, playbooks, processes and controls.
258258
* `Vulners`: [Vulners](vulners.com) is the most complete and the only fully correlated security intelligence database, which goes through constant updates and links 200+ data sources in a unified machine-readable format. It contains 8 mln+ entries, including CVEs, advisories, exploits, and IoCs — everything you need to stay abreast on the latest security threats.
259+
* `AILTypoSquatting`:[AILTypoSquatting](https://github.com/typosquatter/ail-typo-squatting) is a Python library to generate list of potential typo squatting domains with domain name permutation engine to feed AIL and other systems.
259260

260261
##### Generic analyzers (email, phone number, etc.; anything really)
261262

requirements/project-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ querycontacts==2.0.0
7878
blint==2.1.5
7979
hfinger==0.2.2
8080
permhash==0.1.4
81-
81+
ail_typo_squatting==2.7.4
8282
# this is required because XLMMacroDeobfuscator does not pin the following packages
8383
pyxlsb2==0.0.8
8484
xlrd2==1.3.4

0 commit comments

Comments
 (0)