先说一下写这篇文章的初衷。最近微信支付爆发了xxe漏洞,然后领导很快就用自己的静态代码审计工具进行了审计(这里就不点名了,本来可以帮助公司推广产品的)很好,但是恐怕这篇文章太基础了,会被大佬们诟病,侮辱“思”派就是罪过。)
发现可以成功找到漏洞点,如下图。
到目前为止,这是一件很棒的事情,但我发现在使用我自己的规则修复它之后,我仍然可以扫描该漏洞,这非常有启发性。于是老板让我对微信支付漏洞进行漏洞研究,找出产品问题的原因。于是就有了这篇文章。由于本文的初衷是为了改进产品,所以本文无意深入研究xxe漏洞,更适合开发者。
微信支付的SDK中提供了这个工具类,这两个方法都是在这个类中实现的。微信支付本次的xxe漏洞爆发点就在方法中。
该方法是将xml格式的字符串转换为map。由于它可以被攻击者控制,并且程序没有采取任何保护措施(例如禁止引用外部实体;过滤关键字符串等),因此恶意攻击者可以利用外部实体注入来读取服务器上的文件。当攻击者获得用于支付加密的安全密钥后,完全可以用0元支付商品。
这里我们首先以微信SDK中的方法为例,复现xxe漏洞。 (由于我们需要彻底实现微信零元支付,所以需要编写一个比较完整的程序来连接微信支付接口,比较耗时,暂时不做)。
有问题的代码是:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();org.w3c.dom.Document doc = documentBuilder.parse(stream);
生成ry后,直接去解析流。
构造一个xml格式的字符串,如下:
]>&xxe;
这样,当DOM解析器解析字符串时,就会访问外部实体中属性中标识的URL,并将读取到的文件内容放入节点中。然后取出来放入map中(实际场景中,map中的值最终会被攻击者获取到,这里以控制台上的输出为例),即可成功读取系统文件。
1. 完全禁用DTD并在生成ry后设置它们。
ry.(“”,true);
效果如下:
程序会报告错误,提示您将此属性设置为 true。
2、生成ry后进行设置
documentBuilderFactory.setXIncludeAware(false); documentBuilderFactory.setExpandEntityReferences(false); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities",false); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
效果如下:
虽然程序不会报错,但无法再读取系统文件的内容。
3、过滤关键词,如:
分析以上三种防范方法:建议使用第一种方法,可以应对绝大多数xxe漏洞;当需要禁用所有DTD时,使用第二种方法;不建议使用第三种方法,否则很容易被绕过,比如使用其他情况来绕过。
微信支付SDK使用原生DOM来解析XML。接下来我们将重现使用原生SAX解析XML、使用解析XML、使用jdom解析XML的xxe漏洞及修复方法(修复原理相同)。 ,方法类似,但是为了方便以后完善产品规则,这里都列出来了)
使用本机 SAX 解析 xml
问题是生成后直接解析xml。解决方法是添加属性。
sf.(“”,true);
效果如下:
使用解析 xml:
SAXReader reader = new SAXReader();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));Document doc = reader.read(stream);
使固定:
。(““,真的);
效果如下:
使用 Jdom 解析 xml
SAXBuilder builder = new SAXBuilder();Document doc = builder.build(stream);
修复方法如下:
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
效果如下:
最后,审计结果分析:
报告了两个 xxe 漏洞,分别是 .java 和这两个方法。其中,微信支付xxe漏洞的爆发点在,所以两者之一是正确的,另一个是误报。我们先来分析一下误报:
该方法是取出map中的键值对并生成xml节点,并将其放置在根节点中。在这种情况下,即使地图被攻击者控制,在生成xml时也不会构造它。引入外部实体。事实上,xxe漏洞是解析过程中出现问题导致的。仅生成有问题的xml并不能判断是否存在xxe漏洞。关键是看程序在解析时是否有安全措施到位(比如上面提到的添加实体引入的禁止外部属性等)。
对于这种误报我的建议是:不能因为没有设置安全属性就判断存在漏洞。尝试先判断有没有解析xml然后根据
是否设置了安全属性?
安全吗?
来判断是否存在漏洞。 (感觉不太好实现,上面两段比较主观,仅供参考……)
下一篇报告再说一点,断点确定正确。
但是被告知修复后还是会报xxe漏洞,所以就看了一下修复后的方法。
固定方法将该属性设置为 true。本地测试结果如下。发现无法防范xxe漏洞,所以不推荐这种方法。
我们来看看微信支付官方SDK是如何修复这个xxe漏洞的。
使用专门的xml工具类来生成
此类中设置了一些安全属性。应该是微信支付为了安全起见,同时采用我上面提到的修复方法一和二(毕竟没有绝对的安全)。但从规则上来说,我认为只要审核时采用其中之一,就可以认为不存在xxe漏洞。如果规则认为同时使用这两种措施来确定不存在漏洞,则可能会导致较高的误报率。 (毕竟很多程序都只使用第一种方法来防止xxe)。
最后,我还是想说,这是我第一次在网络上发表文章。希望各位大佬站在培养新人的角度,轻喷!