前段时间爆出一个U8cloud的SQL注入,路径为/u8cloud/api/file/upload/base64,在此之前也做过U8cloud的代码审计,没有发现和这个路径类似的路径,正好这次有时间,来复现分析一下这个漏洞到底是怎么回事。
按照网上给出的POC,利用结果如下图,注入点在请求头的system字段。
但是神奇的是,如果吧路径中的file/upload/base64随便替换为其他东西,会发现居然也能成功注入,这就很耐人寻味了,这个漏洞和file/upload/base64居然没有半毛钱关系。
接下来掏出朋友给的一份编译后的源码,全局搜索u8cloud/api,很快就在webapps/u8c_web/WEB-INF/web.xml中找到了这个路径,对应的servlet是ExtSystemInvokerServlet,除了他以外,/u8cloud/openapi/*、/u8cloud/yls/*、/u8cloud/extsystem/dst/*三个路径也都对应到了ExtSystemInvokerServlet。
而这个ExtSystemInvokerServlet的位置在fw.jar!\nc\bs\framework\server\extsys\ExtSystemInvokerServlet。
找到这个类,来看他的doAction()方法。重点关注一下ExtSystemServerEnum和serviceName
ExtSystemServerEnum是一个枚举类,包含/u8cloud/yls、/u8cloud/extsystem/dst、/u8cloud/api/、/u8cloud/openapi/四个常量。
回到上面的doAction()方法,我们要保证我们的request.getRequestURI()必须是以上述四个常量之一开头才可以,否则会抛出异常,也就是说不能按照一般的/servlet/*路径根据模块名和包名去调用,否则就会报错。
此时,如果我们访问的路径是/u8cloud/api/file/upload/base64,就会匹配到/u8cloud/api/,然后serviceName就被赋值为u8cloud_api。
接着一路向下,进入getServiceObject()。
根据serviceName也就是u8cloud_api去找对应的类。这里具体逻辑感兴趣的可以自行去分析,偷了个懒。
根据这项目的惯性,一般就是在各种配置文件中进行的配置。全局搜索一下u8cloud_api,在/modules/uap/META-INF/P_API.upm中找到如下所示的配置,找到u8c.server.APIServletForJSON这么一个类。
继续跟进,在doAction()方法中,会先判断request.getPathInfo(),显然不是以file.开头,进入APIController.forWard(request)。
在APIController.forWard()中,会发现存在checkUser()进行校验,跟进看一下。
在这个地方,看到了本次分析的主角system,通过inputData.getSystem()获取,然后传入APIOutSysUtil.getOutSysVOByCode()中。
继续跟进一下,明晃晃的字符串拼接就出现了,就造成了SQL注入。
还在校验身份甚至没有到校验授权的时候就完成了注入,这也就是我们请求/u8cloud/api/f都可以成功注入的原因了。
自此,关于这个漏洞的一些情况就分析完毕了,但是也还是遗留了一些问题,比如/u8cloud/api/后的服务模块具体是怎么调用的,感兴趣的师傅们就自行去研究了。