XML注入攻击总结

XML注入攻击总结

  • 普通的XML注入
  • XML外部实体注入攻击
  • XML内部实体注入攻击
  • 参考链接以及项目地址

普通的XML注入

  • 原理
    XML注入攻击和SQL注入攻击的原理一样,利用了XML解析机制的漏洞,如果系统对用户输入"<",">"没有做转义的处理,攻击者可以修改XML的数据格式,或者添加新的XML节点,就会导致解析XML异常,对流程产生影响。

  • 如何注入攻击

  1. 如下XML是用于注册访问用户,其中用户名是由用户自己输入的。

<user role="guest">用户输入user>
  1. 攻击者在输入用户的时候,可以构造" user1 < /user> < user role=“admin”>user2"数据去拼接XML,之后整个XML字符串将会变成如下格式。这样就添加了一个管理员权限的用户。

<user role="guest">user1user>
<user role="admin">user2user>
  • 如何防护
  1. 使用白名单校验
    可以使用正则的方式对用户的输入做严格的校验,比如用户输入的用户名只能含有中文,英文大小写字母,数字以及下划线等等。
  2. 使用安全的XML库
    正确代码使用dom4j来构建XML,dom4j是一个定义良好,开源的XML工具库,Dom4j将会对文本数据进行XML编码,从而使得XML的原始结构和格式免受破坏。
    代码中最终生成的XML会进行编码,会被替换,从而防止了XML注入。
    @Test
    public void testDom4j() {
        Document document = DocumentHelper.createDocument();
        Element user = document.addElement("user");
        user.addAttribute("role","guest");
        user.setText(REPLACE_XML);
        String xml = document.asXML();
        System.out.println(xml);
    }

