CodeQL静态代码扫描之抽象类探究

admin 2022年1月7日08:45:26代码审计评论17 views4119字阅读13分43秒阅读模式

CodeQL静态代码扫描之抽象类探究

抽象类探究

 

我在阅读了CodeQL大量插件的代码的情况下发现了一个有趣的结构,这个结构就是抽象方法实例化的时候会自动执行子类的方法,而不需要调用子类的方法。这个结构大量存在于CodeQL的规则中,这里我以CWE-022,TaiantedPath.ql作为例子来讲解

 

首先这个规则的主体是:


 

CodeQL静态代码扫描之抽象类探究


在上一课的讲解中,我们了解到了数据流必须使用DataFlow::xxx和TaintTracking::configuration,其中conf是对数据流进行配置,而这里,我圈出来的any()方法中的就是对一个sink的约束,他的约束主要在PathCreation类和guarded谓词中。这里重点就是在讲解PathCreation类。

首先它是一个静态类。作者抽象了PathCommon.qll库。在这个库里我们可以看到这个方法的原型(Construtor),我把它抽象下结构如下:

abstract class PathCreation extends Expr  {
abstract Expr getInput();
}
class PathsGet extends PathCreation, MethodAccess {
PathsGet() {

}
override Expr getInput() { result = this.getAnArgument() }
}
class FileSystemGetPath extends PathCreation, MethodAccess {
FileSystemGetPath() {

}
override Expr getInput() { result = this.getAnArgument() }
}
class FileCreation extends PathCreation, ClassInstanceExpr {
FileCreation() { …}

override Expr getInput() {
result = this.getAnArgument() and
// Relevant arguments include those that are not a `File`.
not result.getType() instanceof TypeFile
}
}

class FileWriterCreation extends PathCreation, ClassInstanceExpr {
FileWriterCreation() { this.getConstructedType().getQualifiedName() = "java.io.FileWriter" }

override Expr getInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
predicate inWeakCheck(Expr e) {
none()
}
// Ignore cases where the variable has been checked somehow,
// but allow some particularly obviously bad cases.
predicate guarded(VarAccess e) {
none()
)
}

聪明的你可以发现,下面的子类都是继承于PathCreation类,并且重写了一个getInput方法,这个方法我们可以看到都带有result关键词,并且是一个带类型的返回型谓词,根据官方文档的说明,带result就会把符合条件的集合返回。而且可以看到,返回的谓词中大部分都有this.getAnArgument,这个意思就是返回满足上面的参数集合,他们有一个共性,都extends 了PathCreation类。那时候我就好奇了,这个类全文却没地方调用过,或者实例化。

CodeQL静态代码扫描之抽象类探究



全文档搜索了也没发现有这个类的实例化。然后我对这个规则简单的调试了下,发现注释掉部分子类的代码,并且执行了PathCreation和PathGet、 FileCreation和FileWriterCreation发现就是这几个子类的总集合。

 

这是总的集合


 

CodeQL静态代码扫描之抽象类探究

这是PathGet


 

CodeQL静态代码扫描之抽象类探究

这是FileCreation


 

CodeQL静态代码扫描之抽象类探究


到此,我们可以得出一个结论: CodeQL对抽象类的查询会筛选出所有满足子类条件的结果集合,而至于需不需要返回,这个就需要你自己去手动定义个谓词来返回。

 

到这里我相信你就可以去理解一些必须要理解的类,比如RemoteFlowSource类,这对编写插件如何更好的排版代码编写规则逻辑也很有帮助!

下面是PathsCommon的主体的注释,希望能帮你理解

abstract class PathCreation extends Expr {    abstract Expr getInput();  }    class PathsGet extends PathCreation, MethodAccess {    // 寻找`java.nio.file.Paths`类下的get方法    PathsGet() {      exists(Method m | m = this.getMethod() |        m.getDeclaringType() instanceof TypePaths and        m.getName() = "get"      )    }    // 返回这个方法的集合    override Expr getInput() { result = this.getAnArgument() }  }    class FileSystemGetPath extends PathCreation, MethodAccess {    // 寻找`java.nio.file.FileSystem`类下的getPath方法并通过getInput方法返回这个集合    FileSystemGetPath() {      exists(Method m | m = this.getMethod() |        m.getDeclaringType() instanceof TypeFileSystem and        m.getName() = "getPath"      )    }      override Expr getInput() { result = this.getAnArgument() }  }    class FileCreation extends PathCreation, ClassInstanceExpr {    //   限定实例化的对象的原型在`java.io.File`类下    // 例如new xxx()  这个xxx必须在`java.io.File`下    FileCreation() { this.getConstructedType() instanceof TypeFile }      override Expr getInput() {        // 获得上述实例化的class的参数,并且这个参数的类型必须是file类型的,并返回满足and条件的参数集合      result = this.getAnArgument() and      // Relevant arguments include those that are not a `File`.      not result.getType() instanceof TypeFile    }  }    class FileWriterCreation extends PathCreation, ClassInstanceExpr {    //   限定在`java.io.FileWriter`类下    FileWriterCreation() { this.getConstructedType().getQualifiedName() = "java.io.FileWriter" }    // 返回参数类型是String类型的参数    override Expr getInput() {      result = this.getAnArgument() and      // Relevant arguments are those of type `String`.      result.getType() instanceof TypeString    }  }    predicate inWeakCheck(Expr e) {    // None of these are sufficient to guarantee that a string is safe.    // 约束一个类下的方法如果是startswith等方法,注意这里的方法是原生的,这里建议扩大覆盖范围,使用matches去匹配类似的方法名    exists(MethodAccess m, Method def | m.getQualifier() = e and m.getMethod() = def |      def.getName() = "startsWith" or      def.getName() = "endsWith" or      def.getName() = "isEmpty" or      def.getName() = "equals"    )    or    // Checking against `null` has no bearing on path traversal.    exists(EqualityTest b | b.getAnOperand() = e | b.getAnOperand() instanceof NullLiteral)  }    // Ignore cases where the variable has been checked somehow,  // but allow some particularly obviously bad cases.  predicate guarded(VarAccess e) {    //   一个参数必须存在于上面抽象类返回结果的集合中且条件分支为True的情况下的方法,还要不是StartsWith等方法    exists(PathCreation p | e = p.getInput()) and    exists(ConditionBlock cb, Expr c |      cb.getCondition().getAChildExpr*() = c and      c = e.getVariable().getAnAccess() and      cb.controls(e.getBasicBlock(), true) and      // Disallow a few obviously bad checks.      not inWeakCheck(c)    )  }


本文始发于微信公众号(xsser的博客):CodeQL静态代码扫描之抽象类探究

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月7日08:45:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  CodeQL静态代码扫描之抽象类探究 http://cn-sec.com/archives/481871.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: