0x00 原理

  变量覆盖漏洞可以让用户定义的变量值覆盖原有程序变量,可控制原程序逻辑。

0x01 代码

<?php
highlight_file('index.php');
function waf($a){
foreach($a as $key => $value){
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
exit('error');
}
if(md5($_GET['flag'] ) == md5($_Ginclude($_GET['file']){
echo 'flag={你猜猜}';
}
} ?>

0x02 代码审计

  首先对一下代码进行分析

function waf($a){
foreach($a as $key => $value){
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}

  我们知道foreach是php遍历数组的一种方式,这里waf函数遍历$a里面的变量名和变量值,如果变量名中含有flag,则报错

  foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}

  将_POST,_GET,_COOKIE中的值作为 $__R 值判断,是否存在以 $__R 值为变量名的变量,如果有 继续遍历这个变量里的变量名和变量值,如果有里面的变量名存在而且变量名等于变量值就销毁变量__k

。。这样说确实有点乱,但是后面这段foreach 和 熟悉的$$ 应该能想到是通过GET 进行传参。也就是说 $__k==$_GET[flag] ,因为后面要判断flag传参,所以这里只能是flag。 $$__k 是取 $_GET[flag]中的值作为变量名,

之后结合实战可能更好理解点吧

  if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
exit('error');
}
if(md5($_GET['flag'] ) == md5($_GET['daiker'])){
echo 'flag={你猜猜}';
}
}

  通过 if 判断 是否存在POST,GET,COOKIE 变量传参,如果存在 用waf去检测

然后再使用extract($_POST, EXTR_SKIP),extract($_GET, EXTR_SKIP)将变量写入符号表保存起来,而且使用到EXTR_SKIP关键字后不会覆盖之前的变量。

  最后判断是否通过flag进行了传参,传了后,将$flag中的值和$daiker进行比较,相同则结束, 不相同 则 通过md5加密 进行比较,这里存在个php若类型,

我们可以通过两种md5加密后为0e开头的字符串进行绕过,比如QNKCDZO和s878926199a

0x03 实战

  虽然waf函数是最先定义的,但是它是在消除变量后使用的,也就是说题目意思其实是让我们先进行变量清除-》unset函数,不然无法绕过waf函数。因为waf函数匹配了'_POST', '_GET', '_COOKIE',而且后面有要求是通过flag进行传参,所以只能先通过flag和daiker传入对应的值。

简单测试一下吧

