当前位置: 首页 > news >正文

XCTF-warmup详细题解(含思考过程)

一、题目来源

XCTF-Web-warmup

在这里插入图片描述

二、信息搜集

进入场景后,映入眼帘的是一张滑稽图

替代文本

ctrl+u看一下源码,查看是否存在“敏感信息泄露”的现象

在这里插入图片描述
果然存在,访问一下该文件:

http://ip:端口/source.php

可以看到出现了一段后端代码(用php写的)

<?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist = ["source"=>"source.php","hint"=>"hint.php"];if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}if (in_array($page, $whitelist)) {return true;}$_page = mb_substr($page,0,mb_strpos($page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;}}if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])) {include $_REQUEST['file'];exit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}  
?>

三、代码审计

既然有了源码信息,我们就可以对代码进行分析

我们先不管上面的类,看到代码的主体部分,即:

if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])
) {include $_REQUEST['file'];exit;
} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
} 

一眼就可以看到关键函数include,并且里面的参数是用户可控的(通过REQUEST传值)

因此,存在文件包含漏洞

但是要够着这个函数,需要满足三个判断条件,分别是

  • file参数不为空
  • file接受的参数需要是字符串
  • emmm类的checkFile方法其返回值需要为1

如果不满足,就会显示滑稽图,这也就是为什么我们一开始进入会出现滑稽的根本原因(没有传值给file)

好,现在我们就可以回过头去看emmm类了

该类中有且仅有一个方法,就是checkFile(),且该方法的参数值就是我们通过REQUEST传值给file的值

它首先列出来白名单列表:

$whitelist = ["source"=>"source.php","hint"=>"hint.php"];

到这其实就可以大致猜测出来该方法的用途,就是检查我们输入的文件名是否合法

那么,它列举出来的官方文件有且仅有:

  • source.php
  • hint.php

第一个文件我们看过了,直接看第二个文件

http://ip:端口/hint.php
或者直接:
http://ip:端口/?file=hint.php

可以看到一段提示:

flag not here, and flag in ffffllllaaaagggg

说明我们最终要找的flag存储在ffffllllaaaagggg文件中

大家不要因“无后缀”的问题而感到疑惑,在Linux操作系统中是不根据文件后缀名来判断文件类型的
因此,没有后缀名是常有的事情

但是,很明显,该文件是不属于白名单里面的

因此,我们继续分析后面的代码

if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;
}

他会检测我们是否输入信息,如果没有或者不为字符串,就会直接退出且返回false

这点只要我们正常输入文件就不会符合该判断,接着看后面

if (in_array($page, $whitelist)) {return true;
}

会判断我们的输入信息是否在白名单内,如果在就返回true,否则继续

按照正常的逻辑来说,此次判断结束后会直接跟上一个:

return false;

直接发挥白名单真正的作用,但是它并没有这么做

而是会再经过几个判断(且该判断又返回true的希望)最后再到达false逻辑

替代文本

这就变相给了攻击者很多的机会

假设,我们现在输入就是ffffllllaaaagggg,当前这个判断是不满足的,会继续后面的逻辑,还有机会,我们接着看

在下一个判断之前,会多一个步骤:

