本文目录导读:

- 核心原理
- 方案一:使用 Python 脚本(最灵活、跨平台)
- 方案二:使用 Shell 脚本(简单、Linux/macOS 原生)
- 方案三:使用 Windows PowerShell(Windows 原生)
- 如何选择与注意事项
发现内网在线设备是网络管理和安全审计中的常见需求,实现这一目标的核心原理通常基于网络层(IP) 和链路层(MAC) 的协议交互。
由于你提到的“脚本”,以下将介绍几种常用的脚本实现方式,涵盖不同的原理、适用场景以及对应的示例代码(主要使用Python和Shell)。
核心原理
- ICMP Ping 请求:向目标IP发送ICMP Echo Request,等待响应。
- ARP 请求:在本地广播域发送ARP请求,询问“谁是IP X.X.X.X?”。
- TCP/UDP 端口探测:尝试连接目标的特定端口(如80, 445, 22),根据连接是否成功判断设备是否在线。
使用 Python 脚本(最灵活、跨平台)
Python 拥有丰富的网络库,适合构建更复杂的扫描逻辑。
基于 Ping 的简单方法(需要系统权限)
这种方法最直接,但速度较慢,且容易被防火墙拦截。
import subprocess
import platform
def ping_host(ip):
"""Ping 一个 IP 地址,返回是否在线。"""
# 根据系统选择 ping 参数
param = "-n" if platform.system().lower() == "windows" else "-c"
# -W 1 设置超时 1 秒 (Linux/macOS), windows 用 -w 1000 (毫秒)
command = ["ping", param, "1", "-W", "1", ip] if platform.system().lower() != "windows" else ["ping", param, "1", "-w", "1000", ip]
try:
# 执行命令, 不显示输出, 设置超时
result = subprocess.run(command, capture_output=True, timeout=2)
return result.returncode == 0
except subprocess.TimeoutExpired:
return False
def scan_network_ping(network_prefix):
"""扫描 /24 网段 (192.168.1.0/24)"""
online_devices = []
for i in range(1, 255): # 去掉 .0 (网络地址) 和 .255 (广播地址)
ip = f"{network_prefix}.{i}"
if ping_host(ip):
print(f"[+] 设备在线: {ip}")
online_devices.append(ip)
return online_devices
if __name__ == "__main__":
# 请根据你的网络修改前缀,"192.168.1"
scan_network_ping("192.168.1")
基于 ARP 请求的高效方法(推荐,仅限局域网)
使用 scapy 库构造和发送 ARP 包,这是局域网发现最准确、快速的方法之一,但需要 root/管理员权限。
from scapy.all import ARP, Ether, srp
import sys
def scan_network_arp(target_ip):
"""
使用 ARP 请求扫描网段。
:param target_ip: "192.168.1.0/24"
"""
# 创建 ARP 请求包
arp_request = ARP(pdst=target_ip)
# 创建以太网广播帧
broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
# 组合包
packet = broadcast / arp_request
# 发送包并接收响应
# timeout: 等待响应的秒数
# verbose: 是否显示详细信息
answered_list = srp(packet, timeout=2, verbose=False)[0]
devices = []
for element in answered_list:
device_info = {
"ip": element[1].psrc, # 响应者的 IP
"mac": element[1].hwsrc # 响应者的 MAC 地址
}
devices.append(device_info)
print(f"[+] 设备在线: IP={device_info['ip']:15} MAC={device_info['mac']}")
return devices
if __name__ == "__main__":
# 需要 root 权限运行
scan_network_arp("192.168.1.0/24")
基于 TCP 连接探测(穿透性强)
尝试连接常见端口(如 80, 445, 22),如果目标主机在线且端口开放,连接会成功。
import socket
import concurrent.futures
def check_tcp_port(ip, port, timeout=1):
"""尝试 TCP 连接一个端口"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
try:
result = sock.connect_ex((ip, port))
if result == 0:
return True
else:
return False
except socket.error:
return False
finally:
sock.close()
def scan_network_tcp(network_prefix, ports=[80, 445, 22]):
"""扫描网段,使用多线程加速"""
online_devices = []
# 使用线程池加快扫描速度
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
# 为所有 IP 创建任务
future_to_ip = {executor.submit(check_tcp_port, f"{network_prefix}.{i}", ports[0]): f"{network_prefix}.{i}" for i in range(1, 255)}
for future in concurrent.futures.as_completed(future_to_ip):
ip = future_to_ip[future]
try:
if future.result():
online_devices.append(ip)
print(f"[+] 设备可能在线: {ip} (端口 {ports[0]} 开放)")
except:
pass
return online_devices
if __name__ == "__main__":
scan_network_tcp("192.168.1")
使用 Shell 脚本(简单、Linux/macOS 原生)
对于 Linux/macOS 系统,Shell 脚本非常高效。
使用 fping (比普通 ping 快很多)
#!/bin/bash
# 需要先安装 fping: brew install fping (macOS), apt install fping (Ubuntu)
network="192.168.1"
echo "扫描 ${network}.0/24 网段..."
# -a: 只显示活动主机
# -g: 扫描一个网段
# -r 0: 不重试
fping -a -g ${network}.0/24 -r 0 -q 2>/dev/null
# 或者输出到变量
# online_hosts=$(fping -a -g ${network}.0/24 -r 0 -q 2>/dev/null)
使用 arp-scan (最专业,需要 root)
#!/bin/bash # 需要安装: apt install arp-scan (Linux) # 扫描本地网络 sudo arp-scan --localnet # 或者指定接口和网段 # sudo arp-scan --interface eth0 192.168.1.0/24
配合 nmap (功能最全面)
如果系统上有 nmap,这是最专业的扫描工具。
# 简单的 Ping 扫描,发现在线主机 (不进行端口扫描) nmap -sn 192.168.1.0/24 # 更快的扫描 (使用 -T4 激进模式) nmap -sn -T4 192.168.1.0/24 # MAC 地址也会一并显示
使用 Windows PowerShell(Windows 原生)
对于 Windows 用户,PowerShell 提供了内置的 Test-Connection 和 Get-NetNeighbor。
使用 Test-Connection (慢,但不需要额外工具)
# 扫描 1-254 地址
1..254 | ForEach-Object -Parallel {
$ip = "192.168.1.$_"
if (Test-Connection -ComputerName $ip -Count 1 -Quiet -TimeToLive 1) {
Write-Host "[+] 设备在线: $ip"
}
} -ThrottleLimit 50
使用 Get-NetNeighbor (快速查看 ARP 表)
# 查看本地 ARP 缓存中已经发现的设备 (不是扫描,是查看已缓存的)
Get-NetNeighbor | Where-Object {$_.State -eq 'Reachable'}
# 主动触发扫描的方法 (略复杂,需要调用API或使用arp命令)
# 更简单的是利用 cmd 的 arp -a
cmd /c arp -a
如何选择与注意事项
| 方法 | 速度 | 准确度 | 权限要求 | 隐蔽性 | 适用场景 |
|---|---|---|---|---|---|
| ARP (scapy/arp-scan) | 极快 | 极高 | root | 低 (广播) | 局域网内最佳选择 |
| TCP 端口扫描 (多线程) | 快 | 中 | 普通用户 | 中 | 跨网段、防火墙限制环境 |
| ICMP Ping (fping) | 快 | 中 | 普通用户 | 低 (ICMP) | 简单快速的可用性检查 |
| ICMP Ping (subprocess) | 慢 | 中 | 普通用户 | 低 | 跨平台兼容性需求 |
重要注意事项:
- 权限问题:ARP 扫描必须要有 root / 管理员权限,因为需要发送原始数据包。
- 安全性与合规性:未经授权扫描他人网络是违法的,请确保你拥有对目标网络的合法管理权限。
- 防火墙:目标主机可能启用了防火墙(如 Windows 防火墙、iptables),会阻止 ICMP Ping 或 TCP 探测,ARP 因为工作在链路层,通常无法被本网段防火墙阻止。
- 网络负载:大量并发扫描(如脚本中的多线程)可能会对交换机或路由器造成短暂负载,甚至触发 IDS/IPS 告警。
- 网络范围:确定你的 IP 地址范围,常见的是
/24(254个IP),也有/16(6.5万个IP),对于大规模扫描,建议使用arp-scan或nmap并合理设置超时。
对于最简单的单文件脚本,推荐使用 Python + scapy 进行 ARP 扫描(局域网最快最准),或者 Python + socket 进行 TCP 端口探测(跨网段),如果不想依赖第三方库,Shell 脚本 + fping 或 PowerShell + Test-Connection 是内置的好方案。