当前位置:首页 > 时尚

CGI攻击

一个没做任何过滤的留言板,攻击者提交这样一行内容:; cat /etc/passwd。服务器端脚本用系统调用执行了它,密码文件的内容直接出现在HTTP响应里。这不是什么高深漏洞,就是CGI最经典的翻车方式。

CGI,Common Gateway Interface,说白了就是Web服务器跟外部程序之间的一个约定。浏览器发请求,服务器把参数丢给一个可执行程序,程序跑完把结果吐回来。1993年那会儿,这东西是动态网页的唯一方案。NCSA HTTPd配上Perl脚本,几乎就是早期互联网的标配。问题在于,那个年代的开发者对"用户输入"这四个字基本没有敬畏心。

最臭名昭著的案例是1996年phf漏洞。NCSA HTTPd自带一个叫phf的示例CGI脚本,用来做一个电话簿查询。脚本里直接把用户传的参数拼进系统命令,连基本的转义都没做。攻击者构造一个带换行符的请求,就能在服务器上执行任意命令。这个漏洞影响了几十万台服务器,CERT专门发了安全公告。更讽刺的是,这个脚本本身只是个demo,很多人装完服务器根本没删。

你可能会想,都什么年代了,还聊CGI?但事情没那么简单。CGI本身不是漏洞,它只是一种架构模式。今天你用的很多框架,底层逻辑跟CGI如出一辙——接收请求、调用处理程序、返回响应。区别在于,现代框架通常有参数化查询、输入验证、模板引擎这些防护层。而当年那些CGI脚本,等于把这些防护全部裸奔。

我翻过一些老代码仓库,1990年代末的Perl CGI脚本有个共同特征:system()和反引号用得极其随意。有个做文件下载的脚本,直接把用户传的文件名拼进open()调用,连路径穿越都不防。攻击者传../../etc/shadow就能读到影子文件。这种写法在当时不算粗心,算常态。整个行业还没有"不可信输入"这个概念。

CGI攻击的核心就一句话:用户能控制的数据,流进了不该流进的地方。可能是shell命令、可能是SQL语句、可能是文件路径。用今天的话说,叫注入。用当年的话说,叫"这脚本怎么又挂了"。

2000年以后,FastCGI、mod_perl、PHP的SAPI模式逐渐取代了传统CGI。性能是一方面,每次请求都fork一个进程确实扛不住。但安全模型的改善是另一回事——语言层面开始内置转义函数,框架开始提供参数绑定,WAF开始拦截可疑payload。CGI时代那种"裸拼字符串"的写法,慢慢变成了反面教材。

不过老系统没那么容易死。2014年Shellshock爆发的时候,大量暴露在公网的CGI接口成了重灾区。Bash的环境变量解析漏洞,配合CGI的调用方式,攻击者只需要在User-Agent里塞一段恶意函数定义就能拿到shell。这距离phf漏洞已经过去了18年。那些没人维护的老旧CGI脚本,像化石一样埋在服务器里,等着被挖出来。

写CGI脚本的人当年未必不懂安全——他们只是没觉得这是个问题。那个年代,Web服务器大多跑在内部网络,用户都是"自己人"。谁能想到后来互联网会长成这个样子。这大概也是安全领域的一个规律:今天你觉得无所谓的信任假设,十年后可能就是CVE列表上的常客。

分享到: