Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix conn outside of localnet evidence #475

Merged
merged 7 commits into from
Mar 7, 2024
11 changes: 11 additions & 0 deletions docs/flowalerts.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ For example if the currently used local network is: 192.168.1.0/24

and slips sees a forged packet going from 192.168.1.2 to 10.0.0.1, it will alert

Slips detects the current local network by using the local network of the private
ips specified in ```client_ips``` parameter in ```slips.conf```

If no IPs are specified, slips uses the local network of the first private source ip
found in the traffic.

This threat level of this detection is low if the source ip is the one outside of local network
because it's unlikely.
and high if the destination ip is the one outside of local network.


## High entropy DNS TXT answers

Slips check every DNS answer with TXT record for high entropy
Expand Down
2 changes: 1 addition & 1 deletion managers/metadata_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def update_slips_running_stats(self) -> Tuple[int, Set[str]] :
# this is the modification time of the last timewindow
last_modified_tw_time: float
modified_profiles, last_modified_tw_time = (
self.main.db.getModifiedProfilesSince(slips_internal_time)
self.main.db.get_modified_profiles_since(slips_internal_time)
)
modified_ips_in_the_last_tw = len(modified_profiles)
self.main.db.set_input_metadata(
Expand Down
2 changes: 1 addition & 1 deletion managers/process_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ def shutdown_gracefully(self):
timeout_seconds: float = timeout * 60

# close all tws
self.main.db.check_TW_to_close(close_all=True)
self.main.db.check_tw_to_close(close_all=True)
analysis_time = self.get_analysis_time()
self.main.print(
f"Analysis of {self.main.input_information} "
Expand Down
11 changes: 7 additions & 4 deletions modules/flowalerts/set_evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ def different_localnet_usage(
'srcip' outside the localnet or the 'dstip'?
"""
srcip = profileid.split('_')[-1]
# the attacker here is the IP found to be private and outside the localnet
# the attacker here is the IP found to be
# private and outside the localnet
if ip_outside_localnet == 'srcip':
attacker = Attacker(
direction=Direction.SRC,
Expand All @@ -150,6 +151,7 @@ def different_localnet_usage(
victim_type=IoCType.IP,
value=daddr
)
threat_level = ThreatLevel.LOW
description = f'A connection from a private IP ({srcip}) ' \
f'outside of the used local network ' \
f'{self.db.get_local_network()}. To IP: {daddr} '
Expand All @@ -164,6 +166,7 @@ def different_localnet_usage(
victim_type=IoCType.IP,
value=srcip
)
threat_level = ThreatLevel.HIGH
description = f'A connection to a private IP ({daddr}) ' \
f'outside of the used local network ' \
f'{self.db.get_local_network()}. ' \
Expand All @@ -173,8 +176,8 @@ def different_localnet_usage(


confidence = 1.0
threat_level = ThreatLevel.HIGH


twid_number = int(twid.replace("timewindow", ""))
evidence = Evidence(
evidence_type=EvidenceType.DIFFERENT_LOCALNET,
attacker=attacker,
Expand All @@ -183,7 +186,7 @@ def different_localnet_usage(
description=description,
victim=victim,
profile=ProfileID(ip=srcip),
timewindow=TimeWindow(number=int(twid.replace("timewindow", ""))),
timewindow=TimeWindow(number=twid_number),
uid=[uid],
timestamp=timestamp,
conn_count=1,
Expand Down
2 changes: 1 addition & 1 deletion modules/virustotal/virustotal.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def set_url_data_in_URLInfo(self, url, cached_data):
# Score of this url didn't change
vtdata = {'URL': score, 'timestamp': time.time()}
data = {'VirusTotal': vtdata}
self.db.setInfoForURLs(url, data)
self.db.set_info_for_urls(url, data)

def set_domain_data_in_DomainInfo(self, domain, cached_data):
"""
Expand Down
2 changes: 1 addition & 1 deletion slips/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ def sig_handler(sig, frame):
self.update_stats()

# Check if we need to close any TWs
self.db.check_TW_to_close()
self.db.check_tw_to_close()

modified_profiles: Set[str] = (
self.metadata_man.update_slips_running_stats()[1]
Expand Down
9 changes: 5 additions & 4 deletions slips_files/common/slips_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ def __init__(self):
self.local_tz = self.get_local_timezone()
self.aid = aid_hash.AID()

def get_cidr_of_ip(self, ip):
def get_cidr_of_private_ip(self, ip):
"""
returns the cidr/range of the given private ip
:param ip: should be a private ips
:param ip: should be a private ipv4
"""
if validators.ipv4(ip):
first_octet = ip.split('.')[0]
Expand Down Expand Up @@ -322,7 +322,7 @@ def get_own_IPs(self) -> list:
def convert_to_mb(self, bytes):
return int(bytes)/(10**6)

def is_private_ip(self, ip_obj:ipaddress) -> bool:
def is_private_ip(self, ip_obj: ipaddress) -> bool:
"""
This function replaces the ipaddress library 'is_private'
because it does not work correctly and it does not ignore
Expand All @@ -331,7 +331,8 @@ def is_private_ip(self, ip_obj:ipaddress) -> bool:
# Is it a well-formed ipv4 or ipv6?
r_value = False
if ip_obj and ip_obj.is_private:
if ip_obj != ipaddress.ip_address('0.0.0.0') and ip_obj != ipaddress.ip_address('255.255.255.255'):
if (ip_obj != ipaddress.ip_address('0.0.0.0')
and ip_obj != ipaddress.ip_address('255.255.255.255')):
r_value = True
return r_value

Expand Down
59 changes: 28 additions & 31 deletions slips_files/core/database/database_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,23 +537,23 @@ def setNewURL(self, *args, **kwargs):
def get_domain_data(self, *args, **kwargs):
return self.rdb.get_domain_data(*args, **kwargs)

def setNewDomain(self, *args, **kwargs):
return self.rdb.setNewDomain(*args, **kwargs)
def set_new_domain(self, *args, **kwargs):
return self.rdb.set_new_domain(*args, **kwargs)

def set_info_for_domains(self, *args, **kwargs):
return self.rdb.set_info_for_domains(*args, **kwargs)

def setInfoForURLs(self, *args, **kwargs):
return self.rdb.setInfoForURLs(*args, **kwargs)
def set_info_for_urls(self, *args, **kwargs):
return self.rdb.set_info_for_urls(*args, **kwargs)

def get_data_from_profile_tw(self, *args, **kwargs):
return self.rdb.get_data_from_profile_tw(*args, **kwargs)

def getOutTuplesfromProfileTW(self, *args, **kwargs):
return self.rdb.getOutTuplesfromProfileTW(*args, **kwargs)
def get_outtuples_from_profile_tw(self, *args, **kwargs):
return self.rdb.get_outtuples_from_profile_tw(*args, **kwargs)

def getInTuplesfromProfileTW(self, *args, **kwargs):
return self.rdb.getInTuplesfromProfileTW(*args, **kwargs)
def get_intuples_from_profile_tw(self, *args, **kwargs):
return self.rdb.get_intuples_from_profile_tw(*args, **kwargs)

def get_dhcp_flows(self, *args, **kwargs):
return self.rdb.get_dhcp_flows(*args, **kwargs)
Expand All @@ -573,8 +573,8 @@ def add_out_dns(self, *args, **kwargs):
def add_port(self, *args, **kwargs):
return self.rdb.add_port(*args, **kwargs)

def getFinalStateFromFlags(self, *args, **kwargs):
return self.rdb.getFinalStateFromFlags(*args, **kwargs)
def get_final_state_from_flags(self, *args, **kwargs):
return self.rdb.get_final_state_from_flags(*args, **kwargs)

def add_ips(self, *args, **kwargs):
return self.rdb.add_ips(*args, **kwargs)
Expand Down Expand Up @@ -642,14 +642,14 @@ def getTWsfromProfile(self, *args, **kwargs):
def get_number_of_tws_in_profile(self, *args, **kwargs):
return self.rdb.get_number_of_tws_in_profile(*args, **kwargs)

def getSrcIPsfromProfileTW(self, *args, **kwargs):
return self.rdb.getSrcIPsfromProfileTW(*args, **kwargs)
def get_srcips_from_profile_tw(self, *args, **kwargs):
return self.rdb.get_srcips_from_profile_tw(*args, **kwargs)

def getDstIPsfromProfileTW(self, *args, **kwargs):
return self.rdb.getDstIPsfromProfileTW(*args, **kwargs)
def get_dstips_from_profile_tw(self, *args, **kwargs):
return self.rdb.get_dstips_from_profile_tw(*args, **kwargs)

def getT2ForProfileTW(self, *args, **kwargs):
return self.rdb.getT2ForProfileTW(*args, **kwargs)
def get_t2_for_profile_tw(self, *args, **kwargs):
return self.rdb.get_t2_for_profile_tw(*args, **kwargs)

def has_profile(self, *args, **kwargs):
return self.rdb.has_profile(*args, **kwargs)
Expand All @@ -675,14 +675,14 @@ def add_new_tw(self, *args, **kwargs):
def get_tw_start_time(self, *args, **kwargs):
return self.rdb.get_tw_start_time(*args, **kwargs)

def getAmountTW(self, *args, **kwargs):
return self.rdb.getAmountTW(*args, **kwargs)
def get_number_of_tws(self, *args, **kwargs):
return self.rdb.get_number_of_tws(*args, **kwargs)

def getModifiedTWSinceTime(self, *args, **kwargs):
return self.rdb.getModifiedTWSinceTime(*args, **kwargs)
def get_modified_tw_since_time(self, *args, **kwargs):
return self.rdb.get_modified_tw_since_time(*args, **kwargs)

def getModifiedProfilesSince(self, *args, **kwargs):
return self.rdb.getModifiedProfilesSince(*args, **kwargs)
def get_modified_profiles_since(self, *args, **kwargs):
return self.rdb.get_modified_profiles_since(*args, **kwargs)

def add_mac_addr_to_profile(self, *args, **kwargs):
return self.rdb.add_mac_addr_to_profile(*args, **kwargs)
Expand Down Expand Up @@ -714,17 +714,17 @@ def add_profile(self, *args, **kwargs):
def set_profile_module_label(self, *args, **kwargs):
return self.rdb.set_profile_module_label(*args, **kwargs)

def check_TW_to_close(self, *args, **kwargs):
return self.rdb.check_TW_to_close(*args, **kwargs)
def check_tw_to_close(self, *args, **kwargs):
return self.rdb.check_tw_to_close(*args, **kwargs)

def check_health(self):
self.rdb.pubsub.check_health()

def markProfileTWAsClosed(self, *args, **kwargs):
return self.rdb.markProfileTWAsClosed(*args, **kwargs)
def mark_profile_tw_as_closed(self, *args, **kwargs):
return self.rdb.mark_profile_tw_as_closed(*args, **kwargs)

def markProfileTWAsModified(self, *args, **kwargs):
return self.rdb.markProfileTWAsModified(*args, **kwargs)
def mark_profile_tw_as_modified(self, *args, **kwargs):
return self.rdb.mark_profile_tw_as_modified(*args, **kwargs)

def add_tuple(self, *args, **kwargs):
return self.rdb.add_tuple(*args, **kwargs)
Expand Down Expand Up @@ -858,9 +858,6 @@ def delete(self, *args, **kwargs):
def select(self, *args, **kwargs):
return self.sqlite.select(*args, **kwargs)

def execute_query(self, *args, **kwargs):
return self.sqlite.execute_query(*args, **kwargs)

def get_pid_of(self, *args, **kwargs):
return self.rdb.get_pid_of(*args, **kwargs)

Expand Down
33 changes: 11 additions & 22 deletions slips_files/core/database/redis_db/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def _read_configuration(cls):
cls.deletePrevdb: bool = conf.deletePrevdb()
cls.disabled_detections: List[str] = conf.disabled_detections()
cls.width = conf.get_tw_width_as_float()
cls.client_ips: List[str] = conf.client_ips()

@classmethod
def set_slips_internal_time(cls, timestamp):
Expand Down Expand Up @@ -474,33 +475,21 @@ def get_equivalent_tws(self, hrs: float):
for example if the tw width is 1h, and hrs is 24, this function returns 24
"""
return int(hrs*3600/self.width)



def set_local_network(self, cidr):
"""
set the local network used in the db
"""
self.r.set("local_network", cidr)

def set_local_network(self, saddr):
# set the local network used in the db
# For now the local network is only ipv4, but it
# could be ipv6 in the future. Todo.

if self.is_localnet_set:
return

if saddr in ('0.0.0.0', '255.255.255.255'):
return

if not (
validators.ipv4(saddr)
and utils.is_private_ip(ipaddress.ip_address(saddr))
):
return
# get the local network of this saddr
if network_range := utils.get_cidr_of_ip(saddr):
self.r.set("local_network", network_range)
self.is_localnet_set = True
def get_local_network(self):
return self.r.get("local_network")

def get_used_port(self):
return int(self.r.config_get('port')['port'])

def get_local_network(self):
return self.r.get("local_network")

def get_label_count(self, label):
"""
Expand Down
6 changes: 3 additions & 3 deletions slips_files/core/database/redis_db/ioc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ def get_domain_data(self, domain):
data = json.loads(data) if data or data == {} else False
return data

def setNewDomain(self, domain: str):
def set_new_domain(self, domain: str):
"""
1- Stores this new domain in the Domains hash
2- Publishes in the channels that there is a new domain, and that we want
Expand Down Expand Up @@ -391,7 +391,7 @@ def set_info_for_domains(self, domain: str, info_to_set: dict, mode= 'leave'):
domain_data = self.get_domain_data(domain)
if not domain_data:
# This domain is not in the dictionary, add it first:
self.setNewDomain(domain)
self.set_new_domain(domain)
# Now get the data, which should be empty, but just in case
domain_data = self.get_domain_data(domain)

Expand Down Expand Up @@ -451,7 +451,7 @@ def set_info_for_domains(self, domain: str, info_to_set: dict, mode= 'leave'):
# Publish the changes
self.r.publish('dns_info_change', domain)

def setInfoForURLs(self, url: str, urldata: dict):
def set_info_for_urls(self, url: str, urldata: dict):
"""
Store information for this URL
We receive a dictionary, such as {'VirusTotal': {'URL':score}} that we are
Expand Down
Loading
Loading