Python网络安全工具高级开发(六十四):IoT安全之设备指纹识别

摘要:在本文中,我们将构建一个IoT设备指纹识别器,用于自动“画像”一个网络中的所有“黑盒”设备。我们将超越简单的
nmap
扫描,实现一个多维度、多层次的Python分析引擎。你将学习如何组合使用多种侦察技术来构建一个高置信度的设备画像:

L2指纹:使用
scapy
进行ARP扫描以发现存活主机,并利用
maclookup
库通过MAC地址OUI来识别硬件制造商(例如,”TP-Link”, “Samsung”, “Apple”)。

L4指纹:使用
python-nmap
库,对常见IoT端口(如
80
,
554
,
8080
,
9100
)进行服务版本探测,以识别运行的服务(如
GoAhead-Webs
,
RTSP
,
JetDirect
)。

L7指纹:使用
requests
库抓取开放HTTP端口的BannerHTML
<title>
,寻找如“IP Camera Login”或“Printer EWS”之类的关键词。 通过将这三层指纹(“它是什么厂商造的?”“它在运行什么服务?”“它的Web页面叫什么?”)关联起来,我们的工具将能够自动地对一个“哑巴”IP地址,做出如“这是一台海康威视(Hikvision)的网络摄像头”或“这是一台惠普(HP)打印机”的精准判断。

关键词:Python, IoT安全, 指纹识别,
scapy
,
python-nmap
, OUI, MAC地址, 服务发现, Banner抓取


正文

⚠️ 警告:高风险网络扫描,务必在授权网络中进行

端口扫描、服务探测和Banner抓取是主动的网络侦察行为。你必须、也只能在你拥有完全所有权或已获得明确授权的测试网络(如你自己的家庭网络、专用IoT实验室)中进行实验。 对任何公共或企业网络进行此类扫描都是非法的。

1. 为什么需要IoT指纹识别?

“影子IoT(Shadow IoT)”是企业安全的最大噩梦之一。一个员工私自带入公司的、插在网线上的“智能摄像头”或“树莓派”,可能在几年前就被曝出了高危的远程代码执行(RCE)漏洞。但由于它不在IT资产负债表上,它永远不会被打补丁。

一个IoT指纹识别器,就是网络安全团队的“清道夫”,它能定期巡检网络,自动发现并识别出这些未知的、潜在危险的“黑盒”设备。

2. 我们的“三层指纹”策略

L2: 它是谁“生”的? (MAC OUI) MAC地址的前24位(OUI)是分配给硬件制造商的。通过这个,我们可以知道它是“Apple”设备还是“Intel”网卡。

L4: 它开了哪些“门”? (Port/Service)


Port 9100
: 极有可能是打印机 (JetDirect协议)。


Port 554
: 极有可能是IP摄像头 (RTSP流媒体协议)。


Port 80/443
: Web管理界面。

L7: 它自称“叫”什么? (HTTP Banner/Title)


Server: GoAhead-Webs
: 大量嵌入式设备(摄像头、路由器)使用的Web服务器。


<title>HP Color LaserJet Pro</title>
: 明确的身份。

3. 环境准备:我们的Python“侦察兵”

我们将组合使用多个强大的Python库:

Bash



# scapy: 用于L2的ARP扫描
# python-nmap: 用于L4的服务版本探测
# maclookup: 用于MAC OUI厂商查询
# requests: 用于L7的Banner抓取
pip install scapy python-nmap maclookup requests

(注意:
python-nmap
需要你的系统上已经安装了
nmap
可执行程序。
sudo apt-get install nmap
)

4. 代码实现 (
iot_profiler.py
)

Python



# iot_profiler.py
import nmap
import requests
import argparse
import sys
import re
from scapy.all import arping
from maclookup import MacLookup
from urllib.parse import urlparse
 
# --- 1. L2 指纹: MAC OUI查询 ---
def get_device_profile(ip, mac):
    """根据MAC地址获取制造商。"""
    profile = {"ip": ip, "mac": mac, "vendor": "Unknown"}
    try:
        # MacLookup会从本地/远程数据库查询
        profile["vendor"] = MacLookup().lookup(mac)
    except Exception as e:
        print(f"[!] MAC地址 {mac} 查询失败: {e}", file=sys.stderr)
    return profile
 
# --- 2. L4 指纹: 端口与服务扫描 ---
def scan_iot_ports(ip):
    """
    使用nmap对常见的IoT端口进行服务版本探测。
    """
    print(f"  - [L4] 正在对 {ip} 进行服务版本扫描...")
    nm = nmap.PortScanner()
    # 常见的IoT/嵌入式设备端口
    common_iot_ports = "80,443,554,8000,8080,9100,515" 
    try:
        # -sV: 探测服务版本; -T4: 加快速度; -O: 尝试OS探测 (可能不准)
        nm.scan(ip, common_iot_ports, arguments="-sV -T4")
        
        open_ports = []
        if ip in nm.all_hosts() and nm[ip].state() == 'up':
            for proto in nm[ip].all_protocols():
                if proto != 'tcp': continue
                ports = nm[ip]['tcp'].keys()
                for port in ports:
                    service = nm[ip]['tcp'][port]
                    open_ports.append({
                        "port": port,
                        "service": service.get('name', 'unknown'),
                        "product": service.get('product', 'unknown'),
                        "version": service.get('version', 'unknown')
                    })
        return open_ports
    except Exception as e:
        print(f"[!] Nmap扫描 {ip} 失败: {e}", file=sys.stderr)
        return []
 
