Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ba8f256
Support using -ap to make slips monitor the 2 access point interfaces
AlyaGomaa Oct 15, 2025
c56afea
add db functions to set and get AP interfaces
AlyaGomaa Oct 15, 2025
fd573a2
store the interfaces given with -ap to slips in the db
AlyaGomaa Oct 15, 2025
8bd4108
support having 2 zeek threads, observers and log parsers, one for eac…
AlyaGomaa Oct 15, 2025
2b6cc43
blocking: refactor
AlyaGomaa Oct 15, 2025
8a2e9bc
store the host IP per interface in the db
AlyaGomaa Oct 16, 2025
4fadc55
host_ip_manager: return the host ip of each of the given interfaces
AlyaGomaa Oct 16, 2025
d8011f2
threat_intelligence.py: check all host ips when detecting inbound tra…
AlyaGomaa Oct 16, 2025
7ed9d76
display a warning and exit when -ap is given but not running access p…
AlyaGomaa Oct 16, 2025
a3e7cd6
idmef: temporary disable get_host_ip()
AlyaGomaa Oct 16, 2025
c240802
docs: use linux-wifi-hotspot instead of create_ap for AP setup
AlyaGomaa Oct 16, 2025
72ee0c3
input: fix detecting interfaces_to_monitor
AlyaGomaa Oct 17, 2025
fbb2ec1
input: fix problem starting 2 zeek instances for 2 diff interfaces
AlyaGomaa Oct 17, 2025
cb73e2a
Tie each flow, evidence and alert to an interface
AlyaGomaa Oct 19, 2025
64b0a14
Add an interface to each evidence before giving it to evidence handler
AlyaGomaa Oct 19, 2025
ed61c4a
don't tie an alert to an interface, an alert is a combination of evid…
AlyaGomaa Oct 19, 2025
d46a446
ip_info: Support getting the gateway interface of the access point in…
AlyaGomaa Oct 19, 2025
a911923
poisoner: use the given interface for getting the GW ip
AlyaGomaa Oct 20, 2025
1138a5b
Move get_gateway_for_iface from ip_info to slips utils to be used acc…
AlyaGomaa Oct 20, 2025
5b47007
db: use the interface for storing the GW ip and mac
AlyaGomaa Oct 20, 2025
4e37222
ip_info: use the interface for getting the GW ip and MAC
AlyaGomaa Oct 20, 2025
ba62d77
use the interface every time a module needs access to the GW mac or ip
AlyaGomaa Oct 20, 2025
029bf8d
utils: add func to get_all_interfaces
AlyaGomaa Oct 20, 2025
2d83418
Add a class for building the zeek command
AlyaGomaa Oct 21, 2025
b25a577
ZeekCmdBuilder: support custom packet filters (defined in slips code,…
AlyaGomaa Oct 21, 2025
786fdb9
slips_utils: add a func to get_cidr_of_interface
AlyaGomaa Oct 21, 2025
a250e5b
input: Add a tcpdump filter to log only incoming traffic when startin…
AlyaGomaa Oct 21, 2025
2da188d
Add the interface to evidence description
AlyaGomaa Oct 21, 2025
5b8f57a
idmef: Fix Validation failure: '0.0.0.0' is not of type 'object'
AlyaGomaa Oct 21, 2025
efb5a21
Make the getting and setting of the local network dependent on the in…
AlyaGomaa Oct 21, 2025
24f4924
zeek.py: fix problem inheriting BaseFlow in all zeek classes
AlyaGomaa Oct 21, 2025
5413672
Fix problem logging the interface of each evidence of an alert
AlyaGomaa Oct 21, 2025
794d1c9
profiler: make the detection of the GW MAC address dependant on the i…
AlyaGomaa Oct 22, 2025
dd994d5
evidence_handler: add a more deterministic way to get the interface o…
AlyaGomaa Oct 22, 2025
b7ab143
Fix unable to start blocking modules when using -ap
AlyaGomaa Oct 22, 2025
518bab0
Make blocking requests and arp poisoner aware of the interface of the…
AlyaGomaa Oct 22, 2025
431d099
blocking: Add -i and -o to the iptable command to block on the correc…
AlyaGomaa Oct 22, 2025
e4cabec
input: kill the 2 started zeek instances on shutdown_gracefully
AlyaGomaa Oct 22, 2025
93469c9
conn: fix FP conn to port 0 when it's just IGMP
AlyaGomaa Oct 22, 2025
328ec93
zeek: move redef tcp_attempt_delay=1min; to slips-conf.zeek instead o…
AlyaGomaa Oct 22, 2025
907ce0d
update arp poisoner unit tests
AlyaGomaa Oct 23, 2025
921390f
fix checker, blocking and conn.py unit tests
AlyaGomaa Oct 23, 2025
cf588b7
fix database unit tests
AlyaGomaa Oct 23, 2025
cc00bf6
update evidence_handler and evidence_formatter unit tests
AlyaGomaa Oct 23, 2025
555b5a6
update flow_handler unit tests
AlyaGomaa Oct 23, 2025
3fb525a
update host_ip_manager unit tests
AlyaGomaa Oct 24, 2025
efc6f2b
update input.py unit tests
AlyaGomaa Oct 24, 2025
f193178
update ip_info.py unit tests
AlyaGomaa Oct 24, 2025
daea7c5
update profiler.py unit tests
AlyaGomaa Oct 24, 2025
b52188b
update profile handler.py unit tests
AlyaGomaa Oct 24, 2025
47f34a8
update timeline.py unit tests
AlyaGomaa Oct 24, 2025
9fdefde
zeek_cmd_builder.py: fix SyntaxError: unterminated string literal
AlyaGomaa Oct 24, 2025
cdda466
host_ip_manager: infer the used interface when slips is running on a …
AlyaGomaa Oct 24, 2025
39e380f
fix test_conn unit tests
AlyaGomaa Oct 24, 2025
0ea1b4b
Make slips able to infer the interface being monitored when given a g…
AlyaGomaa Oct 24, 2025
aae7ee4
host_ip_manager.py: detect the used interface and host IP when runnin…
AlyaGomaa Oct 24, 2025
eda6b3b
poisoner: remove debugging prints
AlyaGomaa Oct 24, 2025
13715af
fix host ip manager unit tests
AlyaGomaa Oct 24, 2025
4576950
fix process manager unit tests
AlyaGomaa Oct 24, 2025
8a5a2dc
Add a dummy interface to each argus flow to be able to use it in slips
AlyaGomaa Oct 24, 2025
8c8c82d
Add a dummy interface to each Nfdump flow to be able to use it in slips
AlyaGomaa Oct 24, 2025
4cf832e
Add a dummy interface to each suricata flow to be able to use it in s…
AlyaGomaa Oct 24, 2025
1b769fc
iasync_module.py: better exception handling (print traceback)
AlyaGomaa Oct 24, 2025
b6431ff
flowalerts.ssl: Check first if we're looking for a field in the SSL f…
AlyaGomaa Oct 24, 2025
e6c0887
use "default" as the interface when slips is analyzing a file
AlyaGomaa Oct 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ repos:
rev: v1.35.1
hooks:
- id: yamllint
args: ["-d", "{rules: {line-length: {max: 100}}}"]
args: ["-d", "{rules: {line-length: {max: 160}}}"]
files: "slips.yaml"

- repo: local
Expand Down
35 changes: 18 additions & 17 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,24 @@ def profiler_queue():
def flow():
"""returns a dummy flow for testing"""
return Conn(
"1601998398.945854",
"1234",
"192.168.1.1",
"8.8.8.8",
5,
"TCP",
"dhcp",
80,
88,
20,
20,
20,
20,
"",
"",
"Established",
"",
starttime="1601998398.945854",
uid="1234",
saddr="192.168.1.1",
daddr="8.8.8.8",
dur=5,
proto="TCP",
appproto="dhcp",
sport=80,
dport=88,
spkts=20,
dpkts=20,
sbytes=20,
dbytes=20,
state="Established",
history="",
smac="",
dmac="",
interface="eth0",
)


Expand Down
11 changes: 6 additions & 5 deletions docs/immune/installing_slips_in_the_rpi.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ Meaning it wil kick out the malicious device from the AP.


1. Connect your RPI to your router using an ethernet cable
2. Run your RPI as an access point using [create_ap](https://github.com/oblique/create_ap)
2. Install [linux-wifi-hotspot](https://github.com/lakinduakash/linux-wifi-hotspot/blob/master/src/scripts/README.md)
3. Start the access point (in NAT mode)

`sudo create_ap wlan0 eth0 rpi_wifi mysecurepassword -c 40`
`sudo create_ap wlan0 eth0 rpi_wifi mysecurepassword -c 40`

where `wlan0` is the wifi interface of your RPI, `eth0` is the ethernet interface and `-c 40` is the channel of the access point.
where `wlan0` is the wifi interface of your RPI, `eth0` is the ethernet interface and `-c 40` is the channel of the access point.

We chose channel 40 because it is a 5GHz channel, which is faster and less crowded than the 2.4GHz channels.

Expand All @@ -49,13 +50,13 @@ If all goes well you should see `wlan0: AP-ENABLED` in the output of the command

Check the [Debugging common AP errors](#debugging-common-ap-errors) section if you have any issues.

3. Run Slips in the RPI using the command below to listen to the traffic from the access point.
4. Run Slips in the RPI using the command below to listen to the traffic from the access point.

```bash
./slips.py -i wlan0
```

4. (Optional) If you want to block malicious devices, run Slips with the `-p` parameter. Using this parameter will
5. (Optional) If you want to block malicious devices, run Slips with the `-p` parameter. Using this parameter will
block all traffic to and from the malicious device when slips sets an alert.

```bash
Expand Down
9 changes: 5 additions & 4 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,10 @@ Meaning it wil kick out the malicious device from the AP.


1. Connect your RPI to your router using an ethernet cable
2. Run your RPI as an access point using [create_ap](https://github.com/oblique/create_ap)
2. Install [linux-wifi-hotspot](https://github.com/lakinduakash/linux-wifi-hotspot/blob/master/src/scripts/README.md)
3. Start the access point (in NAT mode)

`sudo create_ap wlan0 eth0 rpi_wifi mysecurepassword -c 40`
`sudo create_ap wlan0 eth0 rpi_wifi mysecurepassword -c 40`

where `wlan0` is the wifi interface of your RPI, `eth0` is the ethernet interface and `-c 40` is the channel of the access point.

Expand All @@ -360,13 +361,13 @@ Check the [Debugging common AP errors](https://stratospherelinuxips.readthedocs.



3. Run Slips in the RPI using the command below to listen to the traffic from the access point.
4. Run Slips in the RPI using the command below to listen to the traffic from the access point.

```bash
./slips.py -i wlan0
```

4. (Optional) If you want to block malicious devices, run Slips with the `-p` parameter. Using this parameter will
5. (Optional) If you want to block malicious devices, run Slips with the `-p` parameter. Using this parameter will
block all traffic to and from the malicious device when slips sets an alert.

```bash
Expand Down
1 change: 1 addition & 0 deletions install/apt_dependencies.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ ca-certificates
redis
wget
npm
iw
39 changes: 39 additions & 0 deletions managers/ap_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import subprocess


class APManager:
"""
Gets AP info when slips is running as an AP in the RPI
https://stratospherelinuxips.readthedocs.io/en/develop/immune/installing_slips_in_the_rpi.html#protect-your-local-network-with-slips-on-the-rpi
"""

def __init__(self, main):
self.main = main

def store_ap_interfaces(self, input_information):
"""
stores the interfaces given with -ap to slips in the db
"""
self.wifi_interface, self.eth_interface = input_information.split(",")
interfaces = {
"wifi_interface": self.wifi_interface,
"ethernet_interface": self.eth_interface,
}
self.main.db.set_ap_info(interfaces)

def is_ap_running(self):
"""returns true if a running AP is detected"""
command = ["iw", "dev"]
try:
result = subprocess.run(
command, capture_output=True, text=True, check=True
)
lines = result.stdout.splitlines()
for line in lines:
if "type AP" in line:
return True
return False
except subprocess.CalledProcessError:
return False
except FileNotFoundError:
return False
87 changes: 63 additions & 24 deletions managers/host_ip_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,63 @@
import netifaces
from typing import (
Set,
Optional,
List,
Dict,
)

from slips_files.common.slips_utils import utils
from slips_files.common.style import green


class HostIPManager:
def __init__(self, main):
self.main = main
self.info_printed = False

def get_host_ip(self) -> Optional[str]:
def _get_default_host_ip(self, interface) -> str | None:
"""
Return the host IP of the default interface (IPv4).
usefull when slips is running using -g and the user didn't supply
an interface, so we need to infer it
"""
try:
# Get the default gateway info (usually includes interface name)
addrs = netifaces.ifaddresses(interface)
# AF_INET is for IPv4 addresses
inet_info = addrs.get(netifaces.AF_INET)
if not inet_info:
return None

return inet_info[0]["addr"]
except Exception as e:
print(f"Error getting host IP: {e}")
return None

def _get_host_ips(self) -> Dict[str, str]:
"""
tries to determine the machine's IP.
uses the intrfaces provided by the user if -i is given, or all
interfaces if not.
uses the intrfaces provided by the user with -i or -ap
returns a dict with {interface_name: host_ip, ..}
"""
if not (self.main.args.interface or self.main.args.growing):
# slips is running on a file, we cant determine the host IP
return
if self.main.args.growing:
# -g is used, user didn't supply the interface
# try to get the default interface
interface = utils.infer_used_interface()
if not interface:
return {}

if default_host_ip := self._get_default_host_ip(interface):
return {interface: default_host_ip}
return {}

# we use all interfaces when -g is used, otherwise we use the given
# interface
interfaces: List[str] = (
[self.main.args.interface]
if self.main.args.interface
else netifaces.interfaces()
else self.main.args.access_point.split(",")
)

found_ips = {}
for iface in interfaces:
addrs = netifaces.ifaddresses(iface)
# check for IPv4 address
Expand All @@ -41,9 +69,10 @@ def get_host_ip(self) -> Optional[str]:
for addr in addrs[netifaces.AF_INET]:
ip = addr.get("addr")
if ip and not ip.startswith("127."):
return ip
found_ips[iface] = ip
return found_ips

def store_host_ip(self) -> Optional[str]:
def store_host_ip(self) -> Dict[str, str] | None:
"""
stores the host ip in the db
recursively retries to get the host IP online every 10s if not
Expand All @@ -52,33 +81,43 @@ def store_host_ip(self) -> Optional[str]:
if not self.main.db.is_running_non_stop():
return

if host_ip := self.get_host_ip():
self.main.db.set_host_ip(host_ip)
self.main.print(f"Detected host IP: {green(host_ip)}")
return host_ip
if host_ips := self._get_host_ips():
for iface, ip in host_ips.items():
self.main.db.set_host_ip(ip, iface)
if not self.info_printed:
self.main.print(
f"Detected host IP: {green(ip)} for {green(iface)}"
)
self.info_printed = True

return host_ips

self.main.print("Not Connected to the internet. Reconnecting in 10s.")
time.sleep(10)
self.store_host_ip()

def update_host_ip(
self, host_ip: str, modified_profiles: Set[str]
) -> Optional[str]:
self, host_ips: Dict[str, str], modified_profiles: Set[str]
) -> Dict[str, str]:
"""
Is called every 5s for slips to update the host ip
when running on an interface we keep track of the host IP.
If there was no modified TWs in the host IP, we check if the
network was changed.
:param modified_profiles: modified profiles since slips start time
:param host_ips: a dict with {interface: host_ip,..} for each
interface slips is monitoring
"""
if not self.main.db.is_running_non_stop():
return

if host_ip in modified_profiles:
return host_ip

if latest_host_ip := self.get_host_ip():
self.main.db.set_host_ip(latest_host_ip)
return latest_host_ip
if host_ips:
res = {}
for iface, ip in host_ips.items():
if ip in modified_profiles:
res[iface] = ip
if res:
return res

return latest_host_ip
# there was no modified TWs in the host IPs, check if network changed
return self.store_host_ip()
2 changes: 1 addition & 1 deletion managers/process_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ def should_run_non_stop(self) -> bool:
return (
self.is_debugger_active()
or self.main.input_type in ("stdin", "cyst")
or self.main.is_interface
or self.main.db.is_running_non_stop()
)

def shutdown_interactive(
Expand Down
6 changes: 3 additions & 3 deletions modules/arp/arp.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def get_uids():
# node to announce or update its IP to MAC mapping
# to the entire network. It shouldn't be marked as an arp scan
# Don't detect arp scan from the GW router
if self.db.get_gateway_ip() == flow.saddr:
if self.db.get_gateway_ip(flow.interface) == flow.saddr:
return False

# What is this?
Expand Down Expand Up @@ -417,8 +417,8 @@ def detect_mitm_arp_attack(self, twid: str, flow):
attackers_ip = flow.saddr
victims_ip = original_ip

gateway_ip = self.db.get_gateway_ip()
gateway_mac = self.db.get_gateway_mac()
gateway_ip = self.db.get_gateway_ip(flow.interface)
gateway_mac = self.db.get_gateway_mac(flow.interface)
if flow.saddr == gateway_ip:
saddr = f"The gateway {flow.saddr}"
else:
Expand Down
2 changes: 1 addition & 1 deletion modules/arp/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def should_discard_evidence(self, ip: str) -> bool:

def is_self_defense(self, ip: str):
"""
slips uses arp poison to defend itself and th enetwork,
slips uses arp poison to defend itself and the network,
check arp_poison.py for more details.
goal of this function is to discard evidence about slips doing arp
attacks when it's just attacking attackers
Expand Down
Loading
Loading