✍️ 寫在前面
獎金獵人倒數,今天我們要做一件實用的事:
快速檢測上百個 IoT 設備的可用性與服務開放狀況。核心概念是把 FreeBuf 的網站檢測邏輯「拆成兩層」:
1️⃣ HTTP 狀態碼檢測(確認 Web 是否可達)
2️⃣ Port 掃描(確認哪些服務端口開放)這是紅隊賽前的最基本「偵察腳本」。
| 功能 | requests | httpx | 
|---|---|---|
| HTTP/2 支援 | ❌ 無 | ✅ 支援 | 
| 非同步處理 | ❌ 無 | ✅ async/await | 
| 效能 | 單執行緒 | ✅ 高併發 | 
| 錯誤處理 | 有限 | ✅ 詳細例外機制 | 
| 適合場景 | 單網站請求 | ✅ 大量網站 / IP 檢測 | 
結論:
httpx是 requests 的升級版,更適合紅隊做批量檢測與資產偵測。
target_ip.txt192.168.1.10
192.168.1.20
192.168.1.30
此程式會針對清單內每個 IP 嘗試存取 80、443、8080、8443 端口,
回報 HTTP 狀態碼(如 200、403、404、timeout)。
import httpx
import asyncio
from tabulate import tabulate
TARGET_PORTS = [80, 443, 8080, 8443]
async def check_http(ip, port):
    protocol = "https" if port in [443, 8443] else "http"
    url = f"{protocol}://{ip}:{port}"
    try:
        async with httpx.AsyncClient(timeout=5, follow_redirects=True) as client:
            r = await client.get(url)
            return ip, port, r.status_code
    except httpx.RequestError:
        return ip, port, "無法連線"
    except Exception as e:
        return ip, port, f"錯誤: {e}"
async def run_http_scan(ip_list):
    tasks = []
    for ip in ip_list:
        for port in TARGET_PORTS:
            tasks.append(check_http(ip, port))
    results = await asyncio.gather(*tasks)
    table = [[ip, port, status] for ip, port, status in results]
    print(tabulate(table, headers=["IP 位址", "Port", "HTTP 狀態"], tablefmt="grid"))
if __name__ == "__main__":
    with open("target_ip.txt") as f:
        ip_list = [line.strip() for line in f if line.strip()]
    asyncio.run(run_http_scan(ip_list))
🧾 範例輸出
+-------------+--------+-------------+
| IP 位址      | Port   | HTTP 狀態   |
+-------------+--------+-------------+
| 192.168.1.10 | 80     | 200         |
| 192.168.1.20 | 443    | 無法連線     |
| 192.168.1.30 | 8080   | 403         |
+-------------+--------+-------------+
有些 IoT 設備不一定有 Web 介面(例如 MQTT、Telnet、FTP),
因此還需做 TCP Port 掃描,確認服務是否開放。
import socket
from concurrent.futures import ThreadPoolExecutor
from tabulate import tabulate
TARGET_PORTS = [21, 22, 23, 80, 443, 8080, 1883, 8883]
def check_port(ip, port, timeout=1):
    try:
        with socket.create_connection((ip, port), timeout=timeout):
            return True
    except:
        return False
def run_port_scan(ip_list):
    results = []
    with ThreadPoolExecutor(max_workers=50) as executor:
        futures = []
        for ip in ip_list:
            for port in TARGET_PORTS:
                futures.append(executor.submit(check_port, ip, port))
        idx = 0
        for ip in ip_list:
            open_ports = []
            for port in TARGET_PORTS:
                if futures[idx].result():
                    open_ports.append(str(port))
                idx += 1
            results.append([ip, ", ".join(open_ports) if open_ports else "無開放"])
    print(tabulate(results, headers=["IP 位址", "開放 Ports"], tablefmt="grid"))
    return results
if __name__ == "__main__":
    with open("target_ip.txt") as f:
        ip_list = [line.strip() for line in f if line.strip()]
    run_port_scan(ip_list)
🧾 範例輸出
+-------------+---------------------+
| IP 位址      | 開放 Ports          |
+-------------+---------------------+
| 192.168.1.10 | 22, 80, 443         |
| 192.168.1.20 | 23, 8080            |
| 192.168.1.30 | 無開放              |
+-------------+---------------------+
| 功能 | 用途 | 說明 | 
|---|---|---|
| HTTP 檢測 | 判斷是否可連線、回應狀態 | 適合 Web 介面型 IoT | 
| Port 掃描 | 找出服務端口 | 適合嵌入式設備、NAS、路由器 | 
| 結果存檔 | 匯出 CSV | 可用於後續漏洞測試與報告撰寫 | 
| 延伸分析 | 輸入 nuclei / afrog / dalfox | 進行自動化漏洞掃描 |