A-A+

CTF 之 变量覆盖漏洞详解

2018年10月26日 23:52 学习笔记 暂无评论 共1603字 (阅读3,371 views次)

【注意:此文章为博主原创文章!转载需注意,请带原文链接,至少也要是txt格式!】

今天学习了一个变量覆盖,首先看题。

ctf变量覆盖题目

ctf变量覆盖题目

这里如果想解题,首先需要弄懂里面每一句的意思,只要知道每一句的意思了,就好推理解题了。

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
<?php error_reporting(0); 
show_source(__FILE__); // show_source — 别名 highlight_file() 使用PHP内置的语法高亮器所定义的颜色,打印输出或者返回 filename 文件中语法高亮版本的代码。 
include "flag.php"; //①加载flag.php文件,这个文件里面只有一个变量是 $flag="seccuss. flag is woj.app"; 
$_403 = "Access Denied"; 
$_200 = "Welcome Admin"; 
if ($_SERVER["REQUEST_METHOD"] != "POST") 
    die("CISPCTF is here :p..."); 
if ( !isset($_POST["flag"]) ) 
    die($_403); 
foreach ($_GET as $key =&gt; $value){ 
   $$key = $$value; //注意这里是在大括号中,不是在函数中,不是临时变量。 
   print_r($$key); //重点在这里, 这里就变成了 ${$key}=${$value} 
   echo "------"; // ②这里也就是说 假设 $key=aaa 拿就是 $aaa = ${$value} 
   print_r($$value); 
 
//接上面,如果$value="bbb" 那么就是 $aaa=$bbb 如果bbb是个变量有值呢? 
//如果按上面①里面加载的是变量flag 那么如果 $aaa=$flag 那么 $aaa="seccuss. flag is woj.app"; 过关密钥对吧。 
//php中大括号的作用,如下: 
//一、不管什么程序,function name(){}, for(){},….这太多了,不说也知道什么用了。 
//二、$str{4}在字符串的变量的后面跟上{}刚大括号和中括号一样都是把某个字符串变量当成数组处理 
//三、{$val},这时候大括号起的作用就是,告诉PHP,括起来的要当成变量处理。 
} 
 
foreach ($_POST as $key =&gt; $value){ 
   $$key = $value; 
} //因为这个for循环遍历post接受的参数,所以下面的判断始终相等,既然相等就无法进入die($_403) 
 
if ( $_POST["flag"] !== $flag ) // !== 不全等(完全不同) $x !== $y 如果 $x 不等于 $y,或它们类型不相同,则返回 true。 
    die($_403); 
echo "This is your flag : ". $flag . "\n"; //所以只能走到这里。因为flag上方有判断,必须赋值,所以他的原本值已经被覆盖。 
die($_200); //只能走到这里,终止程序并显示变量$_200 那只能是让上方的② $key等于flag了。 
?>

关于大括号,本人特意做了两个调试结果让大家更明白一些。

${括号内的变量}

${括号内的变量}

图二:

$变量

$变量

 

0×02 extract()函数导致的变量覆盖问题

extract() 该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

extract()的用法参考:http://www.runoob.com/php/func-array-extract.html

语法: extract(array,extract_rules,prefix)

CTF中extract()导致的变量覆盖问题的例题1: 

1
2
3
4
5
6
7
8
9
10
11
$flag = 'xxx';
extract($_GET);
 
if (isset($gift)) {
    $content = trim(file_get_contents($flag));
    if ($gift == $content) {
        echo 'hctf{…}';
    } else {
        echo 'Oh..';
    }
}

题目分析:

题目使用了extract($_GET)接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个if 的条件判断,所以可以使用GET提交参数和值,利用extract()对变量进行覆盖,从而满足各个条件。

解题方法:

GET请求 ?flag=&gift=,extract()会将$flag和$gift的值覆盖了,将变量的值设置为空或者不存在的文件就满足$gift == $content。

最终PAYLOAD:

GET DATA: ?flag=&gift=
这道题真的简单。。。。
-----------
CTF中extract()导致的变量覆盖问题的例题2:
题目源码:

