服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

弈 - Codeql 自动运行和项目监控工具

日期: 来源:默安逐日实验室收集编辑:Zhuri

前言

代码审计总是离不开一些神器,笔者常用 Codeql[1] 这款工具辅助挖洞。当我每写一个规则都需要对其它项目手动运行检查一遍,效率很低,再加上 lgtm[2] 的关闭,此项目诞生了 --- 弈(Yi)[3] 。

CVE-2021-43798

这里以 Graana 的任意文件读取漏洞举例说明使用方法(初学 Codeql,如有错误之处,轻点喷)。
该漏洞版本为 8.0.0 - 8.3.0 , 修复版本为 8.3.1, 8.2.7, 8.1.8, 8.0.7。
git clone https://github.com/grafana/grafana
git checkout v8.2.6
这个漏洞发生在 /public/plugins/:pluginId/* api 中,当输入的 pluginId存在时,会匹配*内容,使用filepath.Clean清理路径中的多余字符后,直接拼接到pluginFilePath,然后使用os.open(pluginFilePath)打开该文件,最终回显到页面。而且plugins api权限为public,是未授权的,任何人都可以查看。

fmt.Println(filepath.Clean("./.../../../../../../../etc/passwd"))

输出:../../../../../etc/passwd 只清除了前面的./.../../

Codeql分析

生成 codeql 数据库:
codeql database create /Users/yhy/CodeQL/database/go/grafana/v8.2.6 -s ./ --language=go


sink

os.open(),这个显而易见。
import go
import DataFlow::PathGraph

class Sink extends DataFlow::Node {
    Sink() {
        exists(
            DataFlow::CallNode call |
            call.getTarget().hasQualifiedName("os", "Open") |
            call.getArgument(0) = this // 标记 sink 为 os.Open 第一个参数
        )
    }
}


source

我将 Source 点定在了macaron.Params()函数。
网上的文章都是以github.com/grafana/grafana/pkg/api/routing.RouteRegister作为起始点,这就导致一个问题,写完的规则只对grafana项目起作用,不通用。
仔细研究会发现,RouteRegister的实现是以gopkg.in/macaron.v1框架为基础的,但是官方的go/ql/lib/semmle/go/frameworks/Macaron.qll,只是实现了一个重定向相关的检测规则,emmm,只能自己动手写了。
写着写着忽然发现,怎么也获取不到macaron.Params, 去看 macaron[4] 源码才发现,这个函数就根本没有,是Grafana自己实现的。我们来分析一下这个 Params 函数。

其实就是获取net/httpRequest.Context的值,而参数r,又是通过pkg/macaron/context.go

也就是 macaron[5] 框架中的Context结构体中的Req成员,这个Req就是我们要找的Source点。
修改go/ql/lib/semmle/go/frameworks/Macaron.qll文件,加入如下代码:
  private class UserControlledRequestField extends UntrustedFlowSource::Range, DataFlow::FieldReadNode {
  UserControlledRequestField() {
    exists(string fieldName | this.getField().hasQualifiedName("gopkg.in/macaron.v1", "Context", fieldName) | 
    fieldName = "Req"
        )
    }
  }
单独执行,可以找到污染点。

直接将 sink、source 拼接跑,并没有出结果,因此需要一些处理来连接数据流。

isAdditionalTaintStep

这里 tyskill[6] 师傅说的很详细,引用一下:
  1. 1. 限制函数为Params。

  2. 2. 函数可被污染就说明参数可控,那么就让pred节点作为参数。

  3. 3. SimpleAssignStmt结构表示一个赋值表达式,如a+=b,Rhs表示等号右边,通过查看源码可知Params函数调用几乎都是在等号右边,因此可以通过该结构减少误报。

  4. 4. 最后将输出节点连接到赋值表达式。


    override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
        exists(
            CallExpr call, SimpleAssignStmt sas |
            // call.getTarget().getName() = "Params" and
            // 限制为 Params 函数会产生局限性,去除
            call.getAnArgument() = pred.asExpr() and
            sas.getRhs().getAChild() = call.getParent*().getAChild() and
            // 使用getParent*()是因为等号右边不止有光秃秃的Params方法调用,如漏洞点就存在Jion函数拼接操作,需要通过传递闭包getParent*()来获取完整表达式
            // 使用getAChild()则是要获取Params的方法调用,不过测试发现用不用效果差不多,所以也不懂为什么还要加这个
            sas.getRhs() = succ.asExpr()
        )
    }


    运行,成功发现该漏洞。


加入工具监控、扫描

因为项目中调用 Codeql 将扫描结果保存为文件,这里需在文件头添加一些描述,完整代码如下:
/**
 * @name read file
 * @description read file
 * @kind path-problem
 * @problem.severity error
 * @security-severity 6.1
 * @sub-severity high
 * @id yhy0/read-file
 * @tags security
 * @precision high
 */
import go
import DataFlow::PathGraph

class ReadFileSink extends DataFlow::Node {
    ReadFileSink() {
        exists(
            DataFlow::CallNode call |
            call.getTarget().hasQualifiedName("os", "Open") |
            call.getArgument(0) = this // 标记 sink 为 os.Open 第一个参数
        )
    }
}

class ReadFileConfig extends TaintTracking::Configuration {
    ReadFileConfig() { this = "read file" }
    // 这里的 source 实现 UntrustedFlowSource ,方便其他框架通用, 对于Grafana ,我们已经修改了go/ql/lib/semmle/go/frameworks/Macaron.qll文件
    override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
    override predicate isSink(DataFlow::Node sink) { sink instanceof ReadFileSink }
    override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
        exists(
            CallExpr call, SimpleAssignStmt sas |
            // call.getTarget().getName() = "Params" and
            // 限制为 Params 函数会产生局限性,去除
            call.getAnArgument() = pred.asExpr() and
            sas.getRhs().getAChild() = call.getParent*().getAChild() and
            // 使用getParent*()是因为等号右边不止有光秃秃的Params方法调用,如漏洞点就存在Jion函数拼接操作,需要通过传递闭包getParent*()来获取完整表达式
            // 使用getAChild()则是要获取Params的方法调用,不过测试发现用不用效果差不多,所以也不懂为什么还要加这个
            sas.getRhs() = succ.asExpr()
        )
    }
}

