1.Resx(原理部分)
这个插件与.resx和.resources文件的安全问题有关,感觉实战里还是有很多机会应用的上的,师傅们可以酌情研究一下。除了原理部分,还会提供几个应用场景,可以切到第二第三小节观看。
这里看一下ResxPlugins的test功能,看看用于测试的sink点是怎样的:
可以看到,这个plugins提供给我们几个主要的模式,主要有CompiledDotResources、BinaryFormatter、SoapFormatter等等。其中前者和后两者对应的sink点不同。先看看ResourceSet()构造方法吧,看起来只需传入一个文件地址 or stream即可实现RCE?
ResourceSet()中有两个关键的方法调用,一个是ResourceReader()一个是ResourceSet.ReadResources(),先跟进一下前者
前者把我们传入的Stream传入BinaryReader(),赋值给_store变量,然后又调用ResourceReader.ReadResources() 跟进一下:
这里实例化了BinaryFormatter,并且设置好了Binder,然后将BinaryFormatter对象赋值给_objFormatter。这块分析完了,再继续看看ResourceSet.ReadResources()
这里先拿到迭代器对象,然后调用其Value属性,这里会走入
System.Resources.ResourceReader.ResourceEnumerator.Value
其get属性有一个GetValueForNameIndex方法的调用,跟进:
其中有一个LoadObjectV2方法的调用,继续跟进,这个方法略复杂,不过在最后我们可以看到DeserializeObject()方法的调用
跟进:
经典的BinaryFormatter反序列化点,且传入的内容我们可控。不过这里还有些细节,因为这里会判断resources文件是否有效,普通的binaryFormatter payload是行不通的:
异常出现在
System.Resources.ResourceReader._ReadResources()
这里对序列化数据做了一些判断
理论上来说也可以生成一个原始BinaryFormatter的序列化payload,然后一步一步将其修饰到能够通过上述方法的检验,不过我这里就摸鱼了,直接用Resx插件生成一个来实验:
ysoserial.exe -p Resx -M CompiledDotResources -c "calc.exe" --of payload.resources
成功实现命令执行。
这是ResourceSet()这个sink点,单参数可控即可实现RCE,非常不错的点,审计中也可以多注意。另一个Sink点如下:
看到两个关键的方法调用,分别是ResXResourceReader()和它的GetEnumerator()。我们也来分析一下。
首先是ResXResourceReader()
主要就是对一些字段进行了初始化,比如进行fileName属性的赋值
(也可以接受TextReader、String,最后就是给reader字段赋值)
接着来看看GetEnumerator()
跟进EnsureResData(),这个方法就有意思了,会对reader、fileName、stream几个字段进行判断,比如我这里有fileName字段,那么就会读取目标文件,得到stream
接下来,进入ParseXml,看起来和Xml数据的处理有关
上面这里会获取一些节点,并且分别传入对应的处理方法
我们跟进
reader.LocalName.Equals("data")
分支的ParseDataNode()看看,其中有一个GetValue()方法的调用
继续跟进,可以找到一个
GenerateObjectFromDataNodeInfo
方法的调用
最后可以找到我们想要的东西:
这里有点复杂,不过从resx文件结构上看就会简单很多:
简单来说,这里会获取data节点的mimetype,决定后续反序列化行为使用的Formatter
例如我们上面的mimetype,符合
ResXResourceWriter.BinSerializedObjectMimeType
因此后续可以进入binaryformatter反序列化点,这里会获取Value节点的值,进行base64解码并进行BinaryFormatter反序列化
同理,这个后面还有Soap反序列化点
这也就是ResxPlugins提供给我们的BinaryFormatter、SoapFormatter两个Mode的原理,都是生成类似下面这样的数据:
不过ysoserial.net提供的Payload实际上可以进一步简写,他这么写可能是防止某些奇怪的异常?实际上简写成下面这样也是可以的
因此实战中可以多注意ResXResourceReader()、ResourceSet()等关键词(也要多注意调用栈上的其他方法),如果开发者用了相关的方法处理.resx/.resources文件,那么是很有可能造成RCE的
2.Resx应用其一(某微软白文件的反序列化)
测试这个问题时的意外发现,某个有微软签名的应用居然也有该问题,跟一些会搞免杀的师傅交流了一下,在进程链操作上应该能有用途。这个文件和处理resx文件密切相关,不给出具体的名字,师傅们可以自己找找。该文件中有一个ReadResources()方法,其第二个参数接受一个实现了IResourceReader的类的对象,并且调用了它的GetEnumerator
往上寻找调用并尝试寻找reader入参为ResXResourceReader类的对象的调用点,可以找到一个:
ReadResources(string filename, bool useSourcePath)
继续寻找ReadResources()的调用点,找到ProcessFileWorker()
继续寻找ProcessFileWorker()的调用,找到:
继续寻找,可以找到Main()函数中的调用:
inFiles从用户提交的参数中获取,于是:
该文件有微软签名:
哼哼,留给各位大师傅们解解谜,和处理Resx有关的exe,应该还是很好找的
3.Resx应用其二(webshell)
在web目录下新建一个App_LocalResources目录
将前文提到的恶意resx文件放在App_LocalResources目录下
访问任意一个页面,触发RCE
如果没有App_LocalResources这个目录,我们也可以自己创建,经验比较丰富的师傅应该能想到Windows下UDF提权的场景,通过类似下面这样的文件名:
App_LocalResources::$index_allocation
可以实现目录的创建,或者使用以前提到过的创建文件夹的链子进行文件夹创建
调试这个问题从调用栈来看非常复杂
不过很多从安全从业者视角看起来很复杂的问题,对于开发人员是常识(不信可以自行百度一下App_LocalResources和resx在WEB开发中的应用
因此我们可以知道,如果有App_GlobalResources文件夹,也是可以实现攻击的,不过App_GlobalResources只能位于应用根目录:
4.GetterCallGadgets
顾名思义,这个plugins是帮助我们触发任意属性的Get的,听到这个功能会不会感觉非常耳熟呢?没错,其核心思路就是通过PropertyGrid、ComboBox、ListBox、CheckedListBox相关的一些set去触发目标属性的get,我们以前已经学习过相关的链子了。这个工具的实现方法也非常简单粗暴:
以我们前面介绍过的System.Security.SecurityException类的Method属性为例,其set可以设置序列化payload,并在get中进行反序列化流程,因此我们可以先将这个类以及set赋值的行为转化为json,并放在一个json文件里(我这里是innergadget.json)
然后现在我们要手搓链子尝试触发上述Method属性的get会比较麻烦,我们应该怎么使用GetterCallGadgets plugins快速生成链子呢?使用如下参数:
ysoserial.exe -p GetterCallGadgets -g ListBox -m Method -i .\innergadget.json
m参数决定你要触发哪个属性的Get。其实这个工具就是把之前介绍的通过PropertyGrid、ComboBox、ListBox、CheckedListBox触发Get的姿势写成了小工具,不用我们每次都手动写链子,算是半自动了。
5.NetNonRceGadgets
从名字上看这个Plugins就是用来生成一些不能RCE的链子的,恰巧我们之前也学习过了:
PictureBox和InfiniteProgressPage两个是造成SSRF的链子,FileLogTraceListener是创建目录的链子。用法也很明了,比如:
ysoserial.exe -p NetNonRceGadgets -g PictureBox -f Json.Net -i "http://192.168.1.100/ssrf"
这样就是使用PictureBox这个gadget,攻击的反序列化点类型是Json.Net,触发后往http://192.168.1.100/ssrf地址发起请求