漏洞接口
1 | /constDef.do?method=newConstDef |
该接口对应 com.seeyon.ctp.view.modules.operationcenter.constdef.controller.ConstDefController的newConstDef方法。
该方法接收了一些参数,创建了ConstDef对象,调用了this.constDefManager.insertConstDef(def)方法进行插入。
![]() |
|---|
该方法中对constKey、constDefine参数进行验证,然后调用了this.findByConstKey(def.getConstKey())
![]() |
|---|
该方法会以构建一个ConstDef对象,设置constKey,然后调用this.constDefDao.findByExample(def),这个方法会以constKey查找一组ConstDef对象,再以ConstDef对象作为参数调用this.updateConstValue(result)。
![]() |
|---|
通过this.constDefDao.findByExample(def)找到ConstDef对象的情况下,会以该对象的constKey调用ConstDefUtil.getConstDefValue(def.getConstKey())方法。
![]() |
|---|
继续以constKey作为参数调用了ConstDefCacheManager.getInstance().getConstDefValue(constKey)
![]() |
|---|
该方法首先会通过constkey作为参数在this.cacheMap中获取ConstDef对象,this.cacheMap中保存的为之前插入的ConstDef对象。拿到ConstDef对象后,使用ConstDef对象作为参数调用this.computeConstValue(def)方法。
![]() |
|---|
![]() |
|---|
在computeConstValue方法中,能看到两处调用evalString和eval方法
![]() |
|---|
![]() |
通过constDefine作为参数,使用groovy计算表达式。
![]() |
|---|
要想进入到groovy命令执行的方法调用中,需要constDefine的值中包含$,且constType需要指定为3或者4。
![]() |
|---|
首先会调用_parserRefKey方法对constDefine进行解析。会通过$界定一组关键字,如$a$,最终会在refs中添加a。
![]() |
|---|
调用ScriptEvaluator.getInstance().evalString(constDefine, context)。使用"进行包裹,进而调用了this.eval()
![]() |
|---|
最后就进入到Groovy命令执行漏洞利用点。
![]() |
|---|
在ScriptEvaluator.getInstance().evalString(constDefine, context) 执行这里面会通过"把scriptText包裹起来,如果直接传入java.lang.Runtime.getRuntime().exec(\"calc\");会报错,可指定constType=3,也可通过如下方式进行拼接即可绕过。
1 | "+"java.lang.Runtime.getRuntime().exec("calc");//$a\" |
这里漏洞的利用,需要提交3次请求,第一次请求需要随机指定一个constKey和constDefine进行提交。
如果不指定直接提交会提示{"error":"操作异常操作失败, 常量引用不存在"}。
![]() |
|---|
所以第二次提交需要在$xx$中引用第一次提交的constKey,但是这一次提交不会触发命令执行,因为在调用this.constDefDao.findByExample(def)进行查找的时候,因为constDefDao中不存在第二次提交的constKey,所以不会进入updateConstValue的if条件中。只有第三次提交,才会从获取到第二次提交的ConstDef对象,进入updateConstValueif条件中,进而触发命令执行。
![]() |
|---|
![]() |
|---|
![]() |
|---|
问题
ctp_const_def表中保存的是ConstDef对象各个属性的值,CONST_DEFINE字段中保存的是constDefine的值,但是该字段限制最大长度为200。
![]() |
|---|
![]() |
|---|
漏洞进一步利用
由于CONST_DEFINE保存的是执行的代码,需要先插入到数据库中,再取出执行,该字段规则限制的长度为200。为了绕过该规则,可以通过上传一个后缀为png,内容为webshell的文件,然后再通过执行代码的方式将文件从上传路径移动到web路径实现RCE。
1 | java.io.File file = new java.io.File("..\\..\\base\\upload\\2023\\12\\15\\8115437553340205223");java.io.File endFile = new java.io.File("..\\webapps\\ROOT\\666.jsp");file.renameTo(endFile);//$b1$ |
1 | POST /seeyon/constDef.do HTTP/1.1 |



















