前言
网站开发者在更新代码的时候,经常会给重要文件做备份,常用的后缀有:
.bak(手动备份时最常用).swp(Vim 编辑器自动生成的交换文件).~(临时备份).txt(纯文本备份)
这些备份文件如果被遗忘在服务器上,就会成为泄露源码的入口。
一、题目
二、解题步骤:
- 根据题目“备份是个好习惯”指向了备份文件泄漏的考点。目标就是找到并下载这个备份文件。
- 输入/index.php.bak,下载了一个文件。
- 查看文件,分析代码
<?php
/* Created by PhpStorm.
* User: Norse
* Date: 2017/8/6
* Time: 20:22
*/
include_once "flag.php"; // 引入包含flag的文件(隐藏不输出)
ini_set("display_errors", 0); // 关闭错误显示,防止暴露关键信息
$str = strstr($_SERVER['REQUEST_URI'], '?'); // 从URL中截取?及其后面的内容,比如访问/?abc=123就得到"?abc=123"
$str = substr($str,1); // 去掉开头的?,得到纯参数字符串,比如"abc=123"
$str = str_replace('key','',$str); // 把参数字符串里所有的"key"都替换成空
parse_str($str); // 把处理后的参数字符串解析成PHP变量,比如"key1=xxx"会生成变量$key1,值为xxx
echo md5($key1); // 输出$key1的MD5值(用于调试看结果)
echo md5($key2); // 输出$key2的MD5值(用于调试看结果)
if(md5($key1) == md5($key2) && $key1 !== $key2){ // 核心判断:MD5值弱比较相等,但两个变量本身强比较不相等
echo $flag."取得flag"; // 满足条件就输出flag
}
?>
这段代码的核心是 str_replace('key','',$str) 的替换逻辑。
str_replace('key','',$str) 会把你传的参数里所有 key 字符串都删掉,所以我们要传一个参数名,删掉 key 后正好是 key1 或 key2。
比如:
- 传
kkey1=xxx→ 替换掉key后变成k1=xxx→ 不行 - 传
keykey1=xxx→ 替换掉key→ 变成1=xxx→不行 - 传
kkeyey1=xxx→ 替换掉key后变成key1=xxx→ 行
我们可以通过构造参数名,让它在替换后变成 key1 和 key2,从而绕过替换规则,再用数组或0e字符串让MD5值相等,最终拿到flag。
- 构造Payload,需要让
key1和key2的MD5值相等但本身不等,直接用 0e 字符串 或者 数组绕过:
方法1:0e字符串
<http://171.80.2.169:11186//?kkeyey1=QNKCDZO&kkeyey2=240610708>
QNKCDZO的MD5是0e830400451993494058024219903391240610708的MD5是0e462097431906509019562988736854- PHP弱比较
==会把这两个0e开头的字符串都解析为0,所以条件成立
方法2:数组绕过
<http://171.80.2.169:11186/>
- PHP的
md5()处理数组会返回NULL - 所以
md5($key1) == md5($key2)→NULL == NULL - 同时
$key1 !== $key2→ 数组[1]不等于数组[2],满足所有条件