# --- 3. L7 指纹: HTTP Banner/Title抓取 ---
def grab_http_info(ip, port):
    """抓取HTTP(S)的Server头和HTML Title。"""
    scheme = 'https' if port == 443 else 'http'
    url = f"{scheme}://{ip}:{port}"
    
    try:
        # verify=False: 忽略自签名证书
        res = requests.get(url, timeout=3, verify=False)
        server_header = res.headers.get('Server', 'N/A')
        
        # 尝试从HTML中提取<title>
        title_match = re.search(r'<title>(.*?)</title>', res.text, re.IGNORECASE)
        html_title = title_match.group(1).strip() if title_match else "N/A"
        
        return {"server_header": server_header, "html_title": html_title}
    except requests.RequestException:
        return {"server_header": "N/A", "html_title": "N/A (Request Failed)"}
 
def main(network_cidr):
    print(f"[*] [L2] 正在使用ARP扫描发现网络: {network_cidr} ...")
    try:
        # 1. 使用Scapy的arping进行主机发现
        ans, unans = arping(network_cidr, verbose=0)
    except Exception as e:
        print(f"[!] 严重: ARP扫描失败 (请使用'sudo'): {e}")
        return
 
    if not ans:
        print("[-] 未在网络上发现任何存活主机。")
        return
 
    print(f"[+] 发现 {len(ans)} 个存活主机。开始指纹识别...")
    
    all_profiles = []
    for sent, received in ans:
        ip = received.psrc
        mac = received.hwsrc
        
        print("
" + "="*50)
        print(f"[+] 正在分析主机: {ip} (MAC: {mac})")
        
        # 1. L2 指纹
        profile = get_device_profile(ip, mac)
        print(f"  - [L2] 制造商: {profile['vendor']}")
        
        # 2. L4 指纹
        profile['open_ports'] = scan_iot_ports(ip)
        if profile['open_ports']:
            print(f"  - [L4] 开放端口与服务:")
            for p in profile['open_ports']:
                print(f"    - TCP/{p['port']}: {p['service']} ({p['product']} {p['version']})")
                
                # 3. L7 指纹 (如果80/443/8080开放)
                if p['port'] in [80, 443, 8080]:
                    print(f"    - [L7] 正在抓取HTTP Banner(端口 {p['port']})...")
                    http_info = grab_http_info(ip, p['port'])
                    profile['http_info'] = http_info
                    print(f"      - Server头: {http_info['server_header']}")
                    print(f"      - HTML标题: {http_info['html_title']}")
 
        all_profiles.append(profile)
        print("="*50)
 
    # --- 最终报告 ---
    print("

" + "="*70)
    print("                    IoT设备指纹识别总报告")
    print("="*70)
    for profile in all_profiles:
        print(f"
[--- 设备: {profile['ip']} | {profile['vendor']} ---]")
        if profile.get('open_ports'):
             for p in profile['open_ports']:
                 print(f"  -> TCP/{p['port']:<5} : {p['product']} {p['version']}")
                 if p['port'] in [80, 443, 8080]:
                     info = profile.get('http_info', {})
                     print(f"      - 标题: {info.get('html_title')}")
        else:
            print("  -> 未发现开放的常见IoT端口。")
 
def main_cli():
    parser = argparse.ArgumentParser(description="多层IoT设备指纹识别器。")
    parser.add_argument("network", help="要扫描的目标网络CIDR (例如: 192.168.1.0/24)。")
    args = parser.parse_args()
    
    if os.geteuid() != 0 and sys.platform != "win32":
        print("[!] 错误: 本工具需要root/sudo权限来执行ARP扫描。")
        sys.exit(1)
        
    # 禁用requests的SSL警告
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    
    main(args.network)
 
if __name__ == "__main__":
    import os
    main_cli()

5. 总结

我们成功地构建了一个自动化的IoT设备指纹识别器。它不再是单一维度的扫描,而是将L2(硬件厂商)L4(开放服务)和L7(应用内容)的情报关联起来,从而对一个“黑盒”设备进行精准的“画像”。

分析师的视角:当你看到一个
vendor: 'Hikvision'
(海康威视) +
port: 554
(RTSP) +
title: 'IP Camera'
的设备时,你就可以100%确定这是一台网络摄像头,并立即开始查找针对该型号的已知漏洞。

自动化:这个脚本可以作为
cron
任务,每天凌晨在你的网络中运行,自动发现新接入的“影子IoT”设备,并发出告警。

至此,我们已经完成了第七章“移动安全与IoT安全工具”的全部内容。我们已经掌握了分析移动App(静态、动态、通信、权限)和IoT设备(固件、硬件、协议、指纹)的全套技能。

© 版权声明

相关文章

暂无评论

none
暂无评论...