1
2
3
4
5
6
7
8
9
<?php if ($_SERVER["REQUEST_METHOD"] == “POST”) { ?>
  <?php
    extract($_POST);
   if ($pass == $thepassword_123) { ?>
<div class=”alert alert-success”>
<code><?php echo $theflag; ?></code>
</div>
 <?php } ?>
 <?php } ?>

题目分析:

题目要求使用POST提交数据,extract($_POST)会将POST的数据中的键名和键值转换为相应的变量名和变量值,利用这个覆盖$pass和$thepassword_123变量的值,从而满足$pass == $thepassword_123这个条件。

解题方法:

使用POST请求提交pass=&thepassword_123=, 然后extract()会将接收到的数据将$pass和$thepassword_123变量的值覆盖为空,便满足条件了。

最终PAYLOAD:

POST DATA:pass=&thepassword_123=

0×03 parse_str函数导致的变量覆盖问题

parse_str() 函数用于把查询字符串解析到变量中,如果没有array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

语法:parse_str(string,array)

parse_str() 用法参考:http://php.net/parse_str

CTF中parse_str()导致的变量覆盖问题的例题1: 

题目源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 2018/10/26
 * Time: 22:42
 */
 
error_reporting(0);
if (empty($_GET['id'])) {
    show_source(__FILE__);
    die();
} else {
    include ('flag.php');
    $a = "www.OPENCTF.com";
    $id = $_GET['id'];
    @parse_str($id);
    if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
        echo $flag;
        exit;
    } else {
        exit('其实很简单其实并不难!');
    }
}

 

题目分析:

首先要求使用GET提交id参数,然后parse_str($id)对id参数的数据进行处理,再使用判断$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)的结果是否为真,为真就返回flag,md5(‘QNKCDZO’)的结果是0e830400451993494058024219903391由于此次要满足$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)所以要利用php弱语言特性,0e123会被当做科学计数法,0 * 10 x 123。所以需要找到一个字符串md5后的结果是0e开头后面都是数字的,如,240610708,s878926199a

这题我做了半天实在想不到,“https://woj.app/test.php?XDEBUG_SESSION_START=19687&id=a%3dqnkcdzo%26a%5b%5d%3dqnkcdzo%26a%5b0%5d%3dQNKCDZO” 然后看的答案PHP处理0e开头md5哈希字符串缺陷/bug 参考:https://woj.app/4311.html

解题方法:

使用GET请求id=a[0]=240610708,这样会将a[0]的值覆盖为240610708,然后经过md5后得到0e462097431906509019562988736854与md5(‘QNKCDZO’)的结果0e830400451993494058024219903391比较都是0 所以相等,满足条件,得打flag。

最终PAYLOAD:

GET DATA:

?id=a[0]=s878926199a

or

?id=a[0]=240610708

0×04 小总结

变量覆盖漏洞在PHP代码审计中会以比较隐晦的方式存在,所以需要更加仔细的阅读源码找出漏洞的点,在CTF里面经常是以比较直接方式展示,所以可以先通过学习CTF各种变量覆盖的题目,然后掌握后再去审计cms,这样可以更加通透的理解掌握和挖掘变量覆盖漏洞。

import_request_variables 函数可以在 register_global = off 时,把 GET/POST/Cookie的参数注册成变量
bool import_request_variables ( string $types [, string $prefix ] )
$type代表要注册的变量,G代表GET,P代表POST,C代表COOKIE,第二个参数为要注册变量的前缀

1
2
3
4
5
<?php
$a = 1;    //原变量值为1
import_request_variables('GP');   //传入参数时注册变量
print_r($a);  //输出结果为2
?>

三、挖掘经验

  由于变量覆盖漏洞通常要结合应用其他功能代码来实现完整攻击,所以挖掘一个可用的变量覆盖漏洞不仅仅要考虑的是能够实现变量覆盖,还要考虑后面的代码能不能让这个漏洞利用起来。

部分资料来源:http://www.freebuf.com/column/150731.html
https://www.cnblogs.com/sqyysec/p/6926095.html

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×

给我留言