$_page = mb_substr($page,0,mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {return true;
}

首先,我们来了解一下mb_substrmb_strpos两个函数

mb_strpos(string $haystack,string $needle,int $offset = 0,?string $encoding = null
): int|false

该函数会查找$needle$haystack中第一次出现的位置(下标位置)

比如mb_strpos("abc","c");的返回值就是2

 mb_substr($str,$start,$length);

该函数会输出从$str$start下标开始的长度为$length的字符串

比如:

<?php
echo mb_substr("abc", 0, 2);
// 输出ab
?>

我们将我们的假想输入“ffffllllaaaagggg”带进去看一看

//根据输入改写代码成:
$_page = mb_substr("ffffllllaaaagggg",0,mb_strpos('ffffllllaaaagggg?', '?')
);

最后的输出就是:ffffllllaaaagggg

很明显,经过转换后还是不能满足下述判断:

if (in_array($_page, $whitelist)) {return true;
}

但是我们已经知道,这里会对“?”作为截取部分的分隔符,先留个心眼,继续看后面的判断

$_page = urldecode($page);
$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {return true;
}

与上一个判断不同的是,这里多出来了一个urldecode

其他的逻辑基本不变,无非是那两个函数的对象变成了"$_page"而不是原本的"$_page"

很明显,如果我们不改变我们的假想输入,那么结果还是一样

四、Payload构造

知道了检查文件的逻辑,我们就可以开始构造payload了

非常明确的几个细节就是:

  • payload中得有关键文件ffffllllaaaagggg
  • 得拿“?”做文章

我们观察到,每次使用函数mb_strpos它都会手动在末尾帮我们拼接(“.”)上一个“?”

换言之,只要我们输入的内容本身就携带"?"就会截断该问号前面的内容,保留后面的内容

而根据我们之前的分析,他们的判断都是针对"?"前面的内容进行判断的,但是include()的参数却是整体的内容

那么我们的payload可不可以是这样的形式:

payload = "白名单内容?xxxxx"

我们只要让其满足:

  • 前面用于白名单判断
  • 整体作为一个正确的文件路径,且能导向到文件ffffllllaaaagggg

因此,我们的payload由此而生:

payload = "source.php?/../../../../ffffllllaaaagggg"

这样的payload,虽然绕不过第一个判断,但是第二、第三个判断都是可以符合的

因为,根据判断逻辑,他只会截取第一个问号前面的数据,即source.php

因而,函数返回为true,使得该payload成功进入文件包含逻辑

而"source.php?"这个整体会被当成一个文件名作为文件路径的一部分

这里可能会有疑问
当我们输入:
http://ip:端口/?file=source.php?/../../../../ffffllllaaaagggg
的时候
浏览器会自动帮我们进行URL编码,但是在此处,编码后的结果还是其本身
在后端被file接受的时候,file接收到的还是“source.php?/../../../../ffffllllaaaagggg
这里大家也可以手搓测试代码验证一下(测试代码如下)

<?php$file = $_GET['file'];echo $file;
?>

结果:
在这里插入图片描述
为什么“?”也被作为我们输入内容的一部分呢?
这就是因为“?”在URL中的作用是:分隔路径与查询参数
因此这里的"?“很明显会被误以为source.php还有传输参数的必要,因此作为正常语法逻辑被传输进来了
但是后续我们通过在”?"后加上一个“/”把“source.php?”完整地作为了一个文件名而存在了

后面的“…/”就是回到上级目录,多个“…/”就可以让目录直接返回到根目录的位置,实现目录穿越的目的

因此我们只要构造URL为:

http://ip:端口/?file=source.php?/../../../../ffffllllaaaagggg

即可成功得到flag!

在这里插入图片描述

http://www.xdnf.cn/news/1295749.html

相关文章:

  • Morph Studio-一站式AI视频创作平台
  • Vue浅学
  • Elasticsearch 中如何配置 RBAC 权限-实现安全的访问控制
  • QT6(创建第一个QT项目)
  • Win10上Qt使用Libcurl库
  • Qt 实现Ymodem协议源码分享
  • MySQL工具包中的其他程序
  • 从概率填充到置信度校准:GPT-5如何从底层重构AI的“诚实”机制
  • 树莓派 4B 上部署 Minecraft PaperMC 1.20.x 的一键部署脚本
  • ASQA: 面向模糊性事实问题的长格式问答数据集与评估框架
  • C#WPF实战出真汁02--登录界面设计
  • 利用 Python 爬虫按图搜索 1688 商品(拍立淘)实战指南
  • Windows批处理脚本自动合并当前目录下由You-get下载的未合并的音视频文件
  • LeetCode 分类刷题:2302. 统计得分小于 K 的子数组数目
  • 我的第一个开源项目-jenkins集成k8s项目
  • 开疆智能Ethernet转ModbusTCP网关连接UR机器人配置案例
  • 区块链 + 域名Web3时代域名投资的新风口(上)
  • 《算法导论》第 25 章:所有结点对的最短路径问题
  • 常见的tls检测的绕过方案
  • Mybatis学习笔记(二)
  • Transformer之多头注意力机制和位置编码(二)
  • vue更改style
  • 双椒派E2000D网络故障排查指南
  • 【Linux】库制作与原理
  • 2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(三)
  • 苹果正计划大举进军人工智能硬件领域
  • 解决EKS中KEDA访问AWS SQS权限问题:完整的IRSA配置指南
  • 能源行业数字化转型:边缘计算网关在油田场景的深度应用
  • 支持pcm语音文件缓存顺序播放
  • 从感知到执行:人形机器人低延迟视频传输与多模态同步方案解析