from ReadFileConfig rfc, DataFlow::PathNode sink, DataFlow::PathNode source
where rfc.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "read file find on $@.", source.getNode(), "user-provided value"

将此 ql 文件路径加入配置文件config.yaml中, - go/ql/src/myRules/ReadFile.ql ,之后程序会自动对监控的项目运行此条规则,等待捡洞即可(笔者已经捡到了^_^)。

效果图




项目的具体介绍请看 https://github.com/ZhuriLab/Yi 。

参考资料

  • https://tyskill.github.io/posts/codeql-grafana/#%E5%AE%9E%E8%B7%B5grafana%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96

  • https://xz.aliyun.com/t/10648

  • https://codeql.github.com/


引用链接

[1] Codeql: https://github.com/github/codeql-cli-binaries
[2] lgtm: lgtm.com/
[3] 弈(Yi): https://github.com/ZhuriLab/Yi
[4] macaron: https://github.com/go-macaron/macaron
[5] macaron: https://github.com/go-macaron/macaron
[6] tyskill: https://tyskill.github.io/posts/codeql-grafana/#%E5%AE%9E%E8%B7%B5grafana%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96


相关阅读

  • 一点微小的贡献,逐日为云原生安全保驾护航

  • 在后疫情时代,如何上好云、用好云成为了企业 IT 信息化转型中的核心关注点,降本增效成为企业云原生上云的一致性共识,越来越多的企业开始向云原生探索,但是云原生安全是不可缺少
  • 恒大柯鹏是替罪羊吗

  • 拉第4个微信群了,欢迎来自银行、券商、基金、保险、AMC、房企的朋友,大家心平气和地聊一些独家消息入群和开白可加猫总微信:doudeera他曾是许家印最大的反对者,后来成为最忠诚的
  • 恒大迎来最强纾困天团

  • 拉第4个微信群了,欢迎来自银行、券商、基金、保险、AMC、房企的朋友,大家心平气和地聊一些独家消息入群和开白可加猫总微信:doudeera深圳恒大时代之光,位于龙华区上芬地铁站西侧
  • 市场延续涨势,能源REITs上市进度更新

  • 文丨明明债券研究团队核心观点去年下半年以来,公募REITs的阶段性走势与债券资产体现出更强相关性,这与当前REITs的投资人结构有密不可分的关系。站在当前时点,基本面和政策预期
  • 盘活资产距离化债有多远?

  • 摘要厘清盘活存量资产的内涵。首先明确,用于盘活的存量资产主要有三类,一是存量规模较大、当前收益较好或增长潜力较大的基础设施项目资产,二是存量和改扩建有机结合的项目资产
  • 【国信宏观固收】私募EB每周跟踪

  • 分析师:王艺熹 S0980522100006分析师:董德志 S0980513100001我们定期梳理从公开渠道可获得的最新的可交换私募债(私募EB)项目情况,对私募可交换债项目做基本要素跟踪,私募发行条
  • constexpr

  • 前面介绍了模板这种编译期动作,关于编译期动作,有必要介绍下constexpr。在这之前有必要简单提一下constexpr与const的关系,两者字面上都表达常量的意思。主要的区别是:const修饰
  • 项目门槛低,怎样使项目持续运转并放大?

  • 回顾一下之前聊过的几个小故事1 前不久,一位线上会员稳哥来工作室做客稳哥在会员群里也是很喜欢分享自己做项目的经验,时不时会在凌晨的会员群炸出一波实操干货让我们记住稳哥

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 弈 - Codeql 自动运行和项目监控工具

  • 前言代码审计总是离不开一些神器,笔者常用 Codeql[1] 这款工具辅助挖洞。当我每写一个规则都需要对其它项目手动运行检查一遍,效率很低,再加上 lgtm[2] 的关闭,此项目诞生了 ---
  • K8S后渗透横向节点与持久化隐蔽方式探索

  • 前言通常在红蓝对抗中,我们可能会通过各种方法如弱口令、sql注入、web应用漏洞导致的RCE等方法获得服务器的权限;在当前云原生迅猛发展的时代,这台服务器很可能是一个容器,在后
  • Linux Capabilities利用总结

  • 前言Linux对于权限的管理,系统权限只有root才有,对于普通用户只有一些有限的权限;而对于普通用户如果想进行一些权限以外的操作,之前主要有两种方法:一是通过sudo提权;二是通过SUI
  • 一点微小的贡献,逐日为云原生安全保驾护航

  • 在后疫情时代,如何上好云、用好云成为了企业 IT 信息化转型中的核心关注点,降本增效成为企业云原生上云的一致性共识,越来越多的企业开始向云原生探索,但是云原生安全是不可缺少
  • K8S API访问控制之RBAC利用

  • 前言K8S对于API的访问安全提供了访问控制,主要为4个阶段,本文为第二个阶段——鉴权的RBAC。RBAC是基于角色的访问控制,使用kubeadm安装集群1.6版本以上的都默认开启了RBAC。本
  • Weblogic安全漫谈(一)

  • 前言@frohoff在2015年初发现commons-collections的反序列化利用链并发布了ysoserial工具[1]。9个月后,@breenmachine对众多知名Java中间件的利用文章[2]使Java反序列化漏洞变