1- import base64
2- import re
1+ from abc import ABCMeta
32from datetime import datetime
43from ipaddress import IPv4Address
5- from urllib .parse import urlparse
64
75from greedybear .consts import PAYLOAD_REQUEST , SCANNER
8- from greedybear .cronjobs .base import ExtractDataFromElastic , Honeypot
6+ from greedybear .cronjobs .base import ExtractDataFromElastic
97from greedybear .cronjobs .sensors import ExtractSensors
108from greedybear .models import IOC , Sensors
11- from greedybear .regex import REGEX_CVE_BASE64COMMAND , REGEX_CVE_LOG4J , REGEX_URL
129
1310
14- class ExtractAttacks (ExtractDataFromElastic ):
11+ class ExtractAttacks (ExtractDataFromElastic , metaclass = ABCMeta ):
1512 class IOCWhitelist (Exception ):
1613 pass
1714
1815 def __init__ (self ):
1916 super ().__init__ ()
20- self .honeypot = Honeypot ("Log4pot" )
2117 self .first_time_run = False
2218
2319 @property
@@ -28,147 +24,7 @@ def minutes_back_to_lookup(self):
2824 minutes = 11
2925 return minutes
3026
31- def _log4pot_lookup (self ):
32- search = self ._base_search (self .honeypot )
33- # we want to get only probes that tried to exploit the specific log4j CVE
34- search = search .filter ("term" , reason = "exploit" )
35- search = search .source (["deobfuscated_payload" , "correlation_id" ])
36- hits = search [:10000 ].execute ()
37-
38- url = None
39- hostname = None
40- hidden_url = None
41- hidden_hostname = None
42- added_scanners = 0
43- added_payloads = 0
44- added_hidden_payloads = 0
45-
46- for hit in hits :
47- scanner_ip = self ._get_scanner_ip (hit .correlation_id )
48-
49- match = re .search (REGEX_CVE_LOG4J , hit .deobfuscated_payload )
50- if match :
51- # we are losing the protocol but that's ok for now
52- url = match .group ()
53- url_adjusted = "tcp:" + url
54- # removing double slash
55- url = url [2 :]
56- self .log .info (f"found URL { url } in payload for CVE-2021-44228" )
57- # protocol required or extraction won't work
58- hostname = urlparse (url_adjusted ).hostname
59- self .log .info (f"extracted hostname { hostname } from { url } " )
60-
61- # it is possible to extract another payload from base64 encoded string.
62- # this is a behavior related to the attack that leverages LDAP
63- match_command = re .search (REGEX_CVE_BASE64COMMAND , hit .deobfuscated_payload )
64- if match_command :
65- # we are losing the protocol but that's ok for now
66- base64_encoded = match_command .group (1 )
67- self .log .info (
68- f"found base64 encoded command { base64_encoded } "
69- f" in payload from base64 code for CVE-2021-44228"
70- )
71- try :
72- decoded_str = base64 .b64decode (base64_encoded ).decode ()
73- self .log .info (
74- f"decoded base64 command to { decoded_str } "
75- f" from payload from base64 code for CVE-2021-44228"
76- )
77- except Exception as e :
78- self .log .warning (e , stack_info = True )
79- else :
80- match_url = re .search (REGEX_URL , decoded_str )
81- if match_url :
82- hidden_url = match_url .group ()
83- if "://" not in hidden_url :
84- hidden_url = "tcp://" + hidden_url
85- self .log .info (
86- f"found hidden URL { hidden_url } "
87- f" in payload for CVE-2021-44228"
88- )
89-
90- hidden_hostname = urlparse (hidden_url ).hostname
91- self .log .info (
92- f"extracted hostname { hidden_hostname } from { hidden_url } "
93- )
94-
95- # add scanner
96- if scanner_ip :
97- self ._add_ioc (scanner_ip , SCANNER )
98- added_scanners += 1
99-
100- # add first URL
101- if hostname :
102- related_urls = [url ] if url else None
103- self ._add_ioc (hostname , PAYLOAD_REQUEST , related_urls = related_urls )
104- added_payloads += 1
105-
106- # add hidden URL
107- if hidden_hostname :
108- related_urls = [hidden_url ] if hidden_url else None
109- self ._add_ioc (
110- hidden_hostname , PAYLOAD_REQUEST , related_urls = related_urls
111- )
112- added_hidden_payloads += 1
113-
114- # once all have added, we can add the foreign keys
115- self ._add_fks (scanner_ip , hostname , hidden_hostname )
116-
117- self .log .info (
118- f"added { added_scanners } scanners, { added_payloads } payloads"
119- f" and { added_hidden_payloads } hidden payloads"
120- )
121-
122- def _add_fks (self , scanner_ip , hostname , hidden_hostname ):
123- self .log .info (
124- f"adding foreign keys for the following iocs: { scanner_ip } , { hostname } , { hidden_hostname } "
125- )
126- scanner_ip_instance = IOC .objects .filter (name = scanner_ip ).first ()
127- hostname_instance = IOC .objects .filter (name = hostname ).first ()
128- hidden_hostname_instance = IOC .objects .filter (name = hidden_hostname ).first ()
129-
130- if scanner_ip_instance :
131- if (
132- hostname_instance
133- and hostname_instance not in scanner_ip_instance .related_ioc .all ()
134- ):
135- scanner_ip_instance .related_ioc .add (hostname_instance )
136- if (
137- hidden_hostname_instance
138- and hidden_hostname_instance
139- not in scanner_ip_instance .related_ioc .all ()
140- ):
141- scanner_ip_instance .related_ioc .add (hidden_hostname_instance )
142- scanner_ip_instance .save ()
143-
144- if hostname_instance :
145- if (
146- scanner_ip_instance
147- and scanner_ip_instance not in hostname_instance .related_ioc .all ()
148- ):
149- hostname_instance .related_ioc .add (scanner_ip_instance )
150- if (
151- hidden_hostname_instance
152- and hidden_hostname_instance not in hostname_instance .related_ioc .all ()
153- ):
154- hostname_instance .related_ioc .add (hidden_hostname_instance )
155- hostname_instance .save ()
156-
157- if hidden_hostname_instance :
158- if (
159- hostname_instance
160- and hostname_instance not in hidden_hostname_instance .related_ioc .all ()
161- ):
162- hidden_hostname_instance .related_ioc .add (hostname_instance )
163- if (
164- scanner_ip_instance
165- and scanner_ip_instance
166- not in hidden_hostname_instance .related_ioc .all ()
167- ):
168- hidden_hostname_instance .related_ioc .add (scanner_ip_instance )
169- hidden_hostname_instance .save ()
170-
171- def _add_ioc (self , ioc , attack_type , related_urls = None ):
27+ def _add_ioc (self , ioc , attack_type , related_urls = None , log4j = False , cowrie = False ):
17228 self .log .info (
17329 f"saving ioc { ioc } for attack_type { attack_type } and related_urls { related_urls } "
17430 )
@@ -202,7 +58,11 @@ def _add_ioc(self, ioc, attack_type, related_urls=None):
20258 if attack_type == PAYLOAD_REQUEST :
20359 ioc_instance .payload_request = True
20460
205- ioc_instance .log4j = True
61+ if log4j :
62+ ioc_instance .log4j = True
63+
64+ if cowrie :
65+ ioc_instance .cowrie = True
20666
20767 if ioc_instance :
20868 ioc_instance .save ()
@@ -227,42 +87,16 @@ def _get_ioc_type(self, ioc):
22787 ioc_type = "ip"
22888 return ioc_type
22989
230- def _get_scanner_ip (self , correlation_id ):
231- self .log .info (f"extracting scanner IP from correlation_id { correlation_id } " )
232- scanner_ip = None
233- search = self ._base_search (self .honeypot )
234- search = search .filter (
235- "term" , ** {"correlation_id.keyword" : str (correlation_id )}
236- )
237- search = search .filter ("term" , reason = "request" )
238- search = search .source (["src_ip" ])
239- # only one should be available
240- hits = search [:10 ].execute ()
241- for hit in hits :
242- scanner_ip = hit .src_ip
243- break
244-
245- if scanner_ip :
246- self .log .info (
247- f"extracted scanner IP { scanner_ip } from correlation_id { correlation_id } "
248- )
249- else :
250- self .log .warning (
251- f"scanner IP was not extracted from correlation_id { correlation_id } "
252- )
253-
254- return scanner_ip
255-
256- def _check_first_time_run (self ):
90+ def _check_first_time_run (self , honeypot_flag ):
25791 all_ioc = IOC .objects .all ()
25892 if not all_ioc :
259- # first time we execute this project.
260- # So we increment the time range to get the data from the last 3 days
261- self .first_time_run = True
26293 # plus, we extract the sensors addresses so we can whitelist them
26394 ExtractSensors ().execute ()
264-
265- def run (self ):
266- self ._healthcheck ()
267- self ._check_first_time_run ()
268- self ._log4pot_lookup ()
95+ self .first_time_run = True
96+ else :
97+ # if this is not the overall first time, it could that honeypot first time
98+ honeypot_ioc = IOC .objects .filter (** {f"{ honeypot_flag } " : True })
99+ if not honeypot_ioc :
100+ # first time we execute this project.
101+ # So we increment the time range to get the data from the last 3 days
102+ self .first_time_run = True
0 commit comments