惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
博客园 - 叶小钗
Blog — PlanetScale
Blog — PlanetScale
Microsoft Azure Blog
Microsoft Azure Blog
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
D
Docker
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Register - Security
The Register - Security
J
Java Code Geeks
S
SegmentFault 最新的问题
月光博客
月光博客
G
Google Developers Blog
美团技术团队
Last Week in AI
Last Week in AI
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
T
The Blog of Author Tim Ferriss
腾讯CDC
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
The Cloudflare Blog
有赞技术团队
有赞技术团队
博客园_首页
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
B
Blog
I
InfoQ
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Fortinet All Blogs
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
爱范儿
爱范儿
D
DataBreaches.Net
F
Full Disclosure
M
MIT News - Artificial intelligence
博客园 - 司徒正美
H
Help Net Security

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 读:AI Agent 生产化——一份从原型到上线的速查清单 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 Linux 数据去重学习笔记 - 暗无天日 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日
2026-04-14 · via 暗无天日

你有没有想过,有人可以用你的 IP 地址去扫描别人的服务器,而你可能毫不知情?

这并不是天方夜谭。2024 年,开源游戏项目 DDNet 的服务器就遭遇了这种攻击。攻击者利用 nmap 的 IP 欺骗扫描功能,冒充 DDNet 的服务器 IP 对大学网络进行端口扫描。大学的安全系统自动检测到扫描行为后,向 DDNet 的主机商发送了 abuse 报告。主机商在无法验证数据包是否真的来自 DDNet 服务器的情况下,直接关停了他们的 VPS。更糟的是,即使 DDNet 配置了防火墙规则,攻击者仍然可以每天重复这种攻击,最终导致服务被终止。

这种攻击利用的是 nmap 的 IP 伪造扫描能力。nmap 提供了多种欺骗扫描方式,包括直接伪造源 IP 的 -S 参数、混入诱饵的 Decoy Scan-D ),以及更加隐蔽的 Idle Scan-sI )。下面我们就来深入了解这些欺骗扫描技术是如何工作的,以及作为服务器管理员应该如何检测和防御。

参考资料: https://hookrace.net/blog/port-scan-with-spoofed-ip-addresses/

什么是 IP 欺骗

IP 欺骗(IP Spoofing)是指发送数据包时伪造源 IP 地址。在 TCP 协议中,由于三次握手机制的存在,单纯的 IP 伪造很难建立完整的 TCP 连接,因为响应包会被发送到被伪造的 IP 地址而非攻击者。

但是,端口扫描不一定需要建立完整的 TCP 连接。nmap 的 SYN 扫描(半开扫描)只需要发送一个 SYN 包并观察响应即可判断端口状态,不需要完成三次握手。这就为 IP 欺骗扫描创造了条件。

nmap 提供了三种主要的伪装扫描方式:

  1. -S (伪造源 IP ):最直接的方式,将扫描包的源 IP 设为受害者的 IP 。这也是 DDNet 攻击中最可能使用的方式
  2. Decoy Scan (诱饵扫描,=-D= 参数):在真实扫描包中混入大量伪造源 IP 的探测包,让目标无法分辨真正的扫描者
  3. Idle Scan (僵尸扫描,=-sI= 参数):利用第三方僵尸主机的 IP ID 递增特性来间接判断端口状态,攻击者 IP 完全不出现在流量中

下面分别详细介绍这三种技术。

伪造源 IP ( -S 参数)

最简单的 IP 伪造方式就是用 -S 参数直接指定扫描包的源 IP 地址:

sudo nmap -S 192.168.31.30 192.168.31.25

使用 -S 后,目标服务器看到的所有扫描包都来自伪造的 IP 。这种方式非常直接,也是 DDNet 攻击中最可能使用的手法——攻击者将自己的源 IP 设为 DDNet 服务器的 IP ,然后去扫描大学网络,大学自然会认为扫描来自 DDNet 。

不过 -S 有一个局限:由于响应包会被发送到伪造的 IP 而非攻击者,攻击者无法直接收到扫描结果。因此 -S 通常与 -e (指定网络接口)和 -Pn (跳过主机发现)配合使用,或者结合其他手段来获取扫描结果。

Decoy Scan(诱饵扫描)

原理

Decoy Scan 的思路很直接:在发送真实的 SYN 扫描包的同时,发送大量源 IP 伪造的 SYN 包。目标服务器会看到来自多个 IP 地址的扫描请求,无法确定哪个是真正的攻击者。

其数据包流程为:

  1. nmap 向目标发送一批 SYN 包,其中一部分的源 IP 是真实的(攻击者的),其余的是伪造的诱饵 IP
  2. 目标服务器对每个 SYN 包都回复 SYN/ACK(端口开放)或 RST(端口关闭)
  3. 只有真实攻击者能收到目标的响应(因为诱饵 IP 是伪造的)
  4. 攻击者根据收到的响应判断端口状态

从目标服务器的日志来看,扫描来自多个不同的 IP,就像遭到了分布式扫描一样。

命令格式

使用 -D 参数指定诱饵 IP 列表,用逗号分隔。 ME 代表自己的真实 IP :

sudo nmap -D 192.168.31.100,192.168.31.101,ME 192.168.31.250

sudo nmap -D RND:10 192.168.31.250

sudo nmap -D 192.168.31.100,192.168.31.101,192.168.31.102,192.168.31.103,ME 192.168.31.250

注意: ME 放在第 6 位或之后时,一些端口扫描检测工具(如 scanlogd)不会报告真实 IP(根据 nmap 文档)。 另外,nmap -D 实现IP地址欺骗(伪造源IP)需要原始套接字 (raw socket) 能力,这通常只有 root 用户才被操作系统允许。当你以普通用户身份运行 nmap 时,系统会拒绝发送源IP不属于本地网卡的伪造数据包。

实操演示

下面我们在本地环境中演示 Decoy Scan。假设有三台机器:

  • 攻击者:192.168.31.10
  • 目标:192.168.31.25
  • 诱饵 IP(伪造):192.168.31.100、192.168.31.101

在攻击者机器上执行:

sudo nmap -D 192.168.31.100,192.168.31.101,ME 192.168.31.25

同时在目标机器上用 tcpdump 抓包观察:

sudo tcpdump -n -i any 'tcp[tcpflags] & (tcp-syn) != 0 and not tcp[tcpflags] & (tcp-ack) != 0' -c 30

目标服务器会看到类似这样的输出:

IP 192.168.31.100.12345 > 192.168.31.25.80: Flags [S], seq 123456
IP 192.168.31.101.12346 > 192.168.31.25.443: Flags [S], seq 234567
IP 192.168.31.10.12347 > 192.168.31.25.22: Flags [S], seq 345678
IP 192.168.31.100.12348 > 192.168.31.25.21: Flags [S], seq 456789
...

可以看到,目标服务器认为扫描来自 192.168.31.100、192.168.31.101 和 192.168.31.10 三个 IP。如果这些诱饵 IP 恰好属于某个真实的服务器,那台服务器的管理员就会收到 abuse 投诉,而不是攻击者。

Idle Scan(僵尸扫描)

原理

Idle Scan 是一种更加精巧的扫描技术。它利用了 TCP/IP 协议栈中 IP ID(IP 标识符)字段递增的特性,通过一个"僵尸主机"来间接探测目标服务器的端口状态,攻击者的 IP 完全不会 出现在目标服务器的任何日志中。

其核心流程分为四步:

  1. 探测僵尸的 IP ID :攻击者向僵尸主机发送 SYN/ACK 包,僵尸主机会回复 RST 包,该包的 IP ID 值记为 N
  2. 伪造 SYN 包发给目标 :攻击者伪造一个源 IP 为僵尸主机的 SYN 包,发送给目标服务器的待测端口
  3. 目标与僵尸交互
    • 若目标端口*开放*:目标回复 SYN/ACK 给僵尸,僵尸觉得莫名其妙(没有发起过连接),回复 RST,僵尸的 IP ID 递增 1(从 N 变为 N+1)
    • 若目标端口*关闭*:目标回复 RST 给僵尸,僵尸不会响应这个 RST,因此 IP ID 不会因这次交互而增加
  4. 再次探测僵尸的 IP ID :攻击者再次发送 SYN/ACK 给僵尸,获取新的 IP ID 值 M:
    • M = N + 1 → 端口关闭或被过滤
    • M = N + 2 → 端口开放(中间那次递增就是目标与僵尸交互时产生的)

整个过程中,目标服务器只看到来自僵尸主机的扫描,*完全看不到攻击者的 IP*。

僵尸主机的选择条件

并不是任何主机都能作为僵尸,需要满足:

  • IP ID 序列是全局递增的(不是 per-connection 递增)
  • 在扫描期间保持空闲(没有其他流量干扰 IP ID 递增)
  • 能够响应 unsolicited SYN/ACK(即回复 RST)

实践中,网络打印机、老旧路由器、某些 IOT 设备常常满足这些条件。nmap 自带一个脚本可以帮你测试候选僵尸:

sudo nmap --script ipidseq <candidate_ip>

如果输出显示 IP ID Sequence: Incremental ,则该主机可以作为僵尸。

命令格式

使用 -sI 参数指定僵尸主机:

sudo nmap -sI <zombie_host> <target>

sudo nmap -sI 192.168.31.50 -p 22,80,443 192.168.31.250

sudo nmap -Pn -p- -sI 192.168.31.50 192.168.31.250

注意:Idle Scan 需要 root 权限,因为要构造原始数据包。

实操演示

假设我们有:

  • 攻击者:192.168.31.10
  • 僵尸主机:192.168.31.50(一台网络打印机)
  • 目标:192.168.31.25

先测试僵尸主机是否可用:

sudo nmap --script ipidseq 192.168.31.50

确认 IP ID 是递增的后,执行扫描:

sudo nmap -sI 192.168.31.50 -p 22,80,443 192.168.31.25