<user role="guest">user1</user><user role="admin">user2user>
  1. 对用户输入的字段进行转码处理
    代码中对传过来的参数进行了转码处理,之后去构造XML字符串,就不会导致XML字符串结构被篡改。
    @Test
    public void testTrans() {
        String xml = "\n" +
                "%s";
        String replace = "user1user2";
        String format = String.format(xml, xmlConversion(replace));
        System.out.println(format);
    }
    
    /**
     * 转义xml中不支持的特殊字符
     * 
     * @param strXml
     * @return
     */
    private String xmlConversion(String strXml){
        String conversionStr = "";
        if(strXml == null){
            return null;
        }
        conversionStr = strXml.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").
                replaceAll("'","'").replaceAll("\"",""");
        return conversionStr;
    }
  • 项目代码中的排查
    首先要找到前台在那些地方拼接了XML,之后需要查看对应的代码逻辑,查看后台是否存在没有处理前端数据直接拼接的情况,如果存在则进行对应的修改,转码,白名单,使用安全的XML库等等。

XML外部实体注入攻击

  • 原理
    XXE:XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。
  • 如何注入攻击,注入攻击类型
  1. 利用外部实体的引用功能实现对任意文件的读取
    这个是解析的xml文件,我们定义了一个通用实体,并且在文件中去引用这个实体。
    password.txt文件中记录了敏感的一些信息。

 ]>
<updateProfile>
    <firstname>joefirstname>
    <lastname>&file;lastname>
updateProfile>

具体解析代码

    @Test
    public void testXXE1() throws DocumentException {
        File file = new File("d://xml//demo.xml");
        SAXReader reader = new SAXReader();
        Document document = reader.read(file);
        Element rootElement = document.getRootElement();
        String lastname = rootElement.element("lastname").getText();
        System.out.println("get the password "+ lastname);// 这边代码会输出password.txt文件里面的内容
    }

XML注入攻击总结_第1张图片
2. 使用参数实体和避免XML解析语法错误,构造恶意的实体解析
使用参数实体和避免XML解析语法错误,构造恶意的实体解析:
XML文件:构造参数实体 % start;% goodies;% end;% dtd 定义一个恶意的combine.dtd




<!ENTITY % end "]]>">

%dtd;
]>
<roottag>&all;roottag>

恶意DTD combine.dtd中定义实体&all;


<!ENTITY all "%start;%goodies;%end;">

甚至可以这样构造恶意的DTD combine.dtd,将结果发送到目标地址,最后会获得file:///etc/fstab文件。


”>
%send;
  • 如何防护
  1. 禁止解析DTDs
    @Test
    public void testXXE2() throws DocumentException, SAXException {
        File file = new File("d://xml//demo.xml");
        SAXReader reader = new SAXReader();
        // 禁止解析DTDS
        reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); //禁止包含doctype
        reader.setFeature("http://xml.org/sax/features/external-general-entities", false); //禁止外部实体解析
        reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //禁止外部参数解析
        Document document = reader.read(file);
        Element rootElement = document.getRootElement();
        String lastname = rootElement.element("lastname").getText();
        System.out.println("get the password "+lastname);
    }

这边对上面列到的testXXE方法做了处理,设置了禁止解析DTDs属性,同时也禁止了参数实体和外部实体的解析,该方式不仅可以防止XML的外部实体攻击也能防止XML内部实体攻击。
具体再运行代码,会抛出如下异常。可以看出DTDs已经被禁止。
XML注入攻击总结_第2张图片

  1. 禁止解析外部一般实体和外部参数实体
    @Test
    public void testXXE3() throws DocumentException, SAXException {
        File file = new File("d://xml//demo.xml");
        SAXReader reader = new SAXReader();
        // 禁止解析DTDS
        reader.setFeature("http://xml.org/sax/features/external-general-entities", false); //禁止外部实体解析
        reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //禁止外部参数解析
        Document document = reader.read(file);
        Element rootElement = document.getRootElement();
        String lastname = rootElement.element("lastname").getText();
        System.out.println("get the password "+lastname);
    }

这边具体运行之后是不能获得lastname的值,可以看到外部参数实体没有被解析出来。(此方法可以防止外部实体攻击,不能预防内部实体攻击)
XML注入攻击总结_第3张图片
3. 禁止解析外部实体
正确示例方法定义一个CustomResolver类来实现接口org.xml.sax.EntityResolver。在这个类中实现自定义的处理外部实体机制。自定义实体解析函数中使用一个简单的白名单,白名单范围里面则返回对应的文件内容,不在白名单范围里面的则返回一个空的实体解析内容。

    // 自定义外部实体处理
    private class CustomResolver implements EntityResolver {
        // 自定义的一个白名单
        String whitePath = "file:///d:/xml/password.txt";

        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            if (systemId.equals(whitePath)) {
                System.out.println("Resolving entity: " + publicId + " " + systemId);
                return new InputSource(whitePath);
            } else {
                // 解析输入恶意的xml内容时,返回空
                return new InputSource();
            }
        }
    }

    @Test
    public void testXXE() throws DocumentException, SAXException {
        File file = new File("d://xml//demo.xml");
        SAXReader reader = new SAXReader();
        // 设置自定义的外部实体处理
        reader.setEntityResolver(new CustomResolver());
        Document document = reader.read(file);
        Element rootElement = document.getRootElement();
        String lastname = rootElement.element("lastname").getText();
        System.out.println("get the password "+lastname);
    }

因为“file:///d:/xml/password.txt”这个路径是加在白名单里面的,所有上面的代码可以运行通过,能够解析到password.txt文件里面的内容。
XML注入攻击总结_第4张图片
如果不在白名单里面,会返回空,或者里面可以加上别的具体的业务逻辑。

XML内部实体注入攻击

  • 说明
    XML内部实体是实体的内容已经在Doctype中声明。内部实体格式:。内部 实体攻击比较常见的是XML Entity Expansion攻击,它主要试图通过消耗目标程序的服务器内存资源导致DoS攻击。外部实体攻击和内部实体扩展攻击有不同的防护措施(禁止DTDs解析可以防护外部实体和内部实体攻击)。
  • 如何注入攻击,注入攻击类型
  1. 拒绝服务攻击
    下面恶意的XML内部实体解析,占用服务器内存资源,导致拒绝服务攻击。


<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;lolz>
  • 如何防护
    内部实体扩展攻击最好的防护措施是禁止DTDs的解析。另外也可以对内部实体数量进行限制,以消减内部实体 展攻击发生的可能性。所以在不需要使用内部实体时,应该禁止DTDs解析,需要使用内部实体时,严格限制内部实体的数量及xml内容的大小。
  1. 禁止解析DTDs
    同上
  2. 限制实体解析个数
    通过设置setFeature(“http://javax.xml.XMLConstants/feature/secure-processing”, true);限制实体个数不能超过100,000个。
    @Test
    public void testXmlDos() throws SAXException, DocumentException {
        File file = new File("d://xml//dos.xml");
        SAXReader reader = new SAXReader();
        // 这边设置实体个数不超过10000个
        reader.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
        Document document = reader.read(file);
        String xml = document.asXML();
        System.out.println(xml);
    }

运行结果如果实体超过100,000的话,会直接抛出异常。
XML注入攻击总结_第5张图片

参考链接以及项目地址

  • 参考链接
    https://xz.aliyun.com/t/3357#toc-0
    https://www.freebuf.com/column/181064.html

  • 项目地址
    https://github.com/yzh19961031/blogDemo/tree/master/xml

你可能感兴趣的:(XML注入攻击总结)