by Ryat
http://www.wolvez.org
2008-2-22
引用:
本地文件包含漏洞是PHP中比较常见的漏洞,像下面的代码:
include('inc/'.$_GET['a'].'/global.php');
这是个典型的文件包含漏洞,但要想包含任意文件的话需要引入NULL字符截断后面的'/global.php',但在gpc为on的情况下null是会被转义的,这往往成了本地文件包含漏洞利用的束缚(在一些特定的情况下也可以用其他方法截断后面的代码,见:http://www.wolvez.org/forum/thread-55-1-1.html)
其实文件包含分为include()和 require()两种,先看下手册中对这两种方式区别的描述:
这两种结构除了在如何处理失败之外完全一样,
手册中对两种方式的区别说的很清楚,而include()的这种对待包含失败的处理方式有时会给我们在利用本地文件包含漏洞上提供一些其他的思路,看下下面的代码片断:
...
if (!empty($_COOKIE["userlanguage"]) && file_exists("lang/" . basename($_COOKIE["userlanguage"]) . "/global.php")) $language = $_COOKIE["userlanguage"];
...
include_once("lang/$language/index.php");
...
$template = preg_replace("/\{lang\s+(.+?)\}/ies", "languagevar('\\1')", $template);
...
fwrite($fp, $template);
...
function languagevar($var) {
if(isset($GLOBALS['lang'][$var])) {
return $GLOBALS['lang'][$var];
} else {
return "!$var!";
}
}
...
简单说下代码的处理流程,程序根据浏览者选择的语言把相应的$lang写进模板缓存,当浏览者访问时直接访问模板缓存,include()本地文件包含漏洞随想》(https://www.unjs.com)。
而这里可以通过$_COOKIE["userlanguage"]触发本地文件包含漏洞,这样提交:
../../[file][null char]/eng
通过basename()返回eng,而/lang/eng/global.php是存在的,绕过了file_exists()的检查,成功触发了本地文件包含漏洞,但这里需要GPC为OFF,因为要引入NULL字符截断后面的字符串。貌似利用很困难,但我们可以转换下思路,这里include_once()正确包含的话会包含语言文件,语言文件里面定义了$lang,这里是关键了,我们只要随便提交$_COOKIE["userlanguage"],使include_once()无法正确包含,而前面提到include()即使包含失败,脚本依旧会向下执行,这样没有包含语言文件,$lang就是没有初始化的了,那么在register_globals为on或用了extract()的情况下,我们就可以自行提交$lang了,然后通过fwrite()写入了缓存文件:)
其实这个思路就是把include()本地文件包含漏洞转化为其他漏洞,是个典型的二次攻击:)