在目标服务器上用 tcpdump 抓包,你会发现 只有 僵尸主机的 IP 出现在日志中:

sudo tcpdump -n host 192.168.31.25 and tcp
IP 192.168.31.50.12345 > 192.168.31.25.22: Flags [S], seq ...
IP 192.168.31.25.22 > 192.168.31.50.12345: Flags [S.], seq ...
IP 192.168.31.50.12345 > 192.168.31.25.22: Flags [R], seq ...

整个过程攻击者 192.168.31.10 *完全没有出现*。如果大学的安全系统检测到这个扫描,他们会认为扫描来自 192.168.31.50 这台打印机。

防御方案

了解了攻击原理后,我们来看看作为服务器管理员可以采取哪些防御措施。

检测异常流量

使用 tcpdump 监控异常的 SYN 包模式:

sudo tcpdump -n -i any 'tcp[tcpflags] & (tcp-syn) != 0 and not tcp[tcpflags] & (tcp-ack) != 0'

如果短时间内看到来自大量不同 IP 的 SYN 包,很可能就是 Decoy Scan。

也可以用 ss 命令查看处于 SYN_RECV 状态的连接:

ss -tunap | grep SYN_RECV

大量 SYN_RECV 状态的连接说明有人在扫描或进行 SYN Flood 攻击。

限制出站 TCP 连接

DDNet 在遭遇攻击后采取的防御措施之一就是限制出站 TCP 新连接,只保留必要端口。这样即使有人想冒充你去扫描,你的服务器也不会发出这些包(不过这只能证明你的服务器没有主动发出扫描,无法阻止别人伪造你的 IP ):

sudo iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A OUTPUT -p tcp -m conntrack --ctstate NEW -j DROP

你也可以直接拒绝特定 IP 段的流量(比如频繁发 abuse 报告的大学):

sudo iptables -A INPUT -s 147.251.0.0/16 -j DROP
sudo iptables -A OUTPUT -d 147.251.0.0/16 -j DROP

BCP38 与 uRPF:根本解决方案

上面这些措施只是治标。IP 欺骗攻击的根本原因是:很多 ISP 没有过滤伪造源 IP 的数据包。

BCP38(最初为 RFC 2827,现已被 RFC 3704 取代)是 IETF 发布的最佳实践文档,要求 ISP 在网络边界实施 入站过滤 ,阻止源 IP 不属于该网络的数据包离开网络。其具体实现机制叫做 uRPF(Unicast Reverse Path Forwarding,单播反向路径转发)。

在 Linux 上,uRPF 可以通过内核参数启用:

cat /proc/sys/net/ipv4/conf/all/rp_filter

sudo sysctl -w net.ipv4.conf.all.rp_filter=1

严格模式会检查数据包的源 IP 是否可以通过接收该包的接口到达。如果不匹配,就丢弃该包。这样可以有效阻止伪造源 IP 的数据包从你的网络发出。

但是 ,uRPF 需要在 ISP 的路由器上配置,普通 VPS 用户无能为力。这也是为什么 IP 欺骗攻击至今仍然有效——它需要整个互联网生态的配合才能根治。

收到 abuse 报告时的应对

如果你的服务器被别人冒充进行 IP 欺骗扫描,收到了主机商转发的 abuse 报告,可以采取以下步骤:

  1. 检查服务器日志 :确认在报告所述时间段内,服务器没有发出相关流量
grep "reported_time_range" /var/log/kern.log | grep "DPT="
  1. 提供 tcpdump 证据 :在服务器上持续抓包记录,作为没有发出扫描流量的证据
sudo tcpdump -i any -G 3600 -w '/var/log/traffic_%Y%m%d_%H.pcap' "tcp[tcpflags] & (tcp-syn) != 0 and not tcp[tcpflags] & (tcp-ack) != 0"
  1. 向主机商解释 :说明 IP 欺骗扫描的原理,指出攻击者可以从任何位置伪造你的 IP 进行扫描,你的服务器不需要发出任何数据包。可以引用原文 https://hookrace.net/blog/port-scan-with-spoofed-ip-addresses/ 作为参考
  2. 请求 ISP 提供 netflow 数据 :只有上游路由器的 netflow 数据才能证明数据包是否真的从你的 VPS 发出

小结

IP 欺骗端口扫描利用的是互联网信任链中的漏洞:大学信任 IP 地址 → 主机商信任 abuse 报告 → 但 IP 地址可以被伪造。本质上是一种"借刀杀人"。

对于个人服务器管理员来说,能做的防御有限:

  • 限制出站连接可以证明自己的清白,但无法阻止别人伪造你的 IP
  • 保留网络流量日志可以在收到 abuse 报告时提供证据
  • 向主机商解释 IP 欺骗的原理,争取理解

根本解决方案需要 ISP 实施 BCP38 源地址验证,阻止伪造源 IP 的数据包离开网络。但在整个互联网都实施之前,这种攻击手法仍将存在。

如果你也遭遇了类似的攻击,欢迎在评论区分享你的经历和应对方法。