别扫整个内网了,用TTL追踪偷看子网结构更快

admin 2026-06-14 04:36:27 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍渗透测试中利用TTL追踪技术快速探测内网拓扑的方法。通过Screamer工具将探测目标从数万压缩至数百,结合ICMP、TCP、UDP多协议绕过过滤,一分钟内生成网络拓扑草图。实测显示该方法可缩减128倍扫描量,但存在网关预测偏差、严格过滤失效等局限性。 综合评分: 85 文章分类: 渗透测试,内网渗透,网络侦察,安全工具,红队


cover_image

别扫整个内网了,用TTL追踪偷看子网结构更快

幻泉之洲

2026年6月4日 00:54 北京

在小说阅读器读本章

去阅读

渗透测试中,面对一个完全陌生的内网地址空间,全端口扫描是场噩梦。本文介绍一个叫Screamer的工具,它通过多协议TTL追踪和启发式采样,把要探测的目标从几万个压缩到几百个,一分钟内就能画出网络拓扑草图。文章会拆解ICMP、TCP、UDP三种探测方式的优劣,展示实际测试数据,也说清楚这招的局限性在哪。

陌生网络里,你在哪?

做渗透测试的,或者管网络但手里没有资产清单的,经常会撞上同一堵墙:连上网络后,完全不知道路由设备藏在哪,后面挂了哪些子网。

第一反应肯定是扫呗。

但10.0.0.0/8有1600多万个地址,172.16.0.0/12也有100多万个。全扫一遍?生产设备扛不住这种压力,而且大量地址根本没人用,扫了也是白扫,时间全搭进去了。

其实有个更取巧的路子。

当你做路由追踪的时候,路径上的设备会主动暴露自己的接口地址——TTL耗尽的网关会回一个ICMP Time Exceeded报文,目标主机自己也会根据类型回不同的包,比如ICMP Destination Unreachable、SYN-ACK或者TCP RST。

Screamer[1]这个工具就是靠这个机制干活的。它用TTL追踪做侦察,不扫全网就能画出网络拓扑图。

本文只讲技术原理,用于授权的安全测试。所有演示都在我自己的隔离实验环境里跑。乱用的话后果自负。

TTL追踪的基本原理

Traceroute这玩意大家都不陌生。它发ICMP或者UDP探测包,把TTL从1开始逐个往上加,每一跳的路由器收到TTL过期的包,按RFC 792的规定,必须回一个ICMP Time Exceeded,这就暴露了自己的IP地址。包到了目标主机,对方回的就是另一种报文了,看端口开没开、协议是啥。

核心机制在IPv4包头那个TTL字段。TTL就是最大跳数,每过一个路由器减1。

减到0,路由器扔掉包,然后发ICMP Time Exceeded回来:

道理很简单。但默认的traceroute或者tracert只能追踪到某个特定地址的一条路径。想搞清楚整个网络里有哪些子网,要么你得提前知道所有目标地址,要么得跑海量追踪。后者又吵又慢,跟全端口扫描一个德行。

怎么办:切分子网,只猜网关

面对一个10.0.0.0/8这种量级的地址空间,一个地址一个地址去追踪肯定不行。

我的思路是这样:把大地址块切成最小的子网单元,然后只挑每个子网里最可能当网关的那两个地址去探测。

企业网络里,最典型的子网划分单元是/24。每个/24里,网关的第四段通常是.1或者.254。这不是硬性规定,但太常见了,足以当成一个启发式规则来用。

两步走:

  • 切片:把原始前缀拆成一组/24子网
  • 定位:从每个/24里挑最可能当网关的地址(Screamer默认选.1和.254,参考代码:https://github.com/ifritnoises/screamer/blob/d513a69e77b538e844c60474e2330e0550d484ac/screamer.py#L145)。你可以用–positions参数手动指定其他位置

def expand_targets(cidr, host_positions):    network = ipaddress.ip_network(cidr, strict=False)    if network.prefixlen <= 24:        subnets = network.subnets(new_prefix=24)    else:        subnets = [network]    targets = []    for subnet in subnets:        for position in host_positions:            try:                targets.append(str(subnet[position]))            except IndexError:                pass    return targets

拿172.16.0.0/12来说,把它切成4096个/24,每个/24只取.1和.254两个地址。总共也就8192个探测目标。要是/16,切成256个/24,从65536个主机地址压缩到512个目标。

这个量级,用TTL探测跑一圈,时间完全可控。

在实验环境里跑一下

测试用的隔离网络拓扑很清晰:中间一台Core路由器,连着Edge路由器和A、B、C三台路由器。每台路由器后面挂一个192.168.X.0/24的用户网段。

攻击者从外部网络通过Edge路由器接入,在192.168.100.0/24这个段里,第一跳网关是192.168.100.171。

下面分别用ICMP、TCP、UDP三种协议来探测同一个192.168.0.0/16空间。

ICMP Echo

ping和标准traceroute用的就是这玩意。发一个TTL=N的包,第N跳路由器回Time Exceeded,目标主机如果活着且没被过滤,回Echo Reply。

sudo screamer active 192.168.0.0/16 -m icmp-echo –max-ttl 3 –out-dot graph.dot –out-subnets subnets.txt

现实是,很多管理员会在某些位置把入站ICMP Echo给禁了,防洪水攻击或者扫描。所以你看到的结果里混进了不少运营商设备的地址——这是因为有些探测目标路由器压根没有路由,包被默认路由0.0.0.0/0扔到了上游,沿途的ISP路由器也回了Time Exceeded。工具在探测阶段分不清哪个是目标网络内部的,哪个是外部的,这些都得事后分析路由表的时候再剥离。

ICMP Timestamp Request

这种ICMP报文本来是用来做主机间时间同步的,对方收到应该回Timestamp Reply。

sudo screamer active 192.168.0.0/16 -m icmp-timestamp –max-ttl 3 –out-dot graph.dot –out-subnets subnets.txt

它提供的信息跟Echo差不多,但有个小优势:通常不会被封。管理员配ACL的时候经常记得禁Echo,但把Timestamp Request给忘了。大量网络设备默认会响应Timestamp请求。

用ICMP的错误码发现过滤规则

ICMP流量不光能暴露出跳的地址,还能间接透露路径上的过滤策略。看配置,路由器收到被ACL拦掉的流量时,可能会回特定类型和代码的ICMP报文。当然管理员可以用no ip unreachables关掉这个行为,让网络更难被摸清。

几个关键的ICMP代码:

  • Code 9:目标网络被管理员禁止(RFC 1812)
  • Code 10:目标主机被管理员禁止(RFC 1812)
  • Code 13:通信被管理员禁止(RFC 1812)

ICMP可以被过滤,但TTL机制作用在IP层。不管传输层是ICMP、TCP还是UDP,TTL耗尽回Time Exceeded这个行为是一样的。这意味着你可以换传输协议来绕过过滤——ICMP常被限制,但TCP/443几乎畅通无阻。

TCP SYN

ICMP容易被封,但TCP就好办多了。去往TCP/443这种常见端口的出站流量几乎不会被拦,因为拦了用户就没法上网了。

TCP探测发的是SYN包,三次握手的第一个包。有三种可能的结果:

  • 收到ICMP Time Exceeded——TTL耗尽了
  • 收到SYN-ACK——主机活着,端口开放
  • 收到RST——主机活着,但端口没开

sudo screamer active 192.168.0.0/16 -m tcp –dport 443 –max-ttl 3 –out-dot graph.dot –out-subnets subnets.txt

所以在入站ICMP被过滤的环境里,TCP是个很好的TTL追踪载体。选对端口,大概率能穿过ACL。

UDP

UDP是无连接协议,响应逻辑跟TCP完全不同。发一个UDP探测包出去,可能收到:

  • ICMP Time Exceeded——TTL耗尽
  • ICMP Destination Unreachable(Type 3, Code 3)——主机收到了包,但端口没开

选UDP/53(DNS)或者UDP/123(NTP)当目标端口,这类流量在企业网里很少被彻底封死。

sudo screamer active 192.168.0.0/16 -m udp –dport 123 –max-ttl 3 –out-dot graph.dot –out-subnets subnets.txt

ICMP、TCP、UDP三种协议轮着用,本质上是打组合拳:封了一个,另外两个大概率还能通。这就是多协议TTL追踪的价值。

实测数据

在隔离环境里对同一个192.168.0.0/16用四种方法各跑一次,条件完全一致:

| 方法 | 目标数 | 发包数 | 耗时 | | — | — | — | — | | ICMP Echo | 512 | 1534 | 25.9s | | ICMP Timestamp | 512 | 1536 | 54.6s | | TCP SYN (443) | 512 | 1534 | 33.8s | | UDP (123) | 512 | 1535 | 25.6s |

条件:192.168.0.0/16,30线程,最大TTL=3,超时1秒。

几个观察:

压缩效果明显。从65536个主机地址砍到512个目标,128倍的缩减。一圈跑下来不到一分钟。实际发包数(1534-1536)略低于理论最大值512×3=1536,差的那几个是因为目标在没到max-ttl之前就被解析出来了,工具不再继续往上加TTL。

覆盖度有差异。ICMP Echo、TCP SYN、UDP都发现了13个独立跳点,Timestamp只发现7个。有些设备压根不回Timestamp Request。所以Timestamp的价值不在于覆盖广,而在于能穿过那些屏蔽了Echo的过滤器——它是个备胎。

耗时主要看无响应目标的比例。固定超时时间下,跑得慢不是因为协议本身慢,而是没回应的目标多。Timestamp回应的主机最少,所以把1536次尝试全部打满,耗时最长(54.6秒)。这个时间数据只在这套测试环境里有意义,别当成协议速度排行榜。

拿到的数据能干什么

探测跑完,手里是一堆TTL排序的跳点序列。工具对每个目标存的数据结构很简单:

traces = {}  # target_ip -> {ttl: responder_ip}

traces.setdefault(target_ip, {})[ttl] = responder_ip

把这些序列拼起来,就得到一张有向图。节点是发现的地址,边是TTL相邻的跳点之间的连接。根节点固定为攻击者自己:

edges = set() for hops_by_ttl in traces.values():    previous_node = “Screamer”    for ttl in sorted(hops_by_ttl):        current_node = hops_by_ttl[ttl]        # 同一个IP可能在多个TTL上出现,跳过自环        if previous_node != current_node:            edges.add((previous_node, current_node))        previous_node = current_node

边存在集合里,重复的(A, B)对只保留一次。共享路由段会坍缩成单条边,分叉处形成分支。图反映的是观测到的路由结构——要是某个跳点没响应,它的邻居就直接连起来了,所以这种相邻关系是条件性的。

这是192.168.0.0/16的探测结果图:

有了这张图和潜在子网列表,攻击者就不用盲目扫全量地址空间了。他知道该往192.168.10.0/24、192.168.50.0/24和192.168.107.0/24这些具体的/24里使劲。针对性扫描几分钟就能拿到服务清单,比闷头扫10.0.0.0/8快几个数量级。

这招的边界在哪

多协议TTL追踪做初始侦察确实管用,但有四个明显的坑:

多接口路由器会被当成多个节点。路由器回Time Exceeded的时候用的源地址取决于反向路由,不是哪个接口收到探测包就从哪个接口回。所以同一台物理路由器可能在图里表现为两个甚至多个不相关的节点。图不等于物理拓扑,这个错觉要小心。

网关预测不一定准。整套方法建立在“每个/24的网关大概率是.1或.254”这个假设上。企业网里确实常见,但没有人规定必须这么配。可以用–positions参数扩大候选地址列表来补救,但这需要迭代式地加大样本量。

遇到严格过滤就歇菜。多协议虽然能对抗单一协议的过滤——ICMP被堵了上TCP,TCP被堵了上UDP。但如果边界安全做得足够狠,三种协议全封了,或者做了应用层流量检测把非标准行为全干掉,这方法就彻底失效了。执行默认拒绝策略的高安全网络里尤其如此。

防火墙可能搞乱TTL。有些路由器配了规则,把入站包的TTL偷偷加一,这样它自己就不会触发Time Exceeded。结果就是在拓扑图里中间跳点消失,两台距离很远的设备看起来像是直连的。

虽然有这些限制,但这个方法确实能在短时间内给攻击者或安全测试人员一个陌生网络的骨架——路由大致怎么走,地址空间大概怎么分。足够用来规划下一步干什么了。


参考资料

[1] https://github.com/ifritnoises/screamer

[2] https://ifritnoises.org/articles/pattern-screamer/


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:幻泉之洲 《别扫整个内网了,用TTL追踪偷看子网结构更快》

评论:0   参与:  0