linux udp 防火墙 161,一次穿透 iptables 防火墙的 UDP 攻击报文真实案例分析[通俗易懂]

linux udp 防火墙 161,一次穿透 iptables 防火墙的 UDP 攻击报文真实案例分析[通俗易懂][root@platinum-PT~]#tcpdump-ieth0-nnnvvvudpandport161tcpdump:listeningoneth0,link-typeEN10MB(Ethernet),capturesize96bytes16:50:07.035719IP(tos0x0,ttl64,id32494,offset0,fla…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

[root@platinum-PT ~]# tcpdump -ieth0 -nnnvvv udp and port 161

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

16:50:07.035719 IP (tos 0x0, ttl  64, id 32494, offset 0, flags [+], proto 17, length: 1500) platinum-PT >209.59.150.117.161:  { SNMPv2c {GetResponse(35) R=20039  .1.3.6.1.2.1.1.1.0=”Linux C”} }

16:50:12.035509 IP (tos 0x16,ECT(0), ttl  49, id 30047, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.046640 IP (tos 0x16,ECT(0), ttl  49, id 30078, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.058869 IP (tos 0x16,ECT(0), ttl  49, id 30075, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.063363 IP (tos 0x16,ECT(0), ttl  49, id 30039, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.074612 IP (tos 0x16,ECT(0), ttl  49, id 30095, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.075511 IP (tos 0x16,ECT(0), ttl  49, id 30092, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.080521 IP (tos 0x16,ECT(0), ttl  49, id 30015, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.086440 IP (tos 0x16,ECT(0), ttl  49, id 30031, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.089447 IP (tos 0x16,ECT(0), ttl  49, id 30001, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.137224 IP (tos 0x16,ECT(0), ttl  49, id 30034, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:12.179586 IP (tos 0x16,ECT(0), ttl  49, id 30044, offset 0, flags [none], proto 17, length: 65) 209.59.150.117.161 > platinum-PT: [udp sum ok]  { SNMPv2c { GetBulk(22) R=20039  N=0 M=2250 .1.3.6.1 } }

16:50:14.799292 IP (tos 0x0, ttl  64, id 32495, offset 0, flags [+], proto 17, length: 1500) platinum-PT > 209.59.150.117.161:  { SNMPv2c { GetResponse(35) R=20039  .1.3.6.1.2.1.1.1.0=”Linux C”} }

16:50:23.250338 IP (tos 0x0, ttl  64, id 32496, offset 0, flags [+], proto 17, length: 1500) platinum-PT > 209.59.150.117.161:  { SNMPv2c { GetResponse(35) R=20039  .1.3.6.1.2.1.1.1.0=”Linux C”} }

16:50:35.448431 IP (tos 0x0, ttl  64, id 32497, offset 0, flags [+], proto 17, length: 1500) platinum-PT > 209.59.150.117.161:  { SNMPv2c { GetResponse(35) R=20039  .1.3.6.1.2.1.1.1.0=”Linux C” }

通过抓包发现,原来真的有攻击,从抓包看,攻击是突发性质的,当有攻击时:

频率:≈ 10Hz

周期:≈ 0.1s

类型:请求 snmpd 的根信息 “Linux C”

原理:通过请求比较高级别的根内容,使系统处于高负载状态;由于频率较高,高负载状态很难消除。

恶意性:为了突破某些无状态防火墙,来源端口 sport 特意也是用了与 snmpd 服务相同的 UDP/161,很阴险。

规则检查

不过奇怪的问题来了,我的防火墙是基于状态检测的,可以轻易区分进来的报文是主动请求进来的,还是我主动发出后的回包。

既然这样,为何 snmpd 报文还是会被系统收到并处理呢?是不是 iptables 规则使用存在问题?

经查看,规则很简单,大体如下:

iptables -m state –state RELATED,ESTABLISHED -j ACCEPT

iptables -A INPUT -i lo -j ACCEPT

iptables -A INPUT -p tcp –dport 80 -j ACCEPT

iptables -A INPUT -p udp –dport 161 -s IP1 -j ACCEPT

iptables -A INPUT -p udp –dport 161 -s IP2 -j ACCEPT

iptables -A INPUT -p udp –dport 161 -s IP3 -j ACCEPT

iptables -A INPUT -j DROP

通过观察,未发现异常,针对 snmpd 报文,系统只允许了 3 个特殊 IP 访问,那么就奇怪了,这个攻击报文是怎么进来的呢?

conntrack 特性分析:UDP 与 TCP 的差异

众所周知,iptables 只是 userspace 的 controller,真正的主体是 netfilter,而 conntrack 则是 netfilter 的一个重要组成部分。

conntrack 的核心价值,就是为 Linux 实现了基于状态的防火墙。

在 Linux 中,当启用了 conntrack 后,即使是 UDP 报文,也是有“新建连接”(NEW)和“已连接”(ESTABLISHED)概念的。

不过与 TCP 不同的是,TCP 是有三次握手的,通过分析三次握手时数据报文头部的合规性可以知道当前数据是否有效。

但是,UDP 则不同,在 Linux 中,只有“去”和“回”两个概念,当系统第一次看到 UDP 包,视为 NEW,看到该包的回包后,视为 ESTABLISHED。

推理

知道了这个,大概可以猜出问题所在了,一定和 conntrack 有关。

猜测失控过程:

1、系统未启动 conntrack 时,已经有攻击报文 request 进来了

2、当系统启动 conntrack 机制时,恰好有系统回 response 包,被系统 conntrack 当做了主动发出数据,是 NEW 状态

3、系统的 iptables 规则最后有阻断功能,这个包虽然被拦掉

但后续攻击报文用同样的 SIP/SPORT 访问同样的 DIP/DPORT,导致 hash 后认为是同一条连接

此次的攻击报文被无当做上一次 NEW 状态的回包,此次该连接变成了 ESTABLISHED 状态

4、今后所有 SIP/SPORT 到 DIP/DPORT 的数据均通行无阻,导致最开始看到的场面

验证

为了证明推理是正确的,刻意写了一个 shell,在第一行 -m state –state RELATED,ESTABLISHED -j ACCEPT 后加入 sleep 以增加重现概率

实验表明,推理完全正确,UDP 攻击报文的回包被当做了 NEW,而真正的攻击则成了 ESTABLISHED。

第一句的位置,也是导致问题出现的主要原因。

尝试解决

为了杜绝这种情况的发生,思考,将 state 匹配放到最后是否可行?

答案是“不可以”,因为一样可能发生前面说的时间差导致的状态误判情况发生。

怎样做才是最稳妥的办法呢?

想了个办法:

1、先 service iptables stop

2、先写第一行规则,无条件 -j DROP 任何东西

3、写其他规则,该怎么写怎么写

4、当规则生效后等一段时间(保证此时间超过 snmpd 报文打进来后的系统响应时间),再删掉第一行规则,让数据涌进来(像开闸放水)

可惜,通过实测,攻击报文仍然可以进来,这个太奇葩了!

/etc/init.d/iptables stop 行为分析

看到上述疑点,不得不怀疑 iptables 脚本中 stop 功能的实现了。

理论上 iptables 在 stop 的时候,不仅会清除所有规则,也会删掉所有 iptables 所用到的模块,这其中也包含了 conntrack。

推理:如果 iptables 的 stop 功能工作异常,那么就无法正确卸载 conntrack,那么上述方法就无济于事了。

stop() {

# Do not stop if iptables module is not loaded.

[ -e “$PROC_IPTABLES_NAMES” ] || return 1

flush_n_delete

set_policy ACCEPT

if [ “x$IPTABLES_MODULES_UNLOAD” = “xyes” ]; then

echo -n $”Unloading $IPTABLES modules: “

ret=0

rmmod_r ${IPV}_tables

let ret+=$?;

rmmod_r ${IPV}_conntrack

let ret+=$?;

[ $ret -eq 0 ] && success || failure

echo

fi

rm -f $VAR_SUBSYS_IPTABLES

return $ret

}

红色部分是清除 conntrack 的关键语句。继续跟踪:

IPTABLES=iptables

IPV=${IPTABLES%tables} # ip for ipv4 | ip6 for ipv6

脚本最初有上述定义,也就是说,最后 IPV 的取值是 “ip”,卸载模块时卸载的是 ip_conntrack。

手动验证一下:

[root@platinum-PT ~]# modprobe ip_conntrack

[root@platinum-PT ~]# iptables -A INPUT

[root@platinum-PT ~]# /etc/init.d/iptables stop

Flushing firewall rules:                                   [  OK  ]

Setting chains to policy ACCEPT: filter                    [  OK  ]

Unloading iptables modules:                                [  OK  ]

[root@platinum-PT ~]# lsmod |grep conntrack

nf_conntrack_ipv4      22028  0

nf_conntrack           67784  1 nf_conntrack_ipv4

[root@platinum-PT ~]#

通过观察发现,conntrack 确实没有被卸载,但注意到了一点,模块名字不是 ip_conntrack 而是 nf_conntrack。

似乎明白了,验证一下:

[root@platinum-PT ~]# cat /etc/redhat-release

Red Hat Enterprise Linux AS release 4 (Nahant Update 2)

[root@platinum-PT ~]# uname -r

2.6.24.4-7

[root@platinum-PT ~]#

知道原因了:

系统是 RHEL 4U2,默认内核应该是 2.6.9,那时的 netfilter 使用的 conntrack 模块叫 ip_conntrack

系统的当前内核是 2.6.24.4,此时的 netfilter 所使用的 conntrack 模块叫 nf_conntrack 和 nf_conntrack_ipv4

由于 RHEL 4U2 的 /etc/init.d/iptables 脚本是为 2.6.9 内核写的,因此在 stop 时不能正确卸载 2.6.24.4 内核的 conntrack

卸载 conntrack 解决方案

修改

rmmod_r ${IPV}_conntrack

改为

rmmod_r nf_conntrack

因为是定制系统,未做详细的判断和动态自适应等工作。

总结

特殊时机生效的 ACL 导致 conntrack 误认为攻击报文的回包是 NEW

攻击报文恶意使用固定 sport,使 conntrack 误认为是同一个 connection

iptables 规则的逻辑问题致使穿透攻击有可能发生(虽然是小概率事件)

System script 与 kernel 的不匹配导致不能正确卸载 conntrack,使问题依然存在

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/186831.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • hd2012 素数题

    hd2012 素数题

  • cocos2d基础篇笔记四

    cocos2d基础篇笔记四

  • Commit message 和 Change log 编写指南

    Commit message 和 Change log 编写指南

  • java代码生成器,springboot代码生成器—增加更新,查询功能(持续更新)

    java代码生成器,springboot代码生成器—增加更新,查询功能(持续更新)时隔一周多,今天终于抽出时间来更新一波代码生成器,最近公司让我研究rpa,弄得焦头烂额的,话不多说,进入正题。之前有朋友让我讲一下代码生成器的原理,这篇博客就大体描述一下,以后慢慢细致讲解。双击codeMan.exe,众所周知,java做成exe程序很麻烦,在这里我是利用了.net的ikvm插件把jar包直接编译成了exe程序,这个启动界面会连接我的服务器,去检查版本更新,如果有更新就会在…

  • 软件测试外包公司有哪些_工程资料外包的坏处

    软件测试外包公司有哪些_工程资料外包的坏处一、前言:什么是软件测试外包随着最近10年创业风气的发起,已经涌起创业项目外包公司的兴起,已经不仅仅局限为了降低成本,更多的是为了解决自己雇佣技术人员或者无法管理技术人员的难题。那么外包是什么意思呢?似乎大家对外包都闻之色变!这里我们详细的认识一下什么是外包?外包类似中介派遣公司或者叫做劳务输出公司。就是我们公司把你招聘进来,但是又把你派到其他公司(甲方)工作。但是最终你的劳务合同…

    2022年10月25日
  • wps怎么做时间线_wps中的word文档如何制作时间轴「建议收藏」

    wps中的word文档如何制作时间轴很多小伙伴不知道wps中的word文档还可以制作时间轴哦,下面小编介绍一下具体办法。具体如下:1.打开一个空白的word文档,点击菜单栏的【插入】,单击选择一个带箭头的线条,在文档上面留一点空白写标题,然后插入线条拉到底部,还可以设置线条颜色,虚实等样式。2.点击工具栏中的【文本框】旁边的倒三角,再点击【多行文字】,插入一个大的文本框3.可以根据需要进行文…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号