眼见不为实,curl | bash 带来的安全问题

之前在 timeline 上看到一篇 2016 年的老文章 Detecting the use of “curl | bash” server side档案馆备份),指出从服务器端可以检测出客户端是在用 curl 拉脚本还是在用 curl | bash 边拉边执行。如果检测到后者,可以返回不同脚本的内容以达到 “加料” 的效果。整个 blog 都干货满满,就是很久没更新了,站点开了 HSTS,(2023 年 3 月 12 日后)还不更新证书,正好让我学到了 Chrome(v111)在证书错误且不能跳过的警告界面盲敲 “thisisunsafe” 就可以强制跳过…

HTTP 是被 TCP 一块儿一块儿驮着在服务器端和客户端之间传输的,服务器端和客户端各有一块缓冲区,这里服务器端得先把己方发送缓冲区固定住。脚本的第一行可以用一条比较耗(客户端的)时的命令如 pingfind 等,文章 demo 的 py 脚本中以 sleep 3 为例,在此之后立即输出一大堆 NUL 空字符给客户端(使用 NUL 的原因是不会把命令行或浏览器弄得乱糟糟,但是可以被抓包或 curl --output 看到),每个 chunk 都与当前 Linux 系统的发送缓冲区大小相当,此时:

  • 如果客户端是在用 curl 拉脚本,由于缓冲区大小被定住了,那么每个 chunk 的发送间隔应该差不多,因为不管脚本里面写了什么,curl 只是当文本拉下来;
  • 如果客户端在用 curl 边拉边交给 bash 执行,由于 bash 执行东西是一行一行的,上面的 sleep 3 被拉下来交给 bash 执行要停止传输 3 秒,服务器端就会检测到有那么一个 chunk 传输间隔时间明显超出其他 chunk 。

因为要排除网络波动的原因,demo 脚本中还使用了 numpy 库中的 std 求标准差的方法来进行统计运算,当找到那个偏离平均值很大的传输间隔时则认为客户端在用 curl | bash 。文中也指出客户端可以使用 curl | (sleep 3; cat) 来反制服务器端的上述行为。其实 curlwget 拉下来看清楚再在本地执行就可以应对以上问题。

又是一个连自己的眼睛都不能相信的案例。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注