<?php
highlight_file('index.php');
function waf($a){
foreach($a as $key => $value){
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
echo '成功消除函数';
}
}
}
var_dump($_POST);
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
exit('error');
}
if(md5($_GET['flag'] ) == md5($_Ginclude($_GET['file']){
echo 'flag={你猜猜}';
}
} ?>

  其实如果理清了思路,多测测就能得到flag了,但是想要深入了解 foreach 是不行的,这里我们构造GET:?_POST[flag]&_POST[daiker] POST: flag=&daike= 来做个小实验



  可以说明当我们传入?_POST[flag]&_POST[daiker]时 ,$_GET 保存了 以 _POST为键 值为 flag 和daiker 的数组 的数组。然后通过foreach遍历因为有'_POST', '_GET', '_COOKIE' 所以总共遍历了3次, 遍历到_GET取出数组赋值到$__R保存,$$__R其实就是$_POST 判定是否存在POST,这里我们是POST提交了参数的,所以存在,继续执行,取出里面的键和值 其实就是 flag:NULL 和 daiker:NULL 判断是否存在 $flag 由于我们POST提交了 flag和daiker,所以它遍历时可判断存在$flag,而且post提交的flag的值正好和GET里flag值一样都为空,通过unset 消去了匹配到的$flag和$daiker,使得$_POST里面没了内容。

<?php
highlight_file('index.php');
function waf($a){
foreach($a as $key => $value){
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
echo '成功消除函数';
}
}
} if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
var_dump($_POST);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
exit('error');
}
if(md5($_GET['flag'] ) == md5($_Ginclude($_GET['file']){
echo 'flag={你猜猜}';
}
} ?>



  根据上面的运行结果我们可以看到之前被消去的$_POST突然回来了,赋值后应该会明显点。



  也就是说知道了这个原理,我们可以通过GET: ?flag=aa&daiker=bb POST: _GET[flag]=aa&_POST[daiker]=bb , 之前故意调换顺序的就是为了让这里变得更加清楚点。

  这里正好和前面反过来,GET传进去了后 遍历时就存在 $flag 变量 而$_GET[flag] 通过 foreach 进行键值得配对,最后删除了$_GET中的$flag和$daiker,然后通过extract函数,

对extract进行测试

<?php

      if($_POST){
extract($_POST, EXTR_SKIP);
echo '成功';
}
var_dump($_GET); ?>



  测试失败,说明 extract 是不能直接进行变量的覆盖的,那只能说明 unset 没有删除干净了,可能涉及到指针吧,如果unset是使用引用置NULL,而extract是通过指针访问数组内存的话就有可能,因为内存地址保存的值还是原来的GET,通过extract可以获取到之前GET中的值,从而绕过了unset。

  因为_GET虽然没了但是POST_存在,会通过指针去访问原来保存了_GET变量的内存地址,直接取出原来的值。(感觉设置不能覆盖之前变量的关键字也和内存地址有干系)。

知道了这个原理,后面的弱类型也就简单了,只要把aa和bb改成QNKCDZO和s878926199a,尝试一下。



成功爆出flag,但是我想看看 extract 是如何覆盖的。

变量覆盖-高级篇(动态覆盖,extract综合)的更多相关文章

  1. extract变量覆盖

    0x01 extract变量覆盖 <?php $flag='xxx'; extract($_GET); if(isset($shiyan)) { $content=trim(file_get_c ...

  2. PHP变量覆盖漏洞整理

    昨天群里HW的大佬们都在传某某服终端检测响应平台edr存在大量RCE的洞 官网上关于EDR的介绍是这么写的 终端检测响应平台EDR,围绕终端资产安全生命周期,通过预防.防御.检测.响应赋予终端更为细致 ...

  3. [fortify] 变量覆盖漏洞

    一.全局变量覆盖当register_global=ON时,变量来源可能是各个不同的地方,比如页面的表单,Cookie等. <?php echo "Register_globals: & ...

  4. ctf变量覆盖漏洞:

    1.变量覆盖: ①:针对extract函数的变量覆盖漏洞: <?php @error_reporting(E_ALL^E_NOTICE); require('config.php'); if($ ...

  5. 【mongoDB高级篇③】综合实战(1): 分析国家地震数据

    数据准备 下载国家地震数据 http://data.earthquake.cn/data/ 通过navicat导入到数据库,方便和mysql语句做对比 shard分片集群配置 # step 1 mkd ...

  6. 面试题_Spring高级篇

    Spring高级篇 1.什么是 Spring 框架? Spring 框架有哪些主要模块?  Spring 框架是一个为 Java 应用程序的开发提供了综合.广泛的基础性支持的 Java 平台. Spr ...

  7. 从零开始学Axure原型设计(高级篇)

    如果你熟悉了Axure的部件库,那么你可以得心应手地画出心目中产品的线框图:如果你会用Axure的母版.动态面板功能,那么你应该能够画出一些简单网站的原型图:但只有你精通了Axure的条件逻辑.变量. ...

  8. 【技巧总结】Penetration Test Engineer[3]-Web-Security(SQL注入、XXS、代码注入、命令执行、变量覆盖、XSS)

    3.Web安全基础 3.1.HTTP协议 1)TCP/IP协议-HTTP 应用层:HTTP.FTP.TELNET.DNS.POP3 传输层:TCP.UDP 网络层:IP.ICMP.ARP 2)常用方法 ...

  9. 7. 由一道ctf学习变量覆盖漏洞

    0×00 背景 近期在研究学习变量覆盖漏洞的问题,于是就把之前学习的和近期看到的CTF题目中有关变量覆盖的题目结合下进一步研究. 通常将可以用自定义的参数值替换原有变量值的情况称为变量覆盖漏洞.经常导 ...

随机推荐

  1. 使用 Velero 跨云平台迁移集群资源到 TKE

    概述 Velero 是一个非常强大的开源工具,可以安全地备份和还原,执行灾难恢复以及迁移Kubernetes群集资源和持久卷,可以在 TKE 平台上使用 Velero 备份.还原和迁移集群资源,关于如 ...

  2. SIP (Session Initiation Protocol) 协议

    Session Initiation Protocol 介绍 SIP是VoIP技术最常使用的协议,它是一种应用程序层协议,可与其他应用程序层协议配合使用,以控制Internet上的多媒体通信会话. V ...

  3. Java中的泛型 - 细节篇

    前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的泛型 - 细节篇>,希望对大家有帮助,谢谢 细心的观众朋友们可能发现了,现在的标题不再是入门篇,而是各种详细篇,细节篇: 是因为之 ...

  4. [贪心]D. 【例题4】国王游戏

    D . [ 例 题 4 ] 国 王 游 戏 D. [例题4]国王游戏 D.[例题4]国王游戏 解析 贪心思想,考虑交换后的值比交换前的小. 然后数据规模用高精度 Code #include <b ...

  5. 【C/C++】面相对象开发之封装

    封装继承多态是面向对象程序开发的基础概念.是实现面向对象的基本要素. 封装 程序开发,最核心价值,是数据. 程序其实是读取数据,操作数据,保存数据等一系列操作. 那么经过良好组织过的数据,将使编程事半 ...

  6. Dynamics CRM实体系列之窗体

    本节开始讲Dynamics CRM的窗体排版和设计,窗体也就是我们实际可以看到的表单界面.Dynamics CRM提供了一套独立的表单模板设计引擎,可以很方便的为开发者提供无代码开发,只需要简单的拖动 ...

  7. Dynamics CRM安装教程一:域环境准备

    服务器环境:Windows Service 2016 Stand Windows域是计算机网络的一种形式,其中所有用户账户,计算机,打印机和其他安全主体都在位于称为域控制器的一个或多个中央计算机集群上 ...

  8. (六)Struts2的拦截器

    一.简介 拦截器体系是struts2重要的组成部分.正是大量的内建拦截器完成了该框架的大部分操作. 比如params拦截器将请求参数解析出来,设置Action的属性.servletConfig拦截器负 ...

  9. 【spring cloud hoxton】Ribbon 真的能被 spring-cloud-loadbalancer 替代吗

    背景 早上刷圈看到 Spring Cloud Hoxton.M2 Released 的消息,随手发布到了我的知识星球,过了会有个朋友过来如下问题. 抽取半天时间学习spring-cloud-loadb ...

  10. iview中table多选、加载更多、下载等使用

    记录工作中的点点滴滴,为回忆过往添加片片记忆... 一.Table 1.使用render函数多层渲染以及表格可展开使用 源码地址:https://gitee.com/Mandy_wang/iview- ...