南浔区建设局 网站,wordpress数据接口,互联网项目名称大全,电子商务网站开发公司前言网上关于codeql的文章并不多#xff0c;国内现在对codeql的研究相对比较少#xff0c;可能是因为codeql暂时没有中文文档#xff0c;资料也相对较少#xff0c;需要比较好的英语功底#xff0c;但是我认为在随着代码量越来越多#xff0c;传统的自动化漏洞挖掘工具的…前言网上关于codeql的文章并不多国内现在对codeql的研究相对比较少可能是因为codeql暂时没有中文文档资料也相对较少需要比较好的英语功底但是我认为在随着代码量越来越多传统的自动化漏洞挖掘工具的瓶颈无法突破的情况下codeql相当于是一种折中的办法通过codeql的辅助来减少漏洞挖掘人员的工作更加关注漏洞的发现和利用过程之所以选ofcms是因为有p0desta师傅之前的审计经验而且使用codeql审计cms尚属第一次所以选用了ofcms审计ql构造在ql中漏洞挖掘是根据污点追踪进行的所以我们需要知道我们的挖掘的cms的source点在哪里sink点在哪里相对来说source点比较固定一般就是http的请求参数请求头这一类的但是sink比较难以确定由于现在的web应用经常使用框架有些文件读取html输出其实是背后的框架在做所以这就导致了我们的sink定义不可能是一成不变的要对整个web应用有一个大致的了解才能定义对应的sinksource点的qlsource点很清楚对于一个web应用来说http请求参数http请求头我们关注ofcms中对请求参数的获取方式ofcms使用了jfinal这个框架而ofcms继承了jfinal的controller来获取参数在整个ofcms中大体有三种类型来获取请求参数BaseControllerController(Jfinal提供)ApiBase所以我们的source都是根据这几个类展开的在观察这几个类之后很容易发现所有的获取http参数的方法都是getXXX()这样的命名方式所以我们可以这样定义source的ql语法class OfCmsSource extends MethodAccess{OfCmsSource(){(this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.admin.controller, BaseController) and(this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(com.jfinal.core, Controller) and(this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(javax.servlet.http, HttpServletRequest) and (this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.api, ApiBase) and(this.getMethod().getName().substring(0, 3) get))}}到这一步我们的source就算定义完了接下来就是定义对应的sink了sink点的ql相对于source的固定sink就很不固定了常见的web漏洞一般来说都可以作为sink而且因为框架的不同同一种漏洞在不同框架下的ql都是不一样的所以我们需要略微分析一下整个web应用在做文件读取模版渲染等操作的时候一般都用的是什么方法模版渲染的问题Jfinal中对模版渲染有一系列的render方法可以看到所有都是render开头所以我们对方法名的判断很简单截取前面6个字符判断是否为render随便找一个项目使用render的地方可以发现render其实是在com.jfinal.core.Controller里面定义的方法所以现在我们唯一确定了模版渲染的方法所以我们的sink也就呼之欲出了也就是这些render方法的参数所以构造qlclass RenderMethod extends MethodAccess{RenderMethod(){(this.getMethod().getDeclaringType*().hasQualifiedName(com.jfinal.core, Controller) andthis.getMethod().getName().substring(0, 6) render) or (this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.core.plugin.freemarker, TempleteUtile) and this.getMethod().hasName(process))}}在上面的ql中我添加了TempleteUtile这个类因为这个类的process第一个参数可控的话也会造成模版的问题所以我们可以随时去到ql中添加我们认为可能出现问题的模版渲染方法文件类的问题在ofcms中文件的创建一般都是new File()这种形式创建的所以我们的sink点应该为new File的参数为我们的sink点所以构造qlclass FileContruct extends ClassInstanceExpr{FileContruct(){this.getConstructor().getDeclaringType*().hasQualifiedName(java.io, File)}}污点追踪codeql提供了几种数据流的查询local data flowlocal taint data flowglobal data flowglobal taint data flowlocal data flow基本是用在一个方法中的比如想要知道一个方法的入参是否可以进入到某一个方法就可以用local data flowglobal data flow是用在整个项目的也是我们做污点追踪用的最多的简单解释一下taint和非taint有什么区别taint的dataflow会在数据流分析的基础上加上污点分析比如String a evil;String b a a;在使用taint的dataflow中b也会被标记为被污染的变量构造configureclass OfCmsTaint extends TaintTracking::Configuration{OfCmsTaint(){this OfCmsTaint}override predicate isSource(DataFlow::Node source){source.asExpr() instanceof OfCmsSource}override predicate isSink(DataFlow::Node sink){exists(FileContruct rawOutput |sink.asExpr() rawOutput.getAnArgument())}}当我们需要去做污点分析的时候我们需要继承TaintTracking::Configuration这个类来重写两个方法isSource和isSink在这里dataflow中的Node节点和我们直接使用的节点是不一样的我们需要使用asExpr或者asParamter来将其转换为语法节点这里可以看到我们的source为我们之前定义的http参数的输入地方sink为我们之前定义的new File的这种实例化结果分析codeql只能给出从source到sink的一条路径但是这条路径中的一些过滤和条件是无法被判断的这也就需要一部分的人工成本让我们来运行一下我们刚刚写的qlimport ofcmsfrom DataFlow::Node source, DataFlow::Node sink, OfCmsTaint configwhere config.hasFlow(source, sink)select source, sink最后的查询结果可以看到找到了11个可能存在问题的地方我们来依次看一看是否有问题ReprotAction第一个在ReprotAction这个类的expReport方法中可以很明显看到在获取j参数之后对jrxmlFileName没有任何的校验导致我们可以穿越到其他目录但是文件后缀名必须为jrxml而且在JasperCompileManager的compileReport函数中对xml文档没有限制实体导致可以造成XXE漏洞这里很尴尬的利用点是需要一个文件上传后缀名必须为jrxmlTemplateController在TemplateController这个类的getTemplates方法中在这里对获取的参数没有任何的校验导致可以跨越目录列文件并且修改文件但是在后面的实现中我们只能修改和查看特定的文件假设我们在tmp目录下有着a.html和a.xml文件我们可以跨越到tmp目录下读取并修改这两个文件TemplateController还有一个地方就是save函数这个函数在p0desta师傅的博客中也挖掘出了任意文件上传漏洞很明显的一任意文件上传文件名路径文件内容全部可控直接getshell剩下的一个并不能造成影响就不多说了后记在render的sink定义中如果运行可以发现很多地方的前台的一个小问题也就是我们可以指定模版文件ofcms使用了freemarker模版引擎如果可以包含到我们自定义的模版文件即可导致RCE但是并没有发现有一个文件上传的点可以上传文件到模版目录下(除了上面的一个任意文件上传)所以不太好前台RCE顺手测了下发现前台评论地方有存储XSS但是和codeql无关就不多说了整个qlofcms.qllimport javaimport semmle.code.java.dataflow.TaintTrackingclass OfCmsSource extends MethodAccess{OfCmsSource(){(this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.admin.controller, BaseController) and(this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(com.jfinal.core, Controller) and(this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(javax.servlet.http, HttpServletRequest) and (this.getMethod().getName().substring(0, 3) get))or(this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.api, ApiBase) and(this.getMethod().getName().substring(0, 3) get))}}class RenderMethod extends MethodAccess{RenderMethod(){(this.getMethod().getDeclaringType*().hasQualifiedName(com.jfinal.core, Controller) andthis.getMethod().getName().substring(0, 6) render) or (this.getMethod().getDeclaringType*().hasQualifiedName(com.ofsoft.cms.core.plugin.freemarker, TempleteUtile) and this.getMethod().hasName(process))}}class SqlMethod extends MethodAccess{SqlMethod(){this.getMethod().getDeclaringType*().hasQualifiedName(com.jfinal.plugin.activerecord, Db)}}class FileContruct extends ClassInstanceExpr{FileContruct(){this.getConstructor().getDeclaringType*().hasQualifiedName(java.io, File)}}class ServletOutput extends MethodAccess{ServletOutput(){this.getMethod().getDeclaringType*().hasQualifiedName(java.io, PrintWriter)}}class OfCmsTaint extends TaintTracking::Configuration{OfCmsTaint(){this OfCmsTaint}override predicate isSource(DataFlow::Node source){source.asExpr() instanceof OfCmsSource}override predicate isSink(DataFlow::Node sink){exists(FileContruct rawOutput |sink.asExpr() rawOutput.getAnArgument())}}test.qlimport ofcmsfrom DataFlow::Node source, DataFlow::Node sink, OfCmsTaint configwhere config.hasFlow(source, sink)select source, sink不足感觉一个很大的问题是sink的定义因为框架的变换以及一些开发者自己的工具类以及一些漏洞可能根本不存在导致sink的定义有时候挖不出来漏洞像p0desta师傅测的CSRF漏洞暂时想不到有什么好的办法来定义sink人工可能很好去看出来但是不好用codeql语言定义这种漏洞太菜了有个点的任意文件读取写不出来ql2333师傅们教教我感觉在定义的时候要尽量找共性但是也不能找太深参考文章