记一个parse_url的漏洞
前言
这是在做moeCTF招新时所积累的一个知识,记下来以作为本菜鸡的一点知识储备,以下是原代码:
源码
<?php
include "config.php";
$number1 = rand(1,100000000000000);
$number2 = rand(1,100000000000);
$number3 = rand(1,100000000);
$url = urldecode($_SERVER['REQUEST_URI']);
$url = parse_url($url, PHP_URL_QUERY);
if (preg_match("/_/i", $url))
{
die("...");
}
if (preg_match("/0/i", $url))
{
die("...");
}
if (preg_match("/\w+/i", $url))
{
die("...");
}
if(isset($_GET['_']) && !empty($_GET['_']))
{
$control = $_GET['_'];
if(!in_array($control, array(0,$number1)))
{
die("fail1");
}
if(!in_array($control, array(0,$number2)))
{
die("fail2");
}
if(!in_array($control, array(0,$number3)))
{
die("fail3");
}
echo $flag;
}
show_source(__FILE__);
?>
分析
这里有两个关键点:
- 绕过前三个正则 ->运用parse_url()的漏洞
- 绕过in_array的三个判断 -> PHP弱类型
第二个关键点可以通过传入 _=A 来绕过,因为当传入为字符串时,由于PHP弱类型,会将字符串转换为数字0而满足条件
而第一个关键点则是需要运用parse_url()的漏洞来解决
查找资料后,翻到了chu师傅的博客,这是他博客的链接
简单的来说,就是如果url是以//开始的,则他会认为它是相对 url,而后认为 url 的部件从 url+2 开始
如果 url 为 ///x.php,则 p = e = s = s + 2(查chu师傅博客或者去查PHP手册),函数将返回 NULL。
所以可以构造以下URL来完成绕过:
http://120.77.152.169:8088///index.php?\_=a