考点unset的一道CTF题目

文件名:123.php

<?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);
//var_dump($_GET);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
        exit('error');
}
if(md5($_GET['flag'] ) == md5($_GET['daiker'])){
        include($_GET['file']);
}
}

首先分析一下

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

这边就是一个典型的foreach遍历取$_POST,$_GET,$_COOKIE中的键值对进行判断

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

这里的话就定义了一个waf的函数 进行正则匹配 ‘flag’ 如果匹配到的话 那么直接exit了 这里肯定要绕过了

if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
//var_dump($_GET);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
        exit('error');
}
if(md5($_GET['flag'] ) == md5($_GET['daiker'])){
        include($_GET['file']);
}

extract 变量覆盖
后面的判断 就是典型的弱类型0e 进行绕过

现在我们开始绕过

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

绕过后面的waf函数的判断主要就是考察如何绕过这个地方

if(isset($$__k) && $$__k == $__v) unset($$__k);

foreach里面的判断先是遍历$_POST然后再遍历$_GET

后面的isset($$__k) && $$__k ==$__v 需要成立 才能进行unset的操作
又看下这边的waf函数如果匹配到flag就会直接exit 而后面又需要$_GET[flag] 进行判断
那么我们绕过的话 必须得先绕过这里

if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);}

测试可以发现 当 GET :http://127.0.0.1/123.php?x=1
POST :_$GET[x] =1 的时候
在这里插入图片描述

我这边var_dump($_GET)
发现是NULL 分析下代码发现是 unset了$_GET了 所以导致$_GET 直接为空
我们可以先分别var_dump($_GET)和var_dump($_POST)

var_dump(\$_GET):
array(1) { ["x"]=> string(1) "1" } 



var_dump(\$_POST):
array(1) { ["_GET"]=> array(1) { ["x"]=> string(1) "1" } } 

可以发现在foreach的时候遍历$_GET的时候 isset($$__k) && $$__k == $__v 成立了
所以导致了之后的var_dump($_GET) 为NULL

extract($_POST,EXTR_SKIP)导致的覆盖变量可以使$_GET成功生成 那么最后的弱类型判断就可以直接成立
从而导致绕过 因为我们最后还需要file来读取flag.php
所以这道题还需要

allow_url_include = On
allow_url_fopen = On

那么最后的payload就是这样子的
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/q1352483315/article/details/89424359