CTF Web安全

CTF PHP代码审计中的一题任意URL跳转

Posted on 2020-01-02,2 min read

源代码

<?php
class Redirect {
    private $websiteHost = 'www.example.com';
    private function setHeaders($url) {
        $url = urldecode($url);
        header("Location: $url");
    }

    public function startRedirect($params) {
        $parts = explode('/', $_SERVER['PHP_SELF']);
        $baseFile = end($parts);
        $url = sprintf(
            "%s?%s",
            $baseFile,
            http_build_query($params)
        );
        $this->setHeaders($url);
    }
}

if ($_GET['redirect']) {
    (new Redirect())->startRedirect($_GET['params']);
}
?>

漏洞关键

用explode('/',$_SERVER['PHP_SELF'])来截取URL中的文件名
这里有个小技巧。在php文件后面跟上/,会正常执行


返回一个数组array(0=>'',1=>'2.php')
再用end函数,取数组中的最后一位。也就是2.php
这里有一个函数http_build_query,作用如下:

$a=array('abc'=>'test','admin'=>'123'); 
echo (http_build_query($a));#传入值必须为数组
返回abc=test&admin=123

这边我不传入值,为空,与2.php拼接

urldecode($url)
最后header("Location:$url")

如果是用/判断文件名,并且,php文件后面跟上/会正常执行,那么我们输入

2.php/index.php/http:%252f%252f/1.php


传入值,explode分割后:
Array ( [0] => [1] => 2.php [2] => index.php [3] => http:%2f%2f127.0.0.1%2f1.php )
end处理过后:
http:%2f%2f127.0.0.1%2f1.php
sprintf拼接过后:
http:%2f%2f127.0.0.1%2f1.php?
urldecode后:
http://127.0.0.1/1.php?
最后location:$url,跳转到了http://127.0.0.1/1.php

一开始为什么要输入%252f呢。因为程序会urldecode解码一次,而浏览器又会自动解码一次,如果输入%2f(/),浏览器第一次解码。就会将/传入后端,导致explode,分割,不能成功为http://,传入的是%252f,第一次解码过后,%25被解码成%,剩下%和2f重新组合,成为%2f,最后urldecode,为/

下一篇: PHP class_exists函数漏洞→