Skip to content

Commit a4e967c

Browse files
authored
Merge pull request #464 from intelowlproject/develop
1.5.0
2 parents f9019b9 + e385f12 commit a4e967c

30 files changed

+1220
-40
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ docker/env_file
44
docker/env_file_postgres
55
.env
66
__pycache__/
7+
mlmodels/
78
# JetBrains IDEs (PyCharm, IntelliJ, etc.)
8-
.idea/
9+
.idea/

api/views/utils.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,10 @@ def feeds_response(iocs, feed_params, valid_feed_types, dict_only=False, verbose
254254

255255
if verbose and ioc_feed_type in ["log4j", "cowrie"]:
256256
data_["honeypots"] = [hp for hp in data_["honeypots"] if hp is not None]
257-
data_["honeypots"].append(ioc_feed_type)
257+
if ioc["log4j"]:
258+
data_["honeypots"].append("log4j")
259+
if ioc["cowrie"]:
260+
data_["honeypots"].append("cowrie")
258261

259262
if verbose:
260263
json_list.append(data_)

docker/.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
REACT_APP_GREEDYBEAR_VERSION="1.4.4"
1+
REACT_APP_GREEDYBEAR_VERSION="1.5.0"

docker/Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ RUN touch ${LOG_PATH}/django/api.log ${LOG_PATH}/django/api_errors.log \
4242
&& touch ${LOG_PATH}/django/celery.log ${LOG_PATH}/django/celery_errors.log \
4343
&& touch ${LOG_PATH}/django/django_errors.log ${LOG_PATH}/django/elasticsearch.log\
4444
&& touch ${LOG_PATH}/django/authentication.log ${LOG_PATH}/django/authentication_errors.log \
45+
&& mkdir -p ${PYTHONPATH}/mlmodels \
4546
&& adduser -S -H -u 2000 -D -g www-data www-data \
46-
&& chown -R www-data:www-data ${LOG_PATH} /opt/deploy/ \
47+
&& chown -R www-data:www-data ${LOG_PATH} /opt/deploy/ ${PYTHONPATH}/mlmodels/ \
4748
&& rm -rf docs/ frontend/ tests/ .github/ docker/hooks/ \
4849
&& /bin/bash ./docker/watchman_install.sh \
4950
&& apk del gcc python3-dev alpine-sdk linux-headers

docker/Dockerfile_nginx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM library/nginx:1.27.3-alpine
1+
FROM library/nginx:1.27.4-alpine
22
RUN mkdir -p /var/cache/nginx /var/cache/nginx/feeds
33
RUN apk update && apk upgrade && apk add bash
44
ENV NGINX_LOG_DIR=/var/log/nginx

docker/default.yml

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ services:
7676
command: /usr/local/bin/celery -A greedybear.celery worker -n worker_default --uid www-data --gid www-data --time-limit=10000 --pidfile= -Ofair -Q default -E -c 1
7777
volumes:
7878
- generic_logs:/var/log/greedybear
79+
- mlmodels:/opt/deploy/greedybear/mlmodels
7980
env_file:
8081
- env_file
8182
depends_on:
@@ -90,3 +91,4 @@ volumes:
9091
nginx_logs:
9192
generic_logs:
9293
static_content:
94+
mlmodels:

frontend/src/components/auth/Login.jsx

+19-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import {
77
Spinner,
88
Button,
99
Row,
10+
Alert,
1011
} from "reactstrap";
12+
import { MdInfoOutline } from "react-icons/md";
1113
import { Form, Formik } from "formik";
1214

1315
import { ContentSection } from "@certego/certego-ui";
1416

1517
import { useAuthStore } from "../../stores";
1618
import {
17-
ResendVerificationEmailButton,
19+
// ResendVerificationEmailButton,
1820
ForgotPasswordButton,
1921
} from "./utils/registration-buttons";
2022

@@ -66,6 +68,20 @@ function Login() {
6668
<ContentSection>
6769
<h3 className="fw-bold">Log In</h3>
6870
<hr />
71+
<Alert
72+
color="accent-2"
73+
id="access-info"
74+
className="col-12 px-1 text-center"
75+
>
76+
<h5 className="text-info">
77+
<MdInfoOutline size="1.15rem" />
78+
&nbsp;New users
79+
</h5>
80+
<p>
81+
If you do not have an account please contact a member of The
82+
Honeynet Project who will provide you with credentials to log in
83+
</p>
84+
</Alert>
6985
{/* Form */}
7086
<Formik
7187
initialValues={initialValues}
@@ -126,7 +142,8 @@ function Login() {
126142
{/* popover buttons */}
127143
<Row className="d-flex flex-column align-items-end g-0">
128144
<ForgotPasswordButton />
129-
<ResendVerificationEmailButton />
145+
{/* Registration operations have been temporarily disabled due to not proper Terms of Service */}
146+
{/* <ResendVerificationEmailButton /> */}
130147
</Row>
131148
</Container>
132149
</ContentSection>

frontend/src/components/auth/Register.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ const onValidate = (values) => {
145145

146146
// Component
147147
export default function Register() {
148+
/* ATTENTION! The Register page has been temporarily disabled due to not proper Terms of Service */
148149
console.debug("Register rendered!");
149150

150151
// page title

frontend/src/layouts/AppHeader.jsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ const guestLinks = (
3030
Login
3131
</RRNavLink>
3232
</NavItem>
33-
<NavItem className="ms-lg-2">
33+
{/* The register button has been temporarily disabled due to not proper Terms of Service */}
34+
{/* <NavItem className="ms-lg-2">
3435
<RRNavLink
3536
id="register-btn"
3637
className="btn btn-sm btn-accent-2"
@@ -39,7 +40,7 @@ const guestLinks = (
3940
>
4041
Register
4142
</RRNavLink>
42-
</NavItem>
43+
</NavItem> */}
4344
</>
4445
);
4546

greedybear/admin.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ class IOCModelAdmin(admin.ModelAdmin):
4444
"destination_ports",
4545
"login_attempts",
4646
]
47-
search_fields = ["name"]
48-
filter_horizontal = ["general_honeypot", "related_ioc"]
47+
search_fields = ["name", "related_ioc__name"]
48+
raw_id_fields = ["related_ioc"]
49+
filter_horizontal = ["general_honeypot"]
4950

5051
def general_honeypots(self, ioc):
5152
return ", ".join([str(element) for element in ioc.general_honeypot.all()])

greedybear/celery.py

+11
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,15 @@ def setup_loggers(*args, **kwargs):
9595
"schedule": crontab(minute=33),
9696
"options": {"queue": "default"},
9797
},
98+
# SCORING
99+
# Important:
100+
# The training task must be run with a small offset after midnight (00:00)
101+
# to ensure training data aligns with complete calendar days.
102+
# The small offset is to make sure that the midnight extraction task is completed before training.
103+
# This way models learn from complete rather than partial day patterns, which is crucial for their performance.
104+
"train_and_update": {
105+
"task": "greedybear.tasks.chain_train_and_update",
106+
"schedule": crontab(hour=0, minute=hp_extraction_interval // 2),
107+
"options": {"queue": "default"},
108+
},
98109
}

greedybear/cronjobs/attacks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
from ipaddress import IPv4Address
77

88
from greedybear.consts import DOMAIN, IP, PAYLOAD_REQUEST, SCANNER
9-
from greedybear.cronjobs.base import Cronjob
9+
from greedybear.cronjobs.base import ElasticJob
1010
from greedybear.cronjobs.sensors import ExtractSensors
1111
from greedybear.models import IOC, GeneralHoneypot, Sensors
1212
from greedybear.settings import EXTRACTION_INTERVAL, LEGACY_EXTRACTION
1313

1414

15-
class ExtractAttacks(Cronjob, metaclass=ABCMeta):
15+
class ExtractAttacks(ElasticJob, metaclass=ABCMeta):
1616
def __init__(self, minutes_back=None):
1717
super().__init__()
1818
self.first_time_run = False

greedybear/cronjobs/base.py

+22-17
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,33 @@
1010

1111

1212
class Cronjob(metaclass=ABCMeta):
13+
def __init__(self):
14+
self.log = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
15+
self.success = False
16+
17+
@abstractmethod
18+
def run(self):
19+
pass
20+
21+
def execute(self):
22+
try:
23+
self.log.info("Starting execution")
24+
self.run()
25+
except Exception as e:
26+
self.log.exception(e)
27+
else:
28+
self.success = True
29+
finally:
30+
self.log.info("Finished execution")
31+
32+
33+
class ElasticJob(Cronjob):
1334
class ElasticServerDownException(Exception):
1435
pass
1536

1637
def __init__(self):
17-
self.log = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
38+
super().__init__()
1839
self.elastic_client = settings.ELASTIC_CLIENT
19-
self.success = False
2040

2141
def _healthcheck(self):
2242
if not self.elastic_client.ping():
@@ -58,21 +78,6 @@ def _base_search(self, honeypot):
5878
def minutes_back_to_lookup(self):
5979
pass
6080

61-
@abstractmethod
62-
def run(self):
63-
pass
64-
65-
def execute(self):
66-
try:
67-
self.log.info("Starting execution")
68-
self.run()
69-
except Exception as e:
70-
self.log.exception(e)
71-
else:
72-
self.success = True
73-
finally:
74-
self.log.info("Finished execution")
75-
7681

7782
def get_time_window(reference_time: datetime, lookback_minutes: int = EXTRACTION_INTERVAL) -> tuple[datetime, datetime]:
7883
"""

greedybear/cronjobs/cowrie.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ def _get_sessions(self, ioc):
111111
session_record.start_time = hit.timestamp
112112
case "cowrie.login.failed" | "cowrie.login.success":
113113
session_record.login_attempt = True
114-
session_record.credentials.append(f"{hit.username} | {hit.password}")
114+
username = hit.username.replace("\x00", "[NUL]")
115+
password = hit.password.replace("\x00", "[NUL]")
116+
session_record.credentials.append(f"{username} | {password}")
115117
session_record.source.login_attempts += 1
116118
case "cowrie.command.input":
117119
session_record.command_execution = True

greedybear/cronjobs/monitor_honeypots.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# This file is a part of GreedyBear https://github.com/honeynet/GreedyBear
22
# See the file 'LICENSE' for copying permission.
3-
from greedybear.cronjobs.base import Cronjob
3+
from greedybear.cronjobs.base import ElasticJob
44
from greedybear.cronjobs.honeypots import Honeypot
55
from greedybear.models import GeneralHoneypot
66

77

8-
class MonitorHoneypots(Cronjob):
8+
class MonitorHoneypots(ElasticJob):
99
def __init__(self):
1010
super(MonitorHoneypots, self).__init__()
1111
self.honeypots_to_monitor = [Honeypot("Log4pot"), Honeypot("Cowrie")]

greedybear/cronjobs/monitor_logs.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from datetime import datetime, timedelta
44
from os.path import getmtime
55

6-
from greedybear.cronjobs.base import Cronjob
6+
from greedybear.cronjobs.base import ElasticJob
77
from greedybear.slack import send_message
88

99

10-
class MonitorLogs(Cronjob):
10+
class MonitorLogs(ElasticJob):
1111
def __init__(self):
1212
super(MonitorLogs, self).__init__()
1313
self.logs_to_monitor = ["greedybear", "api", "django", "celery"]

greedybear/cronjobs/scoring/consts.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
NUM_FEATURES = [
2+
"honeypot_count",
3+
"destination_port_count",
4+
"days_seen_count",
5+
"active_days_ratio",
6+
"login_attempts",
7+
"login_attempts_per_day",
8+
"interaction_count",
9+
"std_days_between",
10+
"days_since_last_seen",
11+
"days_since_first_seen",
12+
]
13+
14+
CATEGORICAL_FEATURES = [
15+
"asn",
16+
"ip_reputation",
17+
]
18+
19+
MULTI_VAL_FEATURES = [
20+
"honeypots",
21+
]
22+
23+
SAMPLE_COUNT = 100

0 commit comments

Comments
 (0)