25.net安全学习特别篇之给ysoserial.net贡献plugins

2024-12-07 19:30   广东  
1.MachineKeySessionSecurityTokenHandler分析
在本文发布之前,也许还没有
MachineKeySessionSecurityTokenHandler
这个插件,因为这是笔者给ysoserial.net项目贡献的插件

我们前面学习过SessionSecurityTokenHandler这个plugins,这个plugins在实战中的价值是比较低的,因为它的加解密都需要依赖DPAPI,但能接触到这玩意的时候基本已经进入后渗透阶段了,基本不会再利用SessionSecurityTokenHandler的安全问题。

但是,在翻阅SessionSecurityTokenHandler文档时,注意到微软的介绍:

注意这个点:

微软的文档告诉我们,在Web场景下可以使用

MachineKeySessionSecurityTokenHandler

它会使用machineKey中的签名密钥和加密密钥对Cookie进行加解密。关于machineKey以及相关配置,我们在ViewState安全问题相关的文章中已经学习过,这边不再展开了。

说回MachineKeySessionSecurityTokenHandler:

我们注意到这个类继承了SessionSecurityTokenHandler,那么是极可能存在类似的问题的,又注意到

new DeflateCookieTransform(),new MachineKeyTransform()

前者不必多说(参考对SessionSecurityTokenHandler的分析),而后者从名字上就类似于ProtectedDataCookieTransform(),我们猜测MachineKeyTransform()就是用于获取MachineKey并进行数据的加解密的,因此可以写出下面的测试代码用于生成payload:

可以拿到payload:

随后,使用下面的代码进行测试,传入上面生成的payload

运行,可以成功实现RCE

这个姿势就要比SessionSecurityTokenHandler要实用一些了,因为算是windows推荐给开发者的姿势,并且要利用的话只需要获取MachineKey配置项中的密钥,利用思路和之前介绍过的ViewState安全问题是很类似的,拿到web.config配置信息,并且目标代码中有类似的写法,就可以实现攻击了。


2.Plugins的实现

上面我们操作了这么多,只是抱着试验的态度去验证了攻击MachineKeySessionSecurityTokenHandler的可行性,若是想实现一个好用的插件,还是有很大问题的,我们上面的操作依赖于完整的web环境,总不能把整个WEB环境打包到工具里吧?

所以接下来得研究MachineKeySessionSecurityTokenHandler Cookie的生成逻辑,研究一下.NET取出web.config中的MachineKey配置后,都经过了哪些流程才实现了加密流程。这里流程其实也比较长,就长话短说了。其核心是一个Protect()方法:

System.Web.Security.Cryptography.NetFXCryptoService.Protect()

在这里,乍一看数据结构和逻辑环环相扣,我差点想从头把整个生成逻辑抠出来,非常绝望,不过后面理清了之后发现并没有那么令人绝望,首先看到NetFXCryptoService构造方法

首先看到老朋友encryptionKey和validationKey,都是CryptographicKey类的对象,后续关于它们的调用主要是两个地方:

那么跟进CryptographicKey以及相关方法

非常好理解,这里我简单猜测就是把encryptionKey和validationKey字符串转化为byte[]形式传入这个类。就暂时不去寻找具体的调用赋值流程。继续看Protect()方法

可以看到还有一个多次使用的关键属性_cryptoAlgorithmFactory,这里先是调用

_cryptoAlgorithmFactory.GetEncryptionAlgorithm()

拿到了一个SymmetricAlgorithm类的对象,然后给Key属性赋值,值即为encryptionKey的byte[]形式

再接着又调用

_cryptoAlgorithmFactory.GetValidationAlgorithm()

拿到了一个KeyedHashAlgorithm类的对象,然后还是给Key赋值,值即为validationKey的byte[]形式

看起来加密和验签都和_cryptoAlgorithmFactory密切相关,_cryptoAlgorithmFactory是ICryptoAlgorithmFactory类型的对象

而在本案例中,其具体是MachineKeyCryptoAlgorithmFactory类的对象

并且注意到

_encryptionAlgorithmFactory

_validationAlgorithmFactory

都为null,这个后续对我们有用,先记着。

跟进MachineKeyCryptoAlgorithmFactory

其构造方法接受一个MachineKeySection类的对象,乍一看我们还得去研究MachineKeySection的结构,如果你这时候再跟进MachineKeySection,就会发现还有一大堆东西要去继续分析,第一次看的我非常绝望。但实际上这样就是走远了。我们之所以需要

MachineKeyCryptoAlgorithmFactory

是因为上面调用了它里面的GetEncryptionAlgorithm()和GetValidationAlgorithm()两个方法,其它的东西实际上和我们没有关系的,那我们可以先看看这两个方法做了什么,首先是GetEncryptionAlgorithm()

当_encryptionAlgorithmFactory为null时,调用

GetEncryptionAlgorithmFactory()

跟进来就很明了了,这里显然是根据MachineKey配置文件中的加密算法来返回相应的委托

GetValidationAlgorithm()也是同理:

因此我们根本不需要关注其它的实现,只需要返回相关的委托即可!后续会返回委托执行结果

因此上述各种复杂的委托,实际上是执行下面这样的方法,并接受其结果:

CryptoAlgorithms.CreateAes()

并且其最终的返回都是类似下面这样的:

new AesCryptoServiceProvider()

这就是一个Public的类了,这样调用就很方便了,最终我们只需要调用上面这样的方法即可,这样就凑齐所有条件了

然后最抽象的是,我刚把最核心的逻辑分离出来,上网找相关资料的时候发现早就有人实现过了,直接导包就行了,浪费一晚上时间(

最后实现代码如下:

运行可以拿到Payload:

替换原来的测试代码进行试验:

成功RCE


3.第一次pull request

第一次给开源项目做贡献,怪紧张的,新手也来记录一下,首先先给ysoserial.net原项目fork一下

然后git clone回来:

git clone https://github.com/YOUR_USERNAME/PROJECT.git

然后在这个文件夹使用git设置原项目地址,便于随时pull最新的修改:

git remote add upstream https://github.com/pwntester/ysoserial.net.git

然后创建一个本地分支

然后开始改代码即可,我这边主要做了如下的工作,首先来到ysoserial.net的Plugins目录,添加一个新的.cs文件,名为

MachineKeySessionSecurityTokenHandlerPlugin

根据ysoserial.net的插件的语法规则编写新的插件:

然后使用Nuget添加AspNetTicketBridge依赖,再添加System.IdentityModel.Services的引用

修改完之后,使用以下命令添加更改到暂存区:

git add .

然后,提交这些更改,简短的说明一下都干了什么:

git commit -m "add MachineKeySessionSecurityTokenHandlerPlugin"

提交更改后,将这些更改推送到GitHub上你的分支。

git push origin ysoserial.net_addMachinePlugin

确保自己的文件都更新好之后,访问自己fork的地址:

可以看到多了一个按钮,点一下,然后在后续进入的界面中说明你都做了哪些改动以及改动的原因,最后再提交即可

HW专项行动小组
大师!教我打攻防
 最新文章