ez_include_revernge暨ez_include

芝士:file_get_contents函数针对data:协议仍然可以进行解析为data封装协议,而include在遇到data:的格式则会由于格式问题返回NULL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
stream_wrapper_unregister('php');

if (!isset($_GET['no_hl'])) highlight_file(__FILE__);

$mkdir = function($dir) {
system('mkdir -- ' . escapeshellarg($dir));
};

$randFolder = bin2hex(random_bytes(16));
$mkdir('users/' . $randFolder);
chdir('users/' . $randFolder);

$userFolder = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']);
$userFolder = basename(str_replace(['.', '-'], ['', ''], $userFolder));

$mkdir($userFolder);
chdir($userFolder);
file_put_contents('profile', print_r($_SERVER, true));
chdir('..');

$_GET['page'] = str_replace('.', '', $_GET['page']);

if (!stripos(file_get_contents($_GET['page']), '<?') && !stripos(file_get_contents($_GET['page']), 'php')) {
if (preg_match('/f.*l.*a.*g/i', $_GET['page'])) {
echo "这次不会让你得逞了!";
} else {
include($_GET['page']);
}
} else {
echo "再想想?";
}

chdir(__DIR__);
system('rm -rf users/' . $randFolder);
?>

从代码来看我们可以知道,定义了一个$mkdir函数会进行创建目录,首先是在当前工作目录创建一个users/[random_bytes(16)]目录并移动工作目录到该目录,随后会尝试获取到HTTP_X_FORWARDED_FOR,也就是请求头中的XFF头作为目录名,如果为空或没有就会获取REMOTE_ADDR,创建目录后继续进入该目录并将$_SERVER全局变量写入profile文件,最后返回上级目录

所以,把xff里面写上data:,a当做目录名字然后接着创建profile,由于对协议处理方式不同,file_get_content函数在遇到data:,a/profile的时候会尝试获取a/profile的文件内容,但是内容为空,所以绕过验证,而include函数在遇到data:,a/profile的时候无法正常的解析data协议,从而直接查找data:,a/profile文件并解析,所以我们在XFF头中设置文件目录为data:,a就可以正常写入了

然后在ua头上执行代码读flag
<?php system('cat /flag');?>
回显

ez_include:非预期解:
?page=/flag
否则像ez_include_revernge一样解就行了

锦家有什么

这是一道没有过滤的ssti模版注入
打开首页点击开始挑战没什么反应,查看源码发现提示,于是访问路径
发现要猜测参数,一般参数会是:

1
2
3
4
5
6
7
8
9
10
11
12
13
?name=
?msg=
?content=
?data=
?text=
?str=
?input=
?show=
?view=
?title=
?user=
?username=
?info=

逐个尝试即可,就是name,然后进行测试,
?name={{7*7}}
返回49,存在模版注入

然后先用通用解试试看看有没有过滤什么的:

1
{{lipsum.__globals__['os'].popen('cat /flag').read()}}

正常解
或者利用焚境自动化解:
fenjing webui
fen
jing

眼见不一定为实

打开就看到说与flask和nginx有关,还与url解析有关,那么可以网上搜一下:
参考连接:https://xz.aliyun.com/news/18629

这是Nginx Unicode 规范化解析绕过
其实,就是利用nginx与flask解析差异利用,正如wp所说的
wp

我们先来看一下给的附件源码:
源码

发现需要访问/secret但是有过滤。
这个 Nginx 配置存在路径解析绕过漏洞,主要原因在于 Nginx 的正则匹配规则与实际路径处理逻辑之间存在不一致性。

  1. 正则匹配的局限性:配置中使用的正则表达式^/secret/?$和^/secret/看似能覆盖所有与/secret相关的路径,但没有考虑到特殊 Unicode 字符的情况。

  2. Nginx 的 Unicode 字符处理机制:Nginx 在处理 URL 中的某些 Unicode 字符时,会将其规范化或忽略,而正则匹配则是基于原始字符进行的。这种差异导致攻击者可以构造特殊 URL,既能够绕过 Nginx 的正则匹配,又能被正确解析为/secret路径。

  3. 关键漏洞点:当请求中包含某些特殊 Unicode 字符时,例如 U+2026(水平省略号…)、U+0085(下一行字符)等,Nginx 的正则匹配会认为这不是/secret路径而允许访问,但其内部路径解析机制会忽略这些特殊字符,最终仍然将请求转发到/secret路径。

如图:
bp1
bp2

将secret后面替换成\x85来绕过,即可访问到获得flag

[玄武杯 2025]normal_php

第一关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 <?php 
highlight_file(__FILE__);
error_reporting(0);
include 'next.php';

if(isset($_GET['a']) && isset($_POST['c'])){
$a=$_GET['a'];
$c=$_POST['c'];
parse_str($a,$b);
if($b['cdusec']!==$c && md5($b['cdusec'])==md5($c)){
$num1=$b['num'][0];
$num2=$b['num'][1];

if(in_array(10520,$b['num'])){
echo "记住这个数";
echo "<br>";
}else{
die("这都记不住?");
}

if($num2==114514){
die("我不想要这个数字!");
}

if(preg_match("/[a-z]/i", $num2)){
die("还想十六进制绕过?");
}

if(strpos($num2, "0")){
die("还想八进制绕过?");
}

if(intval($num2,0)==114514){
echo "好了你可以去下一关了".$next;
}else{
echo "我现在又想要了,嘻嘻";
}

}else{
echo "不er,md5你不会";
}

}else{
echo "你看看传什么呢";
}

parse_str函数:把传入的字符串解析根据&分开
1.md5过滤:

  • 0e开头弱相等绕过:
    1
    2
    3
    4
    5
    240610708
    s878926199a
    s155964671a
    s214587387a
    s214587387a
  • 数组绕过:
    1
    POST:c[]=2

2.数字in_array:num[0]=10520
3.intval($num2,0)==114514: intval()函数绕过方式有很多,比如8或16进制,增加小数点,拼接字符串,所以这里就令:num[1]=114514.1
第一关

第二关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 <?php

#flag在/flag中,试着读读?

error_reporting(0);

if(isset($_GET['filename'])){
$file=$_GET['filename'];
if(!preg_match("/flag|php|filter|base64|text|read|resource|\=|\'|\"|\,/",$file)){
include($file);
}
}else{
highlight_file(__FILE__);
}

过滤的比较多,一般include要么直接包含文件,要么伪协议,要么日志包含
这里直接包含肯定不行,伪协议的话=被过滤了,用日志包含:
分为两个版本的:

1
2
/var/log/nginx/access.log
/var/log/apache2/access.log

又因为日志包含把整个请求头都会记录,include会执行里面的php代码,所以在ua头里面写
第二关

还有两题不会

官方wp链接:https://wanth3f1ag.top/2025/11/02/2025%E7%8E%84%E6%AD%A6%E6%9D%AF%E5%87%BA%E9%A2%98%E8%AE%B0%E5%BD%95/