检测“ curl – bash”服务器端的使用(2016年)

2020-12-09 19:56:27

通过从curl到bash的管道安装软件显然不是一个好主意,并且知识渊博的用户很可能会首先检查内容。因此,如果恶意有效负载仅在通过管道传输到bash时才会呈现,那不是很好吗?之前有一些人通过检查curl用户代理进行了尝试,但这绝不是故障安全的方法-用户可以简单地在命令行上卷曲url,以显示您的恶意代码。幸运的是,当将其卷曲到bash中时,curl(和wget)的行为会发生细微变化。这使得攻击者可以根据上下文提供两种不同版本的脚本:)

它并不是通过curl传递到bash时来自curl的HTTP请求看起来与通过stdout传递的HTTP请求看起来有什么不同,实际上,就所有意图而言,它们是相同的:

#curl -vv http://pluver.xqi.cc/setup.bash*在DNS缓存中找不到主机名*尝试69.28.82.189 ... *已连接到xqi.cc(69.28.82.189)端口80(#0) > GET /setup.sh HTTP / 1.1>用户代理:curl / 7.35.0>主持人:xqi.cc>接受:* / *>

关键的区别在于,bash提取大型http响应的内容所花费的时间。

bash中的执行是逐行执行的,因此bash可以吸收数据的速度受到脚本执行速度的限制。这意味着,如果我们在脚本的开头返回睡眠,则在等待睡眠执行时,TCP发送流将暂停。可以检测到此暂停并将其用于呈现不同的内容流。

不幸的是,这不仅是将socket.send(" sleep 10")包装在计时器中并等待发送调用以阻塞的简单情况。 linux中的发送和接收TCP流在每个套接字的基础上进行缓冲,因此在发送数据的调用被阻塞之前,我们必须填充这些缓冲区。我们知道当接收客户端回复窗口大小标志设置为0(wireshark中的Win = 0)时,缓冲区已满。

为了检测执行中的暂停,我们需要在bash进行bash之前填充所有缓冲区。来自HTTP响应的数据流如下所示:

在Linux上,发送和接收缓冲区的大小都是"自动调整的"每个套接字,这意味着它们的大小可能会有所不同(请检查/ proc / sys / net / ipv4 / tcp_rmem和/ proc / sys / net / ipv4 / tcp_wmem以查看大小)。我们可以在服务器端控制发送缓冲区,但是不能对接收缓冲区做任何事情。通过固定发送缓冲区的大小,我们可以减少从客户端接收到的窗口大小为0之前需要发送的数据量的总体差异。较小的固定大小的发送缓冲区有助于防止TCP接收缓冲区增大。

缓冲区大小可以这样设置(Ubunty 14.04 LTS的默认值为87380)

在Ubuntu上进行测试时,您需要发送大约1mb的数据以填充接收缓冲区-取消对发送缓冲区的限制,这很容易加倍。问题是,作为curl请求填充TCP缓冲区的内容是什么,而没有bash管道将在控制台中呈现。

真正可以用来填充缓冲区的唯一字符是一个空字节,因为在大多数控制台中它不会呈现。当指定字符集text / html时,它也不会在chrome中呈现。我们不知道内容长度数据是通过分块编码传输的,每个分块都是一个空字节字符串,大小与TCP发送缓冲区相同。

HTTP / 1 .1 200 OK主机:xqi .cc传输类型:分块内容类型:text / html;字符集= us-ascii睡眠10< -块#1 0x0000000000000000000000000000000000 ... -块#2 0x0000000000000000000000000000000000 ... ... -块#3 0x0000000000000000000000000000000000 ... ... -块#4 ...

如果您绘制每个块之间发送的时间的图表,并针对这两种情况进行此操作,则很容易确定哪些输出通过bash传递。卷曲bash,您可以在执行sleep命令时看到不到10秒的跳跃(确切位置根据客户端tcp接收缓冲区的大小而有所不同)。

只要服务器和客户端之间的连接稳定,就可以很好地将sleep命令减少到不到一秒,也可以将延迟伪装成另一个慢命令(ping,find等)。只要服务器能够检测到累积传输时间中的突然跳跃,命令运行所需的确切时间就无关紧要。

可以通过获取块传输之间的时间差异,找到最大值,将其从列表中删除,计算剩余数据的方差并确保两者的方差都很小(这意味着稳定的连接)来识别这种独特的模式。和最大的差异是高的。如果识别出此模式,则可以发送另一个包含恶意脚本的http块。

将所有内容放在一起,最终得到一台基于python的小型服务器,该服务器可以根据传递的内容传递不同的有效负载(这也适用于" wget -o / dev / null -O-") 。如果由于某种原因连接不可靠(差异很大)或您通过浏览器请求文件,则非恶意负载将显示:

那么,如何检测服务器是否正在执行此操作?如果检测是通过简单的延迟完成的,则可以尝试寻找包含大量填充的大型脚本,或者执行以下操作:

但是,这绝不是傻瓜,因为攻击者可以使用其他方法(例如http / dns回调)或设置多个被动延迟。更好的解决方案是永远不要将不受信任的数据流传输到bash中。如果您仍然想运行不受信任的bash脚本,更好的方法是将URL的内容通过管道传输到文件中,检查磁盘上的内容,然后再执行它。