[GDOUCTF 2023]受不了一点

[GDOUCTF 2023]受不了一点

题目来源:nssctf

题目类型:web

涉及考点:PHP弱比较

1. 直接做代码审计

<?php
error_reporting(0);
header("Content-type:text/html;charset=utf-8");
if(isset($_POST['gdou'])&&isset($_POST['ctf'])){
    $b=$_POST['ctf'];
    $a=$_POST['gdou'];
    if($_POST['gdou']!=$_POST['ctf'] && md5($a)===md5($b)){
        if(isset($_COOKIE['cookie'])){
           if ($_COOKIE['cookie']=='j0k3r'){
               if(isset($_GET['aaa']) && isset($_GET['bbb'])){
                  $aaa=$_GET['aaa'];
                  $bbb=$_GET['bbb'];
                 if($aaa==114514 && $bbb==114514 && $aaa!=$bbb){
                   $give = 'cancanwordflag';
                   $get ='hacker!';
                   if(isset($_GET['flag']) && isset($_POST['flag'])){
                         die($give);
                    }
                   if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
                       die($get);
                    }
                    foreach ($_POST as $key => $value) {
                        $$key = $value;
                   }
                    foreach ($_GET as $key => $value) {
                         $$key = $$value;
                    }
                   echo $flag;
            }else{
                  echo "洗洗睡吧";
                 }
    }else{
        echo "行不行啊细狗";
        }
  }
}
else {
  echo '菜菜';
}
}else{
  echo "就这?";
}
}else{
  echo "别来沾边";
}
?>
  • 一个个看吧,第一个if,要求POST传入两个参数gdouctf,且两者值不相等,但md5值相等。

这里涉及到md5绕过,对于要求md5强相等的题目,这里给出一对碰撞:

$s1 = "%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab"
$s2 = "%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab"

这里介绍另一种方法,数组绕过

即在php中,函数md5($a)内,若$a是一个数组,则函数返回值为null,因此我们可以构造gdou[]=1 & ctf[]=2

  • 第二个if就要求COOKIE传入cookie=j0k3r,没什么好说的
  • 第三个if要求GET传入aaabbb,两者值都为114514,但需要弱比较不等,因此构造aaa=114514 & bbb=114514a

弱比较请自行查阅

  • 最后一串if,需要用到变量覆盖,这里看到大佬的payload是123=flag&flag=123

个人理解是这样的,若有问题望指正:

  1. 先是需要绕过if(isset($_GET['flag']) && isset($_POST['flag'])),即不能传入flag,因此用123作为变量名(猜测应该是顺序检测的?即此处检测到传入了123=flag,那么后面的flag=123就被绕过了?)
  2. 其次是绕过if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'),这里需要$flag=flag,根据上面的payload,我们知道$123flag还给了$flag
  3. 两个foreach()是用来做循环的,即:将GET或POST获得的参数分别给到$key$value,作为键值对,再进行循环体内的操作。例如传入的123=flag,那么就有$key=123 & $value=flag
  4. 这里没有用POST,也就是第一个foreach(),而是使用第二个foreach(),即利用GET传参。原因是,在第二个循环体内,有:$$key = $$value;$$相当于一个套娃,例如:
$a = 1;
$$a = 2;
那么$$a就相当于$1
  1. 根据上述说到的,将GET传入的参数作为键值对,那么第一次循环就有$key = 123 & $value = flag,在循环体内就有$$key = $$value,也就是$123 = $flag,这一步将最后我们需要echo的变量$flag暂存到了变量$123里;而第二次循环有$key = flag & $value = 123,在循环体内相当于$flag = $123,也就是将$flag的原先值还给了$flag
  2. 但是有个问题是,$flag本身就没变过值,为什么还要绕一步呢?不是太明白这里出题人想考什么,我试着传入flag=,令其为空去绕过if(isset($_GET['flag']) && isset($_POST['flag'])),结果它同时也绕过了if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'),但最终因为foreach() 的作用,导致$flag为空而无回显了

这里有想法的师傅可以评论区留言~~

2. 构造payload

根据上述分析,我们用bp抓包传参:

拿到flag:

NSSCTF{2615da6d-011c-4088-a9e6-1cf90915b12f}

日期:2023.8.29

作者:y0Zero

posted @ 2023-08-29 21:13  y0Zero  阅读(346)  评论(0编辑  收藏  举报