2018-01-26-Spring XXE漏洞(CVE-2013-4152,CVE-2014-0225)

#介绍
老漏洞了,原理也很简单,随便分析一波。
漏洞编号为CVE-2013-4152,根据官方提示,xxe漏洞,漏洞的位置包括oxm,嗯,现学现卖,直接翻到文档学习一波 https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#oxm 根据官方写一个demo

````
public class Application {
private static final String FILE_NAME = "src/main/java/test/settings.xml";
private Settings settings = new Settings();
private Marshaller marshaller;
private Unmarshaller unmarshaller;

public void setMarshaller(Marshaller marshaller) {
    this.marshaller = marshaller;
}

public void setUnmarshaller(Unmarshaller unmarshaller) {
    this.unmarshaller = unmarshaller;
}

public void saveSettings() throws IOException {
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(FILE_NAME);
        this.marshaller.marshal(settings, new StreamResult(os));
    } finally {
        if (os != null) {
            os.close();
        }
    }
}

public void loadSettings() throws IOException {
    FileInputStream is = null;
    try {
        is = new FileInputStream(FILE_NAME);
        this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
    } finally {
        if (is != null) {
            is.close();
        }
    }
}

public static void main(String[] args) throws IOException {
    ApplicationContext appContext =
            new ClassPathXmlApplicationContext("applicationContext.xml");
    Application application = (Application) appContext.getBean("application");
    application.saveSettings();
    application.loadSettings();
}

} ----------------------------------	

````
public class Settings {
private boolean fooEnabled;

public boolean isFooEnabled() {
    return fooEnabled;
}

public void setFooEnabled(boolean fooEnabled) {
    this.fooEnabled = fooEnabled;
}

}

````

测试完xml解析之后,写了一个web项目,验证一下,核心代码如下:

````
@Controller
public class XmlController {
@RequestMapping(value = "/login", method = RequestMethod.POST, consumes = "application/xml")
@ResponseBody
public String login(@RequestBody User user) {
    String username = user.getUserName();
    String userpassword = user.getUserPassword();
    String result;

    if (username.equals("admin") && userpassword.equals("admin888")){
        result = "{'status':'ok', 'message': 'login success', 'username': " + username+ "}";
    }else {
        result = "{'status':'error', 'message': 'login fail', username': " + username+ "}";
    }
    return result;
}

}
```` -----------------------------------

````
@XmlRootElement(name = "user") public class User {
private String userId;
private String userName;
private String userPassword;

@XmlElement
public String getUserPassword() {
    return userPassword;
}

public void setUserPassword(String userPassword) {
    this.userPassword = userPassword;
}

@XmlElement
public String getUserId() {
    return userId;
}

public void setUserId(String userId) {
    this.userId = userId;
}

@XmlElement
public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}
}
````

正常测试XML如下

curl -i -X POST -H “Content-Type:application/xml” -d “adminadmin888” http://127.0.0.1:8080/CVE-2013-4152/login

xml:

adminadmin

有回显 curl -i -X POST -H “Content-Type:application/xml” -d “ <!DOCTYPE a [<!ENTITY xxe2 SYSTEM "file:///etc/passwd">]>

&xxe2;admin

” http://127.0.0.1:8080/CVE-2013-4152/login

漏洞造成的原因是由于unmarshal函数中直接解析xml文件,没什么好分析的。

官方修复的补丁 https://github.com/spring-projects/spring-framework/pull/317/commits/2843b7d2ee12e3f9c458f6f816befd21b402e3b9

指的说明的是网上很多关于xxe漏洞的修复方案中只提到

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

各种类型的具体修复方案见下面 DOM

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(externalSource);

SAX

XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
xmlReader.parse(new InputSource(externalSource));

StAX

XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false); // disable DTDs entirely for that factory
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); // disable external entities
XMLStreamReader reader = factory.createXMLStreamReader(externalSource);

Spring OXM

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(externalSource);
DOMSource source = new DOMSource(document);
Jaxb2Marshaller jaxb2Marshaller = ...
Object unmarshalled = jaxb2Marshaller.unmarshal(source);

CVE-2013-4152补丁设置xmlReader.setFeature(“http://xml.org/sax/features/external-general-entities”,false);可以防止外部实体被解析

###参考文档
http://blog.csdn.net/scmrpu/article/details/50423701 https://security.tencent.com/index.php/blog/msg/69