nginx文件類型錯誤解析漏洞
www.xxx.com/1.jpg
內容爲PHP 代碼,如
<?php
phpinfo();
?>
後面加任意 .php
www.xxx.com/1.jpg/xxx.php
致使代碼被執行
php.ini
cgi.fix_pathinfo=1
PHP_INI_ALL 從 PHP 4.3.0 起可用 請注意:默認爲1
二者訪問時的區別
www.xxx.com/1.jpg
HTTP/1.1 200 OK
Server: nginx/版本
Date: XXX
Content-Type: text/plain
Content-Length: XX
Last-Modified: XX
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes
www.xxx.com/1.jpg/xxx.php
HTTP/1.1 200 OK
Server: nginx/版本
Date: XXX
Content-Type: text/html
Content-Length: XX
Last-Modified: XX
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes
就在Content-Type: text/plain與Content-Type: text/html
若是 jpg 是普通文件,內容直接顯示,但如內容是php代碼就杯具了,代碼直接執行
即便是最普通的配置
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
漏洞一樣會出現,實際和 nginx關係,nginx 只是個 Proxy,只負責根據用戶的配置文件,經過 fastcgi_param 指令將參數忠實地傳遞給 FastCGI Server,問題在於 FastCGI Server 如何處理 nginx 提供的參數
http://xx.com/foo.jpg/a.php/b.php/c.php
nginx 傳遞給 FastCGI 的 SCRIPT_FILENAME 的值爲:
/foo.jpg/a.php/b.php/c.php
也就是 $_SERVER['ORIG_SCRIPT_FILENAME']
php.ini 中 cgi.fix_pathinfo = 1 時,PHP CGI 以 / 爲分隔符號從後向前依次檢查以下路徑:
/foo.jpg/a.php/b.php/c.php
/foo.jpg/a.php/b.php
/foo.jpg/a.php
/foo.jpg
直到找個某個存在的文件,若是這個文件是個非法的文件,悲劇
PHP 會把這個文件當成 cgi 腳本執行,並賦值路徑給 CGI 環境變量——SCRIPT_FILENAME,也就是 $_SERVER['SCRIPT_FILENAME'] 的值
解決辦法
1,上傳時代碼判斷文件類型
2, nginx 解析
如
if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}
http://www.54chen.com/php-tech/nginx-php-cgi-of-security-hole.html
http://www.st0p.org/blog/tag/cgi-fix_pathinfo