Skip to content

Commit a976fcd

Browse files
authored
Merge pull request #190 from intelowlproject/develop
Unpacme + whoisxml API + checkdmarc analyzer + Fix VT2 + doc on xs:code
2 parents e1c453d + c476471 commit a976fcd

File tree

21 files changed

+365
-118
lines changed

21 files changed

+365
-118
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
### the COMPOSE_FILE variable each separated with ':'. If you are on windows, replace all ':' with ';'.
66
### Reference to Docker's official Docs: https://docs.docker.com/compose/reference/envvars/#compose_file#compose_file
77

8-
INTELOWL_TAG_VERSION=v1.6.1
8+
INTELOWL_TAG_VERSION=v1.7.0
99

1010
###### Default (Production) ######
1111

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
liberapay: intelowlproject
2+
custom: ["https://xscode.com/intelowlproject/IntelOwl"]

README.md

Lines changed: 29 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,53 @@
1-
![Intel Owl](static_intel/intel_owl.jpeg)
1+
<img src="static_intel/intel_owl.jpeg" width=500 height=200 alt="Intel Owl"/>
22

33
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/intelowlproject/IntelOwl.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/intelowlproject/IntelOwl/context:python)
44
[![CodeFactor](https://www.codefactor.io/repository/github/intelowlproject/intelowl/badge)](https://www.codefactor.io/repository/github/intelowlproject/intelowl)
55
[![Build Status](https://travis-ci.com/intelowlproject/IntelOwl.svg?branch=master)](https://travis-ci.org/intelowlproject/IntelOwl)
66
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
77

8-
# Intel Owl
8+
<img src="static_intel/xscode-banner.png" width=600 height=125 alt="Get Support"/><br/>
9+
_For urgent issues and priority support, visit [https://xscode.com/intelowlproject/IntelOwl](https://xscode.com/intelowlproject/IntelOwl)._
910

10-
Do you want to get **threat intelligence data** about a file, an IP or a domain?
11+
# Intel Owl
1112

12-
Do you want to get this kind of data from multiple sources at the same time using **a single API request**?
13+
Do you want to get **threat intelligence data** about a malware, an IP or a domain? Do you want to get this kind of data from multiple sources at the same time using **a single API request**?
1314

1415
You are in the right place!
1516

16-
This application is built to **scale out** and to **speed up the retrieval of threat info**.
17-
18-
It can be integrated easily in your stack of security tools to automate common jobs usually performed, for instance, by SOC analysts manually.
19-
20-
Intel Owl is composed of **analyzers** that can be run to retrieve data from external sources (like VirusTotal or AbuseIPDB) or to generate intel from internal analyzers (like Yara or Oletools)
21-
22-
This solution is for everyone who needs a single point to query for info about a specific file or observable (domain, IP, URL, hash).
17+
Intel Owl is an Open Source Intelligence, or OSINT solution to get threat intelligence data about a specific file, an IP or a domain from a single API at scale. It integrates a number of analyzers available online and is for everyone who needs a single point to query for info about a specific file or observable.
2318

24-
Main features:
19+
### Features
2520

26-
- full django-python application
27-
- easily and completely customizable, both the APIs and the analyzers
28-
- clone the project, set up the configuration and you are ready to run
29-
- Official frontend client: **[IntelOwl-ng](https://github.com/intelowlproject/IntelOwl-ng)** provides features such as dashboard, visualizations of analysis data, easy to use forms for requesting new analysis, etc.
21+
- Provides enrichment of threat intel for malware as well as observables (IP, Domain, URL and hash).
22+
- This application is built to **scale out** and to **speed up the retrieval of threat info**.
23+
- It can be integrated easily in your stack of security tools ([pyintelowl](https://github.com/intelowlproject/pyintelowl)) to automate common jobs usually performed, for instance, by SOC analysts manually.
24+
- Intel Owl is composed of **analyzers** that can be run to retrieve data from external sources (like VirusTotal or AbuseIPDB) or to generate intel from internal analyzers (like Yara or Oletools)
25+
- API written in Django and Python 3.7.
26+
- Inbuilt frontend client: **[IntelOwl-ng](https://github.com/intelowlproject/IntelOwl-ng)** provides features such as dashboard, visualizations of analysis data, easy to use forms for requesting new analysis, etc. [Live Demo](https://intelowlclient.firebaseapp.com/).
3027

31-
### Documentation
28+
## Documentation
3229

3330
[![Documentation Status](https://readthedocs.org/projects/intelowl/badge/?version=latest)](https://intelowl.readthedocs.io/en/latest/?badge=latest)
3431

35-
Documentation about IntelOwl installation, usage, contribution can be found at https://intelowl.readthedocs.io/.
36-
37-
### Blog posts
38-
39-
[Daily Swig Article](https://portswigger.net/daily-swig/intel-owl-osint-tool-automates-the-intel-gathering-process-using-a-single-api)
40-
41-
[Honeynet Blog: v1.0.0 Announcement](https://www.honeynet.org/?p=7558)
42-
43-
[Certego Blog: First announcement](https://www.certego.net/en/news/new-year-new-tool-intel-owl/)
44-
45-
### Free Internal Modules Available
32+
Documentation about IntelOwl installation, usage, configuration and contribution can be found at https://intelowl.readthedocs.io/.
4633

47-
- Static Document Analysis
48-
- Static RTF Analysis
49-
- Static PDF Analysis
50-
- Static PE Analysis
51-
- Static Generic File Analysis
52-
- Strings analysis with ML
53-
- PE Emulation with Speakeasy
54-
- PE Signature verification
55-
- PE Capabilities Extraction
56-
- Emulated Javascript Analysis
57-
- Android Malware Analysis
34+
## Blog posts
5835

59-
**Free modules that require additional configuration**:
36+
To know more about the project and it's growth over time, you may be interested in reading the following:
6037

61-
- Cuckoo (requires at least one working Cuckoo instance)
62-
- MISP (requires at least one working MISP instance)
63-
- Yara (Community, Neo23x0, Intezer and McAfee rules are already available. There's the chance to add your own rules)
38+
- [Intel Owl on Daily Swig](https://portswigger.net/daily-swig/intel-owl-osint-tool-automates-the-intel-gathering-process-using-a-single-api)
39+
- [Honeynet: v1.0.0 Announcement](https://www.honeynet.org/?p=7558)
40+
- [Certego Blog: First announcement](https://www.certego.net/en/news/new-year-new-tool-intel-owl/)
6441

65-
### External Services Available
42+
## Available services or analyzers
6643

67-
##### required paid or trial API key
44+
You can see the full list of all available analyzers, [here](https://intelowl.readthedocs.io/en/latest/Usage.html#available-analyzers).
6845

69-
- GreyNoise v2
46+
| Inbuilt modules | External Services | Free modules that require additional configuration |
47+
|- |- |- |
48+
| - Static Document, RTF, PDF, PE, Generic File Analysis<br>- Strings analysis with ML<br>- PE Emulation with Speakeasy<br>- PE Signature verification<br>- PE Capabilities Extraction<br>- Emulated Javascript Analysis<br>- Android Malware Analysis<br>- SPF and DMARC Validator<br>- more... | - GreyNoise v2<br>- Intezer Scan<br>- VirusTotal v2+v3<br>- HybridAnalysis<br>- Censys.io<br>- Shodan<br>- AlienVault OTX<br>- Threatminer<br>- Abuse.ch<br>- many more.. | - Cuckoo (requires at least one working Cuckoo instance)<br>- MISP (requires at least one working MISP instance)<br>- Yara (Community, Neo23x0, Intezer and McAfee rules are already available. There's the chance to add your own rules) |
7049

71-
##### required paid or free API key
72-
73-
- VirusTotal v2 + v3
74-
- HybridAnalysis
75-
- Intezer
76-
- Farsight DNSDB
77-
- Hunter.io - Email Hunting
78-
- ONYPHE
79-
- Censys.io
80-
- SecurityTrails
81-
- Intelligence X
82-
- Pulsedive API (works w/o API key as well)
83-
84-
##### required free API key
85-
86-
- GoogleSafeBrowsing
87-
- AbuseIPDB
88-
- Shodan
89-
- HoneyDB
90-
- AlienVault OTX
91-
- MaxMind
92-
- Auth0
93-
94-
##### needed access request
95-
96-
- CIRCL PassiveDNS + PassiveSSL
97-
98-
##### without api key
99-
100-
- Fortiguard URL Analyzer
101-
- GreyNoise Alpha API v1
102-
- Talos Reputation
103-
- Tor Project
104-
- Robtex
105-
- Threatminer
106-
- Abuse.ch MalwareBazaar
107-
- Abuse.ch URLhaus
108-
- Team Cymru Malware Hash Registry
109-
- Tranco Rank
110-
- Google DoH
111-
- CloudFlare DoH Classic
112-
- CloudFlare DoH Malware
113-
- Classic DNS resolution
114-
115-
### Legal notice
50+
## Legal notice
11651

11752
You as a user of this project must review, accept and comply with the license
11853
terms of each downloaded/installed package listed below. By proceeding with the
@@ -142,21 +77,20 @@ license terms.
14277
[Quark-Engine](https://github.com/quark-engine/quark-engine)
14378
[IntelX](https://intelx.io/terms-of-service)
14479

145-
### Acknowledgments
80+
## Acknowledgments
14681

14782
This project was created and will be upgraded thanks to the following organizations:
14883

14984
<img style="margin-right: 2px" src="static_intel/Certego.png" alt="Certego Logo"/>
15085
<img style="border: 0.2px solid black" src="static_intel/logo-thp-100.png" alt="Honeynet.org logo">
15186

152-
153-
### Google Summer Of Code
87+
#### Google Summer Of Code
15488

15589
The project was accepted to the GSoC 2020 under the Honeynet Project!! A lot of [new features](https://www.honeynet.org/gsoc/gsoc-2020/google-summer-of-code-2020-project-ideas/#intel-owl-improvements) were developed by Eshaan Bansal ([Twitter](https://twitter.com/mask0fmydisguis)).
15690

15791
Stay tuned for the upcoming GSoC 2021! Join the [Honeynet Slack chat](https://gsoc-slack.honeynet.org/) for more info.
15892

159-
### About the author and maintainers
93+
## About the author and maintainers
16094

16195
Feel free to contact the main developers at any time:
16296
- Matteo Lodi ([Twitter](https://twitter.com/matte_lodi)): Author and creator
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import requests
2+
import logging
3+
from api_app.script_analyzers.classes import FileAnalyzer
4+
from api_app.exceptions import AnalyzerRunException
5+
import time
6+
from intel_owl import secrets
7+
from typing import Dict
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class UnpacMe(FileAnalyzer):
13+
base_url: str = "https://api.unpac.me/api/v1/"
14+
15+
def set_config(self, additional_config_params):
16+
self.api_key_name = additional_config_params.get(
17+
"api_key_name", "UNPAC_ME_API_KEY"
18+
)
19+
private = additional_config_params.get("private", False)
20+
self.private = "private" if private else "public"
21+
self.__api_key = secrets.get_secret(self.api_key_name)
22+
# max no. of tries when polling for result
23+
self.max_tries = additional_config_params.get("max_tries", 30)
24+
# interval b/w HTTP requests when polling
25+
self.poll_distance = 5
26+
27+
def run(self):
28+
if not self.__api_key:
29+
raise AnalyzerRunException(
30+
f"No API key retrieved with name: {self.api_key_name}"
31+
)
32+
self.headers = {"Authorization": "Key %s" % self.__api_key}
33+
unpac_id = self._upload()
34+
logger.info(f"md5 {self.md5} job {self.job_id} uploaded id {unpac_id}")
35+
for chance in range(self.max_tries):
36+
time.sleep(self.poll_distance)
37+
logger.info(
38+
f"unpacme polling, try n.{chance + 1}."
39+
f" job_id {self.job_id}. starting the query"
40+
)
41+
status = self._get_status(unpac_id)
42+
if status == "fail":
43+
logger.error(f"md5 {self.md5} job {self.job_id} analysis has failed")
44+
raise AnalyzerRunException("failed analysis")
45+
if status != "complete":
46+
logger.info(
47+
f"md5 {self.md5} job {self.job_id} id {unpac_id} status {status}"
48+
)
49+
continue
50+
return self._get_report(unpac_id)
51+
52+
def _req_with_checks(self, url, files=None, post=False):
53+
try:
54+
if post:
55+
r = requests.post(
56+
self.base_url + url, files=files, headers=self.headers
57+
)
58+
else:
59+
headers = self.headers if self.private == "private" else {}
60+
r = requests.get(self.base_url + url, files=files, headers=headers)
61+
r.raise_for_status()
62+
except requests.exceptions.HTTPError as e:
63+
logger.error(
64+
f"md5 {self.md5} job {self.job_id} url {url} has http error {str(e)}"
65+
)
66+
if post:
67+
raise AnalyzerRunException("Monthly quota exceeded!")
68+
raise AnalyzerRunException(e)
69+
except requests.exceptions.Timeout as e:
70+
logger.error(
71+
f"md5 {self.md5} job {self.job_id} url {url} has timeout error {str(e)}"
72+
)
73+
raise AnalyzerRunException(e)
74+
except requests.exceptions.RequestException as e:
75+
logger.error(
76+
f"md5 {self.md5} job {self.job_id} url {url} failed with error {str(e)}"
77+
)
78+
raise AnalyzerRunException(e)
79+
return r
80+
81+
def _upload(self) -> str:
82+
with open(self.filepath, "rb") as f:
83+
file_data = f.read()
84+
files = {"file": (self.filename, file_data)}
85+
r = self._req_with_checks("private/upload", files=files, post=True)
86+
response = r.json()
87+
if "id" not in response:
88+
raise AnalyzerRunException(
89+
f"md5 {self.md5} job {self.job_id} function upload id not in response"
90+
)
91+
return response["id"]
92+
93+
def _get_status(self, unpac_me_id) -> str:
94+
response = self._req_with_checks(f"{self.private}/status/{unpac_me_id}")
95+
return response.json().get("status", False)
96+
97+
def _get_report(self, unpac_me_id) -> Dict:
98+
response = self._req_with_checks(f"{self.private}/results/{unpac_me_id}")
99+
return response.json()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import subprocess
2+
import json
3+
from shutil import which
4+
5+
from api_app.script_analyzers import classes
6+
from api_app.exceptions import AnalyzerRunException
7+
8+
9+
class CheckDMARC(classes.ObservableAnalyzer):
10+
check_command: str = "checkdmarc"
11+
12+
def run(self):
13+
if not which(self.check_command):
14+
self.report["success"] = False
15+
raise AnalyzerRunException("checkdmarc not installed!")
16+
17+
process = subprocess.Popen(
18+
[self.check_command, self.observable_name],
19+
stdout=subprocess.PIPE,
20+
stderr=subprocess.PIPE,
21+
)
22+
process.wait()
23+
stdout, stderr = process.communicate()
24+
25+
dmarc_info = stdout.decode("utf-8"), stderr
26+
27+
dmarc_str = dmarc_info[0]
28+
29+
dmarc_json = json.loads(dmarc_str)
30+
31+
return dmarc_json

api_app/script_analyzers/observable_analyzers/cymru.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@ def run(self):
2020
# reference: https://team-cymru.com/community-services/mhr/
2121
# if the resolution works, this means that the file is reported
2222
# as malware by Cymru
23-
resolutions = []
23+
domains = None
2424
try:
2525
query_to_perform = f"{self.observable_name}.malware.hash.cymru.com"
2626
domains = socket.gethostbyaddr(query_to_perform)
27-
resolutions = domains[2]
2827
except (socket.gaierror, socket.herror):
2928
logger.info(f"observable {self.observable_name} not found in HMR DB")
30-
if resolutions:
29+
if domains:
3130
results["found"] = True
32-
results["resolution_data"] = resolutions
31+
results["resolution_data"] = domains[2]
3332

3433
return results

api_app/script_analyzers/observable_analyzers/talos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def run(self):
3232
def updater():
3333
try:
3434
logger.info("starting download of db from talos")
35-
url = "https://www.talosintelligence.com/documents/ip-blacklist"
35+
url = "https://snort.org/downloads/ip-block-list"
3636
r = requests.get(url)
3737
r.raise_for_status()
3838

api_app/script_analyzers/observable_analyzers/vt2_get.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,43 @@ def run(self):
1818
f"No API key retrieved with name: {self.api_key_name}"
1919
)
2020

21-
return vt_get_report(
21+
resp = vt_get_report(
2222
self.__api_key, self.observable_name, self.observable_classification
2323
)
2424

25+
resp_code = resp.get("response_code", 1)
26+
verbose_msg = resp.get("verbose_msg", "")
27+
if resp_code == -1 or "Invalid resource" in verbose_msg:
28+
self.report["errors"].append(verbose_msg)
29+
raise AnalyzerRunException(f"response code {resp_code}. response: {resp}")
30+
return resp
2531

26-
def vt_get_report(api_key, observable_name, observable_classification):
32+
33+
def vt_get_report(api_key, observable_name, obs_clsfn):
2734
params = {"apikey": api_key}
28-
if observable_classification == "domain":
35+
if obs_clsfn == "domain":
2936
params["domain"] = observable_name
3037
uri = "domain/report"
31-
elif observable_classification == "ip":
38+
elif obs_clsfn == "ip":
3239
params["ip"] = observable_name
3340
uri = "ip-address/report"
34-
elif observable_classification == "url":
41+
elif obs_clsfn == "url":
3542
params["resource"] = observable_name
3643
uri = "url/report"
37-
elif observable_classification == "hash":
44+
elif obs_clsfn == "hash":
3845
params["resource"] = observable_name
3946
params["allinfo"] = 1
4047
uri = "file/report"
4148
else:
4249
raise AnalyzerRunException(
43-
"not supported observable type {}. Supported are: hash, ip, domain and url"
44-
"".format(observable_classification)
50+
f"not supported observable type {obs_clsfn}. "
51+
"Supported are: hash, ip, domain and url."
4552
)
4653

4754
try:
4855
response = requests.get(vt_base + uri, params=params)
4956
response.raise_for_status()
5057
except requests.RequestException as e:
5158
raise AnalyzerRunException(e)
52-
result = response.json()
53-
response_code = result.get("response_code", 1)
54-
if response_code == -1:
55-
raise AnalyzerRunException(f"response code -1. result:{result}")
56-
return result
59+
60+
return response.json()

0 commit comments

Comments
 (0)