Skip to content

Commit d0b5ea7

Browse files
authored
Merge pull request #3138 from intelowlproject/develop
v6.5.0
2 parents 6715f82 + 99ecd61 commit d0b5ea7

File tree

516 files changed

+18066
-9823
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

516 files changed

+18066
-9823
lines changed

.github/CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
[**Upgrade Guide**](https://intelowlproject.github.io/docs/IntelOwl/installation/#update-to-the-most-recent-version)
44

5+
## [v6.5.0](https://github.com/intelowlproject/IntelOwl/releases/tag/v6.5.0)
6+
Happy new year! :sparkler: And Happy Birthday IntelOwl! :tada:
7+
8+
We are celebrating the 6th IntelOwl Birthday! :sunglasses: WOW! Such a Milestone!
9+
10+
And we reached almost 4.5k stars! :star: Thank you for your support!
11+
12+
This release merges all the developments performed by our Google Summer of Code contributors for this year. You can read the related blogs for more info about:
13+
- [Akshit Maheshwary](https://x.com/Akshit20437406): [IntelOwl Improvements: Analyzers and Integrations](https://intelowlproject.github.io/blogs/gsoc_25_new_analyzers_and_integrations)
14+
- [Pranjal Gupta](https://github.com/pranjalg1331): [IntelOwl improvements: refactor analyzer tests](https://intelowlproject.github.io/blogs/gsoc25_refactor_analyzer_tests)
15+
16+
A special thanks to the new maintainer and GSoC mentor for the 2025: [Federico Gibertoni](https://github.com/fgibertoni).
17+
18+
The UI now supports a new page for the so called "Artifacts" or "Analyzables". They are a representation of an observable or a sample.
19+
Thanks to this new section, you can now store your evaluations for each observables/samples and make them count in your analyses results!
20+
Please take time to explore this new section in the GUI and provide feedback!
21+
[Docs reference](https://intelowlproject.github.io/docs/IntelOwl/usage/#analyzables-artifacts)
22+
23+
As usual, we add new plugins. This release brings the following new ones:
24+
* [Hunting Abuse.ch](https://hunting.abuse.ch/api/): new central API for Abuse.ch
25+
* [YaraX](https://virustotal.github.io/yara-x/docs/intro/getting-started/) integration: you can now run your Yara rules with the new engine written in Rust
26+
* Now [Floss](https://github.com/mandiant/flare-floss) and [Capa](https://github.com/mandiant/capa) are integrated directly in the main container so you don't need anymore to run the optional container `malware_tools_analyzers" for them.
27+
* [Phunter](https://github.com/N0rz3/Phunter) which requires the execution of a new optional container with `--phunter`.
28+
* [JoeSandbox](https://www.joesandbox.com/), a malware analysis tool.
29+
* "ExpandURL" which takes a shortened URL and provides us the actual expanded URL, along with full redirection chain.
30+
31+
We don't mention here all the other adjustments, fixes and dependencies upgrades. Please check the full changelog for that.
32+
533
## [v6.4.0](https://github.com/intelowlproject/IntelOwl/releases/tag/v6.4.0)
634
This release mostly provides important changes in the backend part that will be supported in the UI in the next releases.
735
* Analyzable: Representation of an observable or a sample: every job is linked to the scanned analyzable.

.github/pull_request_template.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ Please delete options that are not relevant.
2626
- [ ] Check if it could make sense to add that analyzer/connector to other [freely available playbooks](https://intelowlproject.github.io/docs/IntelOwl/usage/#list-of-pre-built-playbooks).
2727
- [ ] I have provided the resulting raw JSON of a finished analysis and a screenshot of the results.
2828
- [ ] If the plugin interacts with an external service, I have created an attribute called precisely `url` that contains this information. This is required for Health Checks (HEAD HTTP requests).
29-
- [ ] If the plugin requires mocked testing, `_monkeypatch()` was used in its class to apply the necessary decorators.
30-
- [ ] I have added that raw JSON sample to the `MockUpResponse` of the `_monkeypatch()` method. This serves us to provide a valid sample for testing.
29+
- [ ] If a new analyzer has beed added, I have created a unittest for it in the appropriate dir. I have also mocked all the external calls, so that no real calls are being made while testing.
30+
- [ ] I have added that raw JSON sample to the `get_mocker_response()` method of the unittest class. This serves us to provide a valid sample for testing.
3131
- [ ] I have created the corresponding `DataModel` for the new analyzer following the [documentation](https://intelowlproject.github.io/docs/IntelOwl/contribute/#how-to-create-a-datamodel)
3232
- [ ] I have inserted the copyright banner at the start of the file: ```# This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl # See the file 'LICENSE' for copying permission.```
3333
- [ ] Please avoid adding new libraries as requirements whenever it is possible. Use new libraries only if strictly needed to solve the issue you are working for. In case of doubt, ask a maintainer permission to use a specific library.

.github/workflows/codeql-analysis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
6666
# Initializes the CodeQL tools for scanning.
6767
- name: Initialize CodeQL
68-
uses: github/codeql-action/init@v3.28.0
68+
uses: github/codeql-action/init@v4.31.0
6969
with:
7070
languages: python
7171
# Override the default behavior so that the action doesn't attempt
@@ -93,4 +93,4 @@ jobs:
9393
# make release
9494

9595
- name: Perform CodeQL Analysis
96-
uses: github/codeql-action/analyze@v3.28.0
96+
uses: github/codeql-action/analyze@v4.31.0

.github/workflows/pull_request_automation.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ jobs:
115115
- name: Run test
116116
run: |
117117
docker exec intelowl_uwsgi coverage run manage.py test --keepdb tests
118+
- name: Run async tests
119+
run: |
120+
docker exec intelowl_uwsgi coverage run manage.py test --keepdb async_tests
118121
119122
frontend-tests:
120123
runs-on: ubuntu-latest
@@ -128,7 +131,7 @@ jobs:
128131
with:
129132
node-version: 18
130133
- name: Cache node modules
131-
uses: actions/cache@v4
134+
uses: actions/cache@v5
132135
with:
133136
path: ~/.npm
134137
key: npm-build-${{ hashFiles('frontend/package-lock.json') }}

.github/workflows/scorecard.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
6060
# format to the repository Actions tab.
6161
- name: "Upload artifact"
62-
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
62+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
6363
with:
6464
name: SARIF file
6565
path: results.sarif
@@ -68,6 +68,6 @@ jobs:
6868

6969
# Upload the results to GitHub's code scanning dashboard.
7070
- name: "Upload to code-scanning"
71-
uses: github/codeql-action/upload-sarif@5b6e617dc0241b2d60c2bccea90c56b67eceb797 # v2.22.11
71+
uses: github/codeql-action/upload-sarif@8d77149e0c9e2199ac9cfc90c9e15116f5c69c48 # v2.22.11
7272
with:
7373
sarif_file: results.sarif

README.md

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,19 @@ You can see the full list of all available analyzers in the [documentation](http
6464

6565
As open source project maintainers, we strongly rely on external support to get the resources and time to work on keeping the project alive, with a constant release of new features, bug fixes and general improvements.
6666

67-
Because of this, we joined [Open Collective](https://opencollective.com/intelowl-project) to obtain non-profit equal level status which allows the organization to receive and manage donations transparently. Please support IntelOwl and all the community by choosing a plan (BRONZE, SILVER, etc).
67+
Because of this, we joined [Open Collective](https://opencollective.com/intelowl-project) to obtain US and EU non-profit equal level status which allows the organization to receive and manage donations transparently and with tax exemption. Please support IntelOwl and all the community by choosing a plan (BRONZE, SILVER, etc).
6868

6969
<a href="https://opencollective.com/intelowl-project/donate" target="_blank">
7070
<img src="https://opencollective.com/intelowl-project/donate/button@2x.png?color=blue" width=200 />
7171
</a>
7272

73-
### 🥇 GOLD
74-
7573
#### Certego
7674

7775
<a href="https://certego.net/?utm_source=intelowl"> <img style="margin-right: 2px" width=250 height=71 src="static/Certego.png" alt="Certego Logo"/></a>
7876

7977
[Certego](https://certego.net/?utm_source=intelowl) is a MDR (Managed Detection and Response) and Threat Intelligence Provider based in Italy.
8078

81-
IntelOwl was born out of Certego's Threat intelligence R&D division and is constantly maintained and updated thanks to them.
79+
IntelOwl was born out of Certego's Threat intelligence R&D division and is mostly maintained and updated thanks to them.
8280

8381
#### The Honeynet Project
8482

@@ -96,16 +94,6 @@ Since its birth this project has been participating in the [Google Summer of Cod
9694
If you are interested in participating in the next Google Summer of Code, check all the info available in the [dedicated repository](https://github.com/intelowlproject/gsoc)!
9795

9896

99-
### 🥈 SILVER
100-
101-
#### ThreatHunter.ai
102-
103-
<a href="https://threathunter.ai?utm_source=intelowl"> <img style="border: 0.2px solid black" width=194 height=80 src="static/threathunter_logo.png" alt="ThreatHunter.ai logo"> </a>
104-
105-
[ThreatHunter.ai®](https://threathunter.ai?utm_source=intelowl), is a 100% Service-Disabled Veteran-Owned Small Business started in 2007 under the name Milton Security Group. ThreatHunter.ai is the global leader in Dynamic Threat Hunting. Operating a true 24x7x365 Security Operation Center with AI/ML-enhanced human Threat Hunters, ThreatHunter.ai has changed the industry in how threats are found, and mitigated in real time. For over 15 years, our teams of Threat Hunters have stopped hundreds of thousands of threats and assisted organizations in defending against threat actors around the clock.
106-
107-
### 🥉 BRONZE
108-
10997
#### Docker
11098

11199
In 2021 IntelOwl joined the official [Docker Open Source Program](https://www.docker.com/blog/expanded-support-for-open-source-software-projects/). This allows IntelOwl developers to easily manage Docker images and focus on writing the code. You may find the official IntelOwl Docker images [here](https://hub.docker.com/search?q=intelowlproject).
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import rest_framework_filters as filters
2+
from django_filters.widgets import QueryArrayWidget
3+
4+
from api_app.analyzables_manager.models import Analyzable
5+
6+
7+
class CharInFilter(filters.BaseInFilter, filters.CharFilter):
8+
pass
9+
10+
11+
class AnalyzableFilter(filters.FilterSet):
12+
name = CharInFilter(widget=QueryArrayWidget)
13+
14+
class Meta:
15+
model = Analyzable
16+
fields = {
17+
"discovery_date": ["lte", "gte"],
18+
}

api_app/analyzables_manager/models.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from typing import Type, Union
23

34
from django.core.exceptions import ValidationError
@@ -7,17 +8,14 @@
78

89
from api_app.analyzables_manager.queryset import AnalyzableQuerySet
910
from api_app.choices import Classification
10-
from api_app.data_model_manager.models import (
11-
BaseDataModel,
12-
DomainDataModel,
13-
FileDataModel,
14-
IPDataModel,
15-
)
11+
from api_app.data_model_manager.models import BaseDataModel
1612
from api_app.data_model_manager.queryset import BaseDataModelQuerySet
1713
from api_app.defaults import file_directory_path
1814
from api_app.helpers import calculate_md5, calculate_sha1, calculate_sha256
1915
from certego_saas.models import User
2016

17+
logger = logging.getLogger(__name__)
18+
2119

2220
class Analyzable(models.Model):
2321
name = models.CharField(max_length=255)
@@ -82,23 +80,11 @@ def get_all_user_events_data_model(
8280
).values_list("data_model__pk", flat=True)
8381
)
8482
query |= query2
83+
logger.debug(f"{query=}")
8584
return self.get_data_model_class().objects.filter(query)
8685

8786
def get_data_model_class(self) -> Type[BaseDataModel]:
88-
if self.classification == Classification.IP.value:
89-
return IPDataModel
90-
elif self.classification in [
91-
Classification.URL.value,
92-
Classification.DOMAIN.value,
93-
]:
94-
return DomainDataModel
95-
elif self.classification in [
96-
Classification.HASH.value,
97-
Classification.FILE.value,
98-
]:
99-
return FileDataModel
100-
else:
101-
raise NotImplementedError()
87+
return self.CLASSIFICATIONS.get_data_model_class(self.classification)
10288

10389
def _set_hashes(self, value: Union[str, bytes]):
10490
if isinstance(value, str):
@@ -111,6 +97,10 @@ def _set_hashes(self, value: Union[str, bytes]):
11197
self.sha1 = calculate_sha1(value)
11298

11399
def clean(self):
100+
if self.file:
101+
self.classification = Classification.FILE.value
102+
else:
103+
self.classification = Classification.calculate_observable(self.name)
114104
if self.classification == Classification.FILE.value:
115105
from api_app.analyzers_manager.models import MimeTypes
116106

api_app/analyzables_manager/queryset.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,21 @@ class AnalyzableQuerySet(QuerySet):
1010
def visible_for_user(self, user):
1111

1212
from api_app.models import Job
13+
from api_app.user_events_manager.models import UserAnalyzableEvent
1314

14-
analyzables = (
15+
analyzables_job = (
1516
Job.objects.visible_for_user(user)
1617
.values("analyzable")
1718
.distinct()
1819
.values_list("analyzable__pk", flat=True)
1920
)
20-
return self.filter(pk__in=analyzables)
21+
analyzables_ue = (
22+
UserAnalyzableEvent.objects.visible_for_user(user)
23+
.values("analyzable")
24+
.distinct()
25+
.values_list("analyzable__pk", flat=True)
26+
)
27+
return self.filter(pk__in=analyzables_job) | self.filter(pk__in=analyzables_ue)
2128

2229
def create(self, *args, **kwargs):
2330
obj = self.model(**kwargs)
Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,74 @@
1-
from rest_framework.serializers import ModelSerializer
1+
import logging
2+
3+
from rest_framework import serializers as rfs
24

35
from api_app.analyzables_manager.models import Analyzable
6+
from api_app.choices import Classification
7+
from api_app.models import Job
48
from api_app.serializers.job import JobRelatedField
59

10+
logger = logging.getLogger(__name__)
11+
612

7-
class AnalyzableSerializer(ModelSerializer):
13+
class AnalyzableSerializer(rfs.ModelSerializer):
814
jobs = JobRelatedField(many=True, read_only=True)
915

1016
class Meta:
1117
model = Analyzable
1218
fields = "__all__"
19+
read_only_fields = [
20+
"jobs",
21+
"discovery_date",
22+
"md5",
23+
"classification",
24+
"sha256",
25+
"sha1",
26+
"mimetype",
27+
]
28+
29+
def to_representation(self, instance):
30+
logger.debug(f"{instance=}")
31+
analyzable = super().to_representation(instance)
32+
job = (
33+
Job.objects.filter(id__in=analyzable["jobs"])
34+
.order_by("-finished_analysis_time")
35+
.first()
36+
)
37+
try:
38+
user_event_data_model = (
39+
instance.get_all_user_events_data_model().order_by("-date").first()
40+
)
41+
except NotImplementedError:
42+
user_event_data_model = None
43+
logger.debug(f"{job=}, {user_event_data_model=}")
44+
if not job and not user_event_data_model:
45+
analyzable["last_data_model"] = None
46+
logger.debug(f"no data {analyzable=}")
47+
return analyzable
48+
elif (job and job.data_model) or user_event_data_model:
49+
if not job or not job.data_model:
50+
last_data_model = user_event_data_model
51+
elif not user_event_data_model:
52+
last_data_model = job.data_model
53+
else:
54+
if (job and job.data_model) and (
55+
job.data_model.date > user_event_data_model.date
56+
):
57+
last_data_model = job.data_model
58+
else:
59+
last_data_model = user_event_data_model
60+
61+
try:
62+
serializer_class = Classification.get_data_model_class(
63+
classification=analyzable["classification"],
64+
).get_serializer()
65+
except NotImplementedError:
66+
pass
67+
else:
68+
analyzable["last_data_model"] = serializer_class(last_data_model).data
69+
logger.debug(f"before return {analyzable=}")
70+
return analyzable
71+
72+
def create(self, validated_data):
73+
instance, _ = self.Meta.model.objects.get_or_create(**validated_data)
74+
return instance

0 commit comments

Comments
 (0)