记一个黑盒挖到的C#程序反序列化漏洞

Author: TheKingOfDuck

很久之前黑盒挖到的一个漏洞,过程比较有意思。

前置知识:

https://xz.aliyun.com/t/9168
https://xz.aliyun.com/t/9591
https://xz.aliyun.com/t/9593
https://xz.aliyun.com/t/9592
https://xz.aliyun.com/t/9594
https://xz.aliyun.com/t/9595
https://xz.aliyun.com/t/9597
https://xz.aliyun.com/t/9598
https://xz.aliyun.com/t/9599
https://xz.aliyun.com/t/9600
https://xz.aliyun.com/t/9601
https://xz.aliyun.com/t/9602
https://xz.aliyun.com/t/9603
https://xz.aliyun.com/t/9604
https://xz.aliyun.com/t/9605

懒得挨个点开可以直接查看主页:

https://xz.aliyun.com/u/12258

Y4er的文章应该全文背诵.

0x01 起

拿到一个压缩包,里面有个客户端程序但根本不敢运行,怕被反打被钓鱼,所以只是翻了翻程序运行配置和日志,配置中找到一组账号密码,有加密但是估计问题不大,如果账号密码正确直接运行应该是可以登录的。环境有些恶劣,物理机本身都卡装虚拟机运行肯定是不现实的,只得先拖进peid查一下看看是什么程序,研究一下密码明文能不能解出来,没准其他地方也能用。

拖进PEID的时候意外发生了,不小心点了一下导致程序运行了。看到登录框有账号密码虽然验证了猜想,但运行是件非预期的事情,赶紧关闭,然后拖进360杀毒扫了一下,有两个dll报毒...那种恐慌感至今记忆犹新。排查计划任务排查进程删敏感文件,一套操作下来仍不放心,就差关机换机器了。

所幸后续在VT查出报毒的两个dll都是多年前就被标记的,显然不可能是为了当前场景准备的水坑,逆向看代码也未找到什么可疑的代码段,故正常运行,账号也确实可登陆,权限为某部们下的管理员,可查看该部门下所有员工的信息以及跳转认证到一些其他系统,相关功能及站点未发现可getshell的点,该部门也和推断的管理目标的部门有些远,已知了账号规律和默认密码,故希望爆破获取到权限更高一些的账号,方便查看更多的信息,登录更多的系统。

0x02 承

抓包发现流量是有加密的,无法直接爆破,需要解决加密问题。

代码分析:

根据登录按钮的文字提示定位到对应的点击事件:

点击后会判断账号密码验证码这些是否为空,然后进入登录事件OnLoginEvent

往下继续跟会发现比较有意思的点是它没有直接传递输入框中拿到的值,而是塞进UserInfo里,再调用SendLoginMsg方法进一步处理

继续套娃,将UserInfo塞到MsgSysInfo再调zip的对象中GetBuffer方法去处理最后交个给Login方法,看到这初步怀疑程序可能有问题,就算没有直接传递相关值,那到最后发送相关的处理前应该要转成json之类的才符合预期。

zipdh是分别在构造方法及其调用的Init方法中初始化完成,前者里面的相关方法主要是数据压缩加密,后者是数据发送。

先看被调用的YYSharpZip中的GetBuffer方法,调用顺序如下图所示,GetZipBuffer方法在压缩之前先调BinaryFormatter对传入的对象进行了序列化操作,完了再去调加密方法EncryptData进行数据加密。

客户端对数据处理的过程中有序列化的操作,那服务端接受到数据后必然有反序列化的操作,盲猜有洞,整理调用流程如下:

this.btnLogin_Click --> this.OnLoginEvent() --> this.SendLoginMsg() --> this.zip.GetBuffer() --> this.ZipData() --> this.GetZipBuffer() --> new BinaryFormatter().Serialize() --> this.CompressToByte() --> new YYEncrypt().EncryptData() --> this.dh.Login()

盲猜服务器处理逻辑流程如下:

XXX.MsgReceive --> new YYEncrypt().DecryptData-->this.DeCompressToBytes --> new BinaryFormatter().Deserialize() --> this.msgSysInfo.getLoginInfo() --> XXX

漏洞验证逻辑应当如下:

Ysoserial.NET --> Gadget serialize data --> this.zip.GetBuffer --> this.ZipData --> this.GetZipBuffer --> new BinaryFormatter().Serialize() --> this.CompressToByte --> new YYEncrypt().EncryptData --> Send To Tartget Server --> XXX.MsgReceive --> new YYEncrypt().DecryptData-->this.DeCompressToBytes --> new BinaryFormatter().Deserialize() --> Attack success

0x03 转

按照猜想的验证逻辑写好漏洞利用代码,本地测试了几条Gadget后成功弹出计算器。

本地成功弹出计算器的Gadget在目标上并未正常执行,依然是重新试了几条Gadget后命令才得以执行成功,写文件访问不到,Ysoserial.NET中提供的回显方法当时未测试成功,时间紧也没法投入精力去研究其原因,Windows一直无回显执行命令就怪难受的...所幸服务器的发现服务器其他端口开了iis. 默认路径写aspx拿到shell.

0x04 合

程序是通用的,前前后后打了七八个shell,由于其自带的加密给payload上了保护伞,攻击过程并未被发现过,有意思的是内网扫描被发现后起初防御人员排查的时候采取的措施是删除某个打payload前会探测的特征文件。🐮得很,可关服务器才是最强防御措施!

整个过程并未看到过服务端代码,看似黑盒,可站在开发的逻辑上来看,盲猜的处理逻辑是完全合理的,也就说漏洞其实是一个理所应当的过程,开发就要那么写,能怎么办? ORZ不如换份开发的工作去卷他们的饭碗得了...

一个热爱域渗透/WAF绕过/免杀/代码审计/工具开发的憨批