复现环境
致远 V7.1SP1
补丁分析
致远官方在2023年8月发布了rest接口重置密码漏洞补丁,补丁链接https://service.seeyon.com/patchtools/tp.html#/patchList?type=%E5%AE%89%E5%85%A8%E8%A1%A5%E4%B8%81&id=175
致远是通过jersey
框架实现REST
接口,通过配置init-param
参数来添加过滤器类,添加后,在进入到资源类之前,会先进入到过滤器类,一些校验的逻辑就可以写在过滤器中。
rest接口重置密码漏洞补丁的工作原理是通过将用户角色权限与资源访问权限的逻辑写在ResourceCheckRoleAccessFilter
类中,在ResourceCheckRoleAccessFilter
的filter
方法中,会以访问资源类的类名及方法名和当前用户作为参数调用RestCheckRoleAccessManagerImpl
的checkRole
方法,验证当前用户是否具有访问资源类的权限,如果不具备访问权限,则抛出异常。
在补丁包中checkRoleAccessInfo.properties
配置文件中,定义了com.seeyon.ctp.rest.resources.MemberResource
类中方法已经对应的用户访问权限。
在MemberResource.class
的changePassword
方法中,可通过指定memberid
和password
对用户密码进行修改。
致远中存在一些自带的用户,这些用户的memberid
值都是固定的,正常情况下,我们可以通过changePassword
方法修改system
等用户的密码。
seeyon-guest -6964000252392685202
system -7273032013234748168
audit-admin -4401606663639775639
group-admin 5725175934914479521
rest接口权限校验
在CTPSecurityFilter.class
的doFilter
方法中,根据uri
的特征,分别有7种权限校验的方法。
当uri
的前缀为/seeyon/rest/
时,会调用RestAuthenticator.class
的authenticate
方法进行验证,该接口仅支持token
进行认证,不允许使用Session
。
在致远的开放平台描述了toekn的获得方式,https://open.seeyon.com/book/ctp/restjie-kou/gai-shu.html
两个步骤,1、登录系统用户创建一个rest用户,
2、通过/seeyon/rest/token/{restusername}/{password}
接口获取token
获取到token
以后,就可以调用changePassword
方法修改密码了,调用路径/seeyon/rest/orgMember/{id}/password/{password}
,这里将system
用户密码修改为123456
。
通过system管理员创建rest用户,在通过rest用户获取token,最后通过token访问接口修改密码,利用的前提需要一个管理员账号,难免有些鸡肋。而访问rest接口只能是token,而token只能通过管理员创建rest用户拿到,看起来是个死结,实际上大佬们的思路是另辟蹊径。
权限绕过
回到CTPSecurityFilter.class
的doFilter
方法中,在进入到rest
接口的权限校验方法前,会先判断是不是SpringController
的请求。
当uri
的后缀为.do
或者 .do;jessionid=
的时候,那么就会进入到SpringControllerAuthenticator
的authenticate
方法中进行验证。
而rest接口修改密码的路由为/seeyon/rest/orgMember/-7273032013234748168/password/123456
,123456
为我们需要修改的密码,当把密码写成123456.do
或者123456.do;jessionid=
,即可让该请求走SpringControllerAuthenticator
的authenticate
方法中进行验证,所以只需要普通用户的权限就可以修改管理员的密码。
武器化利用思考
致远中存在一些接口,是可以RCE的,但是设置了访问权限,当拿到管理员权限以后,我们可以通过管理员权限为普通用户赋予一些访问权限,然后调用这些接口实现RCE,另一个是通过管理员权限创建普通用户留后门。
修复
在致远 8.2之后版本的CTPSecurityFilter.class
中,除验证uri路径以.do
结尾以外,还验证了该uri是否为rest
接口,限制了普通用户禁止通过SpringController
的验证逻辑去访问rest
接口。