c++代码健壮性_复活Navex-使用图查询进行代码分析(上)

46ef1cc623e23c1816ae3857970f3175.png
从了解到修复 Navex, 其中花了一年多, 从对自动化代码审计一无所知到学习PL/Static Analysis, 翻阅十几年前的文档, 补全Gremlin Step, 理解AST, CFG, DDG, PDG, CPG, 也感谢z3r0yu师傅和Gaba哥的的交流指导.
本文重点在于静态分析 Joern-图查询部分, 后面的动态分析自动生成EXP部分是剪枝的过程, 也相对好实现, 各位有兴趣的话, 我会在下一篇文章继续谈论.
这里不得不说的Navex实际的效果没有描述的那么优秀, 以及作者故意在代码里埋坑, 毕竟人家也研究了快十年, 留一手也是正常的.
这里不是说一定非要完成/使用Navex, 而是借鉴新鲜的学术思想, 结合实际环境实现相关功能来降低排查漏洞成本.

预备知识

Navex 是什么

下面这段摘自z3r0yu师傅的博文 Navex

NAVEX->Precise and Scalable Exploit Generation for Dynamic Web Applications
出处:27th USENIX Security Symposium
作者:Abeer Alhuzali, Rigel Gjomemo, Birhanu Eshete, and V.N.
单位:Venkatakrishnan University of Illinois at Chicago
资料:Paper | Github
作者在本文中提出了一种以静态分析作为指导,结合动态分析自动验证漏洞并构造可用exploit的工具NAVEX。
研究问题:
  1. 解决以往自动化审计的误报以及必须结合人工参与构造Exp的问题;
  2. 静态分析虽然覆盖率高,但是对于具有动态特性的语言其建模困难。解决方案:
  3. 静态分析阶段:使用符号执行创建Web应用程序的各个模块的行为模型。标记出包含潜在漏洞点的模块;
  4. 动态分析阶段:使用Web爬虫和concolic执行器去发现可能导致攻击者进入易受攻击模块的可能的HTTP导航路径,之后使用约束求解器生成一组对漏洞进行利用的HTTP输入序列。
    方案优点:.
  5. 动态分析与静态分析相结合提升了性能,可以应用于大型应用程序;
  6. 是一种多类型漏洞的Exp生成框架。
    NAVEX分析了320万行PHP代码,自动构建并利用204个漏洞,其中有195个与SQLI和XSS相关,而9个与逻辑漏洞相关。此外NAVEX是第一个可以自动发现并利用EAR漏洞的方案。

Joern 静态分析核心模块

JoernShiftLeft公司开发的用于C/C++代码健壮性分析的平台. 其核心思想: 将代码分析问题转化为用Gremlin去遍历存储在Neo4j中的CPG(代码属性图). 其商业产品 Ocular 支持多种语言, 也侧面证明 CPG 作为一种 IR, 是可以解决大部分语言的审计问题.

PS. 静态分析这部分其实可以使用Codeql代替.

CPG 代码属性图

CPG (代码属性图) 的论文可以参考

Modeling and Discovering Vulnerabilities with Code Property Graphs

这里用几张图简要描述一下

原始代码

562bdb86256b6ea5ced714b49d478941.png

代码对应的AST(抽象语法树)

d3247f04d851a55915b0f730d1b7ba8a.png

代码对应的CFG(控制流程图)

10a1b3e0a4e4643a43705af9efab73bf.png

代码对应的PDG(程序依赖图)

2be399d2177575714d30be49fa7881ed.png

](https://blog.riskivy.com/wp-content/uploads/2020/05/4afab12ab74238d1b09a90517beabf9e.png)

代码对应的CPG(代码属性图)

2be399d2177575714d30be49fa7881ed.png

其实以上的信息都可以从AST中获取, 只是后续的操作提高了单位节点的信息密集度, 对分析过程更友好

TinkerPop 2.x Gremlin 图查询语言

由于Navex作者是2012年开始研究这个方向, 所以大部分依赖都是远古版本, 我尽可能的修复了一些, 其中TinkerPop 2.x Gremlin由于官方已经更新 TinkerPop 3.x, 2.x 已经不再维护了, 全网只有一个github上面的历史文档

spmallette/GremlinDocs: Gremlin Documentation and Samples

或者阅读TinkerPop 2.x Gremlin的实现源码

tinkerpop/gremlin: A Graph Traversal Language (no longer active – see Apache TinkerPop).

其实更新为最新版的TP3(文档, 性能和语法都更好), 我也尝试过, 但是整个框架的Gremlin step需要重写, 不利于前期探索, TP2目前还够用, 所以如果后续有需要, 可以考虑整体重构.

目前的python-joern的实现方式是通过HTTP请求发送Gremlin查询语言(Groovy实现)Neo4jGremlin插件

为什么不用Neo4j自带的Cypher, 因为Gremlin支持Groovy语法, 有更强的操作性, 也兼容其他图数据库

Tinkerpop 2.x Gremlin 基础知识

首先得了解Groovy的相关语法

精通 Groovy

TinkerPop 2.x Gremlin 文档查看这个

tinkerpop/gremlin: A Graph Traversal Language (no longer active – see Apache TinkerPop).

下面是我添加了一些注释, 方便理解

it

it 是groovy闭包中的默认参数

list.each {println it
}//等于list.each { obj ->println obj 
}

id

Gets the unique identifier of the element.

每个节点/边都有唯一的id

gremlin> v = g.V("name", "marko").next()
==>v[1]
gremlin> v.id
==>1
gremlin> g.v(1).id
==>1

V

The vertex iterator for the graph. Utilize this to iterate through all the vertices in the graph. Use with care on large graphs unless used in combination with a key index lookup.

TP2

g.V() 代表所有节点

g.v(1) 注意这里是小写的v, 可以用node_id取值

g.V("name", "marko") 返回 v.name=="marko" 的节点

gremlin> g.V
==>v[3]
==>v[2]
==>v[1]
==>v[6]
==>v[5]
==>v[4]
gremlin> g.V("name", "marko")
==>v[1]
gremlin> g.V("name", "marko").name
==>marko

E

The edge iterator for the graph. Utilize this to iterate through all the edges in the graph. Use with care on large graphs.

返回节点的所有边

gremlin> g.E
==>e[10][4-created->5]
==>e[7][1-knows->2]
==>e[9][1-created->3]
==>e[8][1-knows->4]
==>e[11][4-created->3]
==>e[12][6-created->3]
gremlin> g.E.weight
==>1.0
==>0.5
==>0.4
==>1.0
==>0.4
==>0.2

in

Gets the adjacent vertices to the vertex.

返回当前node的父节点

参数的调用可以不写 ()

  1. 没有参数的调用可以不写 ()
  2. 这个技巧在后面存储路径信息的时候会用到

g.v(4).inE.outV == g.v(4).in

g.v(4).outE.inV == g.v(4).out

gremlin> v = g.v(4)
==>v[4]
gremlin> v.inE.outV
==>v[1]
gremlin> v.in
==>v[1]
gremlin> v = g.v(3)
==>v[3]
gremlin> v.in("created")
==>v[1]
==>v[4]
==>v[6]
gremlin> v.in(2,'created')
==>v[1]
==>v[4]
gremlin> v.inE("created").outV
==>v[1]
==>v[4]
==>v[6]
gremlin> v.inE(2,'created').outV[0]
==>v[1]

out

Gets the out adjacent vertices to the vertex.

返回当前node的子节点

gremlin> v = g.v(1)
==>v[1]
gremlin> v.outE.inV
==>v[2]
==>v[4]
==>v[3]
gremlin> v.out
==>v[2]
==>v[4]
==>v[3]
gremlin> v.outE('knows').inV
==>v[2]
==>v[4]
gremlin> v.out('knows')
==>v[2]
==>v[4]
gremlin> v.out(1,'knows')
==>v[2]

both

Get both adjacent vertices of the vertex, the in and the out.

both 操作表示node 的相邻节点, 也就有有edge 存在, 且忽略 edge 的方向

gremlin> v = g.v(4)
==>v[4]
gremlin> v.both
==>v[1]
==>v[5]
==>v[3]
gremlin> v.both('knows')
==>v[1]
gremlin> v.both('knows', 'created')
==>v[1]
==>v[5]
==>v[3]
gremlin> v.both(1, 'knows', 'created')
==>v[1]

Transform

Transform steps take an object and emit a transformation of it.

Transform 操作可以返回其后面闭包里面的值

Identity turns an arbitrary object into a “pipeline”.

gremlin> x = [1,2,3]
==>1
==>2
==>3
gremlin> x._().transform{it+1}
==>2
==>3
==>4
gremlin> x = g.E.has('weight', T.gt, 0.5f).toList()
==>e[10][4-created->5]
==>e[8][1-knows->4]
gremlin> x.inV
==>[StartPipe, InPipe]
==>[StartPipe, InPipe]
gremlin> x._().inV
==>v[5]
==>v[4]

has

使用has可以做一些简单的属性判断

Allows an element if it has a particular property. Utilizes several options for comparisons through T:

  • T.gt – greater than
  • T.gte – greater than or equal to
  • T.eq – equal to
  • T.neq – not equal to
  • T.lte – less than or equal to
  • T.lt – less than
  • http://T.in – contained in a list
  • T.notin – not contained in a list

It is worth noting that the syntax of has is similar to g.V("name", "marko"), which has the difference of being a key index lookup and as such will perform faster. In contrast, this line, g.V.has("name", "marko"), will iterate over all vertices checking the name property of each vertex for a match and will be significantly slower than the key index approach. All that said, the behavior of has is dependent upon the underlying implementation and the above description is representative of most Blueprints implementations. For instance, Titan will actually try to use indices where it sees the opportunity to do so. It is therefore important to understand the functionality of the underlying database when writing traversals.

gremlin> g.V.has("name", "marko").name
==>marko
gremlin> g.v(1).outE.has("weight", T.gte, 0.5f).weight
==>0.5
==>1.0
gremlin> g.V.has('age').name
==>vadas
==>marko
==>peter
==>josh
gremlin> g.V.has('age',T.in,[29,32])
==>v[1]
==>v[4]
gremlin> g.V.has('age').has('age',T.notin, [27,35]).name
==>marko
==>josh

[i]

A index filter that emits the particular indexed object.

通过下标可以进行取值, 跟Python的数组相似

gremlin> g.V[0].name
==>lop

[i..j]

A range filter that emits the objects within a range.

下标也可以取范围. 前闭后开, [0,2)

gremlin> g.V[0..2].name
==>lop
==>vadas
==>marko
gremlin> g.V[0..<2].name
==>lop
==>vadas

filter

Decide whether to allow an object to pass. Return true from the closure to allow an object to pass.

filter操作就是通过一个闭包函数来过滤输入

//filter有时会失效,最好用has()
g.v(1).outE.has('label','created')
//g.v(1).outE.filter{it.label=='created'}
groovy
in filter{}it.xxx() 可能返回 pipe 对象
可以使用it.xxx().next()
来获取第一个节点
gremlin> g.V.filter{it.age > 29}.name
==>peter

dedup

Emit only incoming objects that have not been seen before with an optional closure being the object to check on.

用于去除重复元素

gremlin> g.v(1).out.in
==>v[1]
==>v[1]
==>v[1]
==>v[4]
==>v[6]
gremlin> g.v(1).out.in.dedup()
==>v[1]
==>v[4]
==>v[6]

as

Emits input, but names the previous step.

给一个操作设置一个别名, 配合select, loop

g.v(1).as('sloop').outE.inV.loop('sloop'){it.loops < 2}

循环体为 .outE.inV. 等价

g.v(1).outE.inV.loop(2){it.loops < 2}

gremlin> g.V.as('x').outE('knows').inV.has('age', T.gt, 30).back('x').age
==>29

select

Select the named steps to emit after select with post-processing closures.

select 一般配合as一起使用

gremlin> g.v(1).as('x').out('knows').as('y').select
==>[x:v[1], y:v[2]]
==>[x:v[1], y:v[4]]
gremlin> g.v(1).as('x').out('knows').as('y').select(["y"])
==>[y:v[2]]
==>[y:v[4]]
gremlin> g.v(1).as('x').out('knows').as('y').select(["y"]){it.name}
==>[y:vadas]
==>[y:josh]
gremlin>  g.v(1).as('x').out('knows').as('y').select{it.id}{it.name}
==>[x:1, y:vadas]
==>[x:1, y:josh]

sideEffect

Emits input, but calls a side effect closure on each input.

官方示例中的是交互console, 可以延伸到下一条语句

gremlin> youngest = Integer.MAX_VALUE
==>2147483647
gremlin> g.V.has('age').sideEffect{youngest=youngest>it.age?it.age:youngest}
==>v[2]
==>v[1]
==>v[6]
==>v[4]
gremlin> youngest
==>27

sideEffect可以在运行过程中执行指定操作, 但是不会影响遍历过程, 主要用于收集信息, 尽量不要用于改变节点信息

python-joern中, sideEffect的作用域只在当前遍历过程/语句, 这里比较坑人, 大家注意

g.V.has('age').sideEffect{youngest=youngest>it.age?it.age:youngest}.transform{youngest}

ifThenElse

Allows for if-then-else conditional logic.

gremlin> g.v(1).out.ifThenElse{it.name=='josh'}{it.age}{it.name}
==>vadas
==>32
==>lop

判断条件选择分支执行, 这边倾向于单独使用groovyif语句来处理, 逻辑更清晰

loop

Loop over a particular set of steps in the pipeline. The first argument is either the number of steps back in the pipeline to go or a named step. The second argument is a while closure evaluating the current object. The it component of the loop step closure has three properties that are accessible. These properties can be used to reason about when to break out of the loop.

  • it.object: the current object of the traverser.
  • it.path: the current path of the traverser.
  • it.loops: the number of times the traverser has looped through the loop section.

The final argument is known as the “emit” closure. This boolean-based closure will determine wether the current object in the loop structure is emitted or not. As such, it is possible to emit intermediate objects, not simply those at the end of the loop.

gremlin> g.v(1).out.out
==>v[5]
==>v[3]
gremlin> g.v(1).out.loop(1){it.loops<3}
==>v[5]
==>v[3]
gremlin> g.v(1).out.loop(1){it.loops<3}{it.object.name=='josh'} 
==>v[4]

loop应该这里最关键的操作, 可以参考

Loop Pattern · tinkerpop/gremlin Wiki

大部分的查询操作都需要loop进行配合

g.v(1).out.loop(1){it.loops<3}{it.object.name=='josh'}

大概等价于

arr = []
for (i=1; i<3; i++){if(it.object.name=='josh'){arr.add(it.object)}
}
return arr

结合后面的enablePath, 可以在遍历的过程中获取当前所在的完整路径信息

g.v(1).out.loop(1){it.loops<3}{it.object.name=='josh' && it.path.contains(g.v(4))}.enablePath

大概等价于

arr = []
for (i=1; i<3; i++){if(it.object.name=='josh' && it.path.contains(g.v(4))){arr.add(it.object)}
}
return arr

Pipe.enablePath

If the path information is required internal to a closure, Gremlin doesn’t know that as it can not interpret what is in a closure. As such, be sure to use GremlinPipeline.enablePath() if path information will be required by the expression.

主要是保存路径信息

gremlin> g.v(1).out.loop(1){it.loops < 3}{it.path.contains(g.v(4))}
Cannot invoke method contains() on null object
Display stack trace? [yN] 
gremlin> g.v(1).out.loop(1){it.loops < 3}{it.path.contains(g.v(4))}.enablePath()
==>v[5]
==>v[

Pipe.next

Gets the next object in the pipe or the next n objects. This is an important notion to follow when considering the behavior of the Gremlin Console. The Gremlin Console iterates through the pipeline automatically and outputs the results. Outside of the Gremlin Console or if more than one statement is present on a single line of the Gremlin Console, iterating the pipe must be done manually. Read more about this topic in the Gremlin Wiki Troubleshooting Page.

There are some important things to note in the example below. Had the the first line of Gremlin been executed separately, as opposed to being placed on the same line separated by a semi-colon, the name of the vertex would have changed because the Gremlin Console would have automatically iterated the pipe and processed the side-effect.

gremlin> g.v(1).sideEffect{it.name="same"};g.v(1).name
==>marko
gremlin> g.v(1).sideEffect{it.name="same"}.next();g.v(1).name
==>same
gremlin> g.V.sideEffect{it.name="same-again"}.next(3);g.V.name
==>same-again
==>same-again
==>same-again
==>peter
==>ripple
==>josh

next 操作可以从pipe中取出对象 // pipe返回的一般都是生成器对象

path

Gets the path through the pipeline up to this point, where closures are post-processing for each object in the path. If the path step is provided closures then, in a round robin fashion, the closures are evaluated over each object of the path and that post-processed path is returned.

gremlin> g.v(1).out.path
==>[v[1], v[2]]
==>[v[1], v[4]]
==>[v[1], v[3]]
gremlin> g.v(1).out.path{it.id}
==>[1, 2]
==>[1, 4]
==>[1, 3]
gremlin> g.v(1).out.path{it.id}{it.name}
==>[1, vadas]
==>[1, josh]
==>[1, lop]
gremlin> g.v(1).outE.inV.name.path
==>[v[1], e[7][1-knows->2], v[2], vadas]
==>[v[1], e[8][1-knows->4], v[4], josh]

path操作返回遍历的所有路径

simplePath

Emit the object only if the current path has no repeated elements.

gremlin> g.v(1).out.in
==>v[1]
==>v[1]
==>v[1]
==>v[4]
==>v[6]
gremlin> g.v(1).out.in.simplePath
==>v[4]
==>v[6]

simplePath返回没有环路的path

toList

g.v(1).out //返回生成器
g.v(1).out.toList() //返回一个列表, 已经把数据都读出来了, 可以随便操作

intersect

返回交集

[1,2,3].intersect([1]) 
=> [1][].intersect([1]) 
=> []

Navex 排坑

被删除的查询语句

当你信心满满的解决了前面的各种古老依赖, 奇怪版本号问题时, 在最关键的查询语句是丢失的

如果你真的尝试运行了, 大概会这样

#python static-main.py the query is 
xss_funcs = ["print", "echo"]
sql_query_funcs = ["mysql_query", "mysqli_query", "pg_query", "sqlite_query"]
os_command_funcs = ["backticks", "exec" , "expect_popen","passthru","pcntl_exec","popen","proc_open","shell_exec","system", "mail"     ]m =[];  queryMapList =[]; g.V().filter{sql_query_funcs.contains(it.code)  && isCallExpression(it.nameToCall().next()) }.callexpressions().sideEffect{m = start(it, [], 0, 'sql', false, queryMapList)}.sideEffect{ warnmessage = warning(it.toFileAbs().next().name, it.lineno, it.id, 'sql', '1')}.sideEffect{ reportmessage = report(it.toFileAbs().next().name, it.lineno, it.id)}.ifThenElse{m.isEmpty()}{it.transform{reportmessage}}{it.transform{findSinkLocation(m, warnmessage, 'sql', queryMapList, it)}}
Caught exception: <class 'py2neo.error.BadInputException'> groovy.lang.MissingMethodException: No signature of method: com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.start() is applicable for argument types: (com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Vertex, java.util.ArrayList, java.lang.Integer, java.lang.String, java.lang.Boolean, java.util.ArrayList) values: [v[721], [], 0, sql, false, []]
Possible solutions: wait(), any(), every()
None

很显然是作者删除了关键函数

m = start(it, [], 0, 'sql', false, queryMapList) # 筛选sql注入节点

findSinkLocation(m, warnmessage, 'sql', queryMapList, it) # 查找Sink

所以你不可能直接复现论文里的静态分析结果, 世界上除了作者应该没人知道写的是啥了, issue中也有人反馈这样的问题

python-joern/Analysis.py at e5f651511143938511ae572b7986bfa92c6c4936 · aalhuz/python-joern

b2f5e135bf14f531bfe971d73f858557.png

大部分想尝试的人, 面对这样未知的领域, 未知的语言, 未知的代码, 都会就此止步, 可惜了, 我不信邪, 哪怕重新写一个.

之后的时间, 去寻找“Tinkerpop Gremlin的教程, 然后学完百度的HugeGraph教程才发现市面上的文档都是针对Tinkerpop 3.x, 甚至又学习了一个宝藏博主的Tinkerpop 3.x`教程
PRACTICAL GREMLIN: An Apache TinkerPop Tutorial
想着触类旁通, 修复Tinkerpop 2.x 的 Navex, 在一个完全陌生的领域探索必然是缓慢而痛苦的, 又过了很久, 找到 github上面的一份古老文档
spmallette/GremlinDocs: Gremlin Documentation and Samples
这是一份 2012-2015 年的Tinkerpop 2.x文档, 然后勉强把Tinkerpop 2.x文档扣了一遍, 中间穿插学习了编译原理, 离散数学, 南大的静态分析课程, 也算是知道了什么是静态分析, 大概的原理和目的也算是清楚了些.
在浏览器相关收藏快100个了的时候, 前后知识点终于打通了, 被迫完成了作者删除的代码, 回过头来看, 也不是特别难, 硬着头皮写Gremlin遍历, 边查边写就是了.

CPG – Vertex, Edge , Property

CPG节点, 属性信息都记录在下面这个文件中

joern/phpjoernsteps/_constants.groovy

// AST node property keysObject.metaClass.NODE_INDEX = 'id'  // 每个node都有自己的id
Object.metaClass.NODE_TYPE = 'type' // 节点的类型, 后面`AST node types`有具体描述
Object.metaClass.NODE_FLAGS = 'flags'   // 参考`AST node flags`, 赋值, 二元操作,判断, 文件包含, 目录信息
Object.metaClass.NODE_LINENO = 'lineno' // 当前节点所处源文件的行数
Object.metaClass.NODE_CODE = 'code'     // 引用的函数或者变量的名称
Object.metaClass.NODE_FUNCID = 'funcid' // 所处文件的文件id
Object.metaClass.NODE_ENDLINENO = 'endlineno'   // 所处文件的总行数
Object.metaClass.NODE_NAME = 'name'             // 函数声明的函数名称, 文件的文件名
Object.metaClass.NODE_DOCCOMMENT = 'doccomment'     // 注释// AST node types
//g.V().has('type', TYPE_STMT_LIST)
Object.metaClass.TYPE_STMT_LIST = 'AST_STMT_LIST' // ...; ...; ...;
Object.metaClass.TYPE_CALL = 'AST_CALL' // foo()
Object.metaClass.TYPE_STATIC_CALL = 'AST_STATIC_CALL' // bla::foo()
Object.metaClass.TYPE_METHOD_CALL = 'AST_METHOD_CALL' // $bla->foo()
Object.metaClass.TYPE_PROP = 'AST_PROP' // e.g., $bla->foo
Object.metaClass.TYPE_FUNC_DECL = 'AST_FUNC_DECL' // function foo() {}
Object.metaClass.TYPE_METHOD = 'AST_METHOD' // class bla { ... function foo() {} ... }
Object.metaClass.TYPE_ARG_LIST = 'AST_ARG_LIST' // foo( $a1, $a2, $a3)
Object.metaClass.TYPE_PARAM_LIST = 'AST_PARAM_LIST' // function foo( $p1, $p2, $p3) {}
Object.metaClass.TYPE_PARAM = 'AST_PARAM' // $p1
Object.metaClass.TYPE_ASSIGN = 'AST_ASSIGN' // $buzz = true
Object.metaClass.TYPE_ASSIGN_REF = 'AST_ASSIGN_REF' // $b = &$a
Object.metaClass.TYPE_ASSIGN_OP = 'AST_ASSIGN_OP' // $x += 3
Object.metaClass.TYPE_NAME = 'AST_NAME' // names (e.g., name of a called function in call expressions)
Object.metaClass.TYPE_VAR = 'AST_VAR' // $v
Object.metaClass.TYPE_BINARY_OP = 'AST_BINARY_OP' // e.g., "foo"."bar" or 3+4
Object.metaClass.TYPE_ENCAPS_LIST = 'AST_ENCAPS_LIST' // e.g., "blah{$var1}buzz $var2 beep"
Object.metaClass.TYPE_INCLUDE_OR_EVAL = 'AST_INCLUDE_OR_EVAL' // eval, include, require
//Abeer
Object.metaClass.TYPE_CALLEE = 'Callee'
Object.metaClass.TYPE_FUNCTION = 'Function'
Object.metaClass.TYPE_ECHO = 'AST_ECHO' // echo
Object.metaClass.TYPE_PRINT = 'AST_PRINT' // PRINT//ABEER
Object.metaClass.TYPE_IF_ELEM = 'AST_IF_ELEM' // HOLDES THE COND INSIDE IF 
Object.metaClass.TYPE_DIM = 'AST_DIM' // _POST[x]
Object.metaClass.TYPE_ISSET = 'AST_ISSET' // is_set()
// TODO and many more...// AST node flags
// of AST_ASSIGN.*
Object.metaClass.FLAG_ASSIGN_CONCAT = 'ASSIGN_CONCAT' // $v .= "foo"
// of AST_BINARY_OP
Object.metaClass.FLAG_BINARY_CONCAT = 'BINARY_CONCAT' // "foo"."bar"
//Abeer
Object.metaClass.FLAG_BINARY_EQUAL = 'BINARY_IS_EQUAL' // x==y
Object.metaClass.FLAG_BINARY_NOT_EQUAL = 'BINARY_IS_NOT_EQUAL'  // x != y
Object.metaClass.FLAG_BINARY_IS_IDENTICAL = 'BINARY_IS_IDENTICAL'   // 1 === 1
Object.metaClass.FLAG_BINARY_IS_NOT_IDENTICAL = 'BINARY_IS_NOT_IDENTICAL' // 1 !== 1
// of AST_INCLUDE_OR_EVAL
Object.metaClass.FLAG_EXEC_EVAL = 'EXEC_EVAL' // eval("...")
Object.metaClass.FLAG_EXEC_INCLUDE = 'EXEC_INCLUDE' // include "..."
Object.metaClass.FLAG_EXEC_INCLUDE_ONCE = 'EXEC_INCLUDE_ONCE' // include_once "..."
Object.metaClass.FLAG_EXEC_REQUIRE = 'EXEC_REQUIRE' // require "..."
Object.metaClass.FLAG_EXEC_REQUIRE_ONCE = 'EXEC_REQUIRE_ONCE' // require_once "..."// TODO and many more...// Other (non-AST) node types
// 目录结构信息
Object.metaClass.TYPE_DIRECTORY = 'Directory'
Object.metaClass.TYPE_FILE = 'File'Object.metaClass.TYPE_STRING = 'string'// Edge typesObject.metaClass.DIRECTORY_EDGE = 'DIRECTORY_OF'
Object.metaClass.FILE_EDGE = 'FILE_OF'
Object.metaClass.AST_EDGE = 'PARENT_OF'// 不清楚, dvwa里面没有这种边
Object.metaClass.TYPE_IDENTIFIER_DECL_STMT = 'IdentifierDeclStatement'
Object.metaClass.TYPE_PARAMETER = 'Parameter'Object.metaClass.TYPE_FILE = 'File'// Edge typesObject.metaClass.CALLS_EDGE = 'CALLS'  // 类中的函数定义
Object.metaClass.CFG_EDGE = 'FLOWS_TO' // 用来描述 ControlFlowObject.metaClass.USES_EDGE = 'USE'
Object.metaClass.DEFINES_EDGE = 'DEF'
Object.metaClass.DATA_FLOW_EDGE = 'REACHES'  // 用来描述 DataFlowObject.metaClass.FUNCTION_TO_AST_EDGE = 'IS_FUNCTION_OF_AST'
Object.metaClass.FILE_TO_FUNCTION_EDGE = 'IS_FILE_OF'// Edge keysObject.metaClass.DATA_FLOW_SYMBOL = 'var' // 如果这是一条`REACHES`的边, 就会有`var`这个key, 其值代表上一个节点流出到下一个节点的变量名//Abeer
// phpjoern 自带的过滤函数检测, 这里我们不用
Object.metaClass.DATA_FLOW_TAINT_SRC = 'taint_src'
Object.metaClass.DATA_FLOW_TAINT_DST = 'taint_dst'

作者:斗象能力中心 TCC – 小胖虎

由于篇幅有限,有关漏洞查询代码补全分析、完整代码、安装与使用、查询结果分析、总结与参考内容将在 《复活Navex-使用图查询进行代码分析(下)》篇展示,记得持续关注哦~


如果想要获得「更多最前沿的安全技术研究与内容」欢迎关注‘斗象智能安全能力中心’

斗象能力中心 - 斗象智能安全​blog.riskivy.com

TCC Team长期招聘,包含各细分领域安全研究员[Web/网络攻防/逆向]、机器学习、数据分析等职位。感兴趣不妨发简历联系我们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/505151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

公文字体字号标准2020_一文了解公文格式规范,图文并茂(建议收藏备用)

本方法根据《党政机关公文格式国家标准》(GB/T9704-2012)制定。具体内容如下&#xff1a;一、办公软件要求适用于微软OFFICE—WORD文字处理软件。二、页面设置1.选择“文件”——“页面设置”选择“页边距”附签&#xff0c;上&#xff1a;3.7厘米&#xff0c;下&#xff1a;3.…

360浏览器卸载_无法卸载?Win10 强推新 Edge 浏览器,来教你如何干掉它

8月17日消息&#xff0c;相信不少更新了 Windows 10 v2004 版本的用户都已经发现&#xff0c;系统默认浏览器已经自动更新为基于 Chromium 打造的全新 Edge 浏览器&#xff0c;虽然该浏览器已经一跃成为全球第二大桌面浏览器&#xff0c;但却仍然有不少用户反馈不好用。撰文 | …

磁卡门锁怎么配卡_样式多的铜工艺品怎么设计请查看_江西南昌皇巢|铜门||别墅铜门|...

江西南昌皇巢|铜门||别墅铜门|专注FNbnWz样式多的铜工艺品怎么设计请查看&#xff0c;咨询更多详情&#xff01;KLC欧式门锁室内门锁卧室房门锁黄古铜门锁实木门锁具执手锁&#xffe5;&#xff0c;月销笔进店相关推荐词军升欧式门锁黄古铜田园室内门锁执手机械门锁卧室锁具防盗…

php怎么分割页面,用html如何把页面分割成多个文件,由多个文件拼接而成?

用html如何把页面分割成多个文件&#xff0c;由多个文件拼接而成&#xff1f;更新时间&#xff1a;2014-11-10 作者&#xff1a;久久经验网 来源&#xff1a;久久经验网 所属分类&#xff1a;Web前端摘要&#xff1a;静态html分割页面&#xff0c;达到类似php等动态页面的in…

13寸笔记本电脑尺寸_如何判断行李箱的尺寸?标准行李箱尺寸对照表(13~32寸)

行李箱已经成为家庭必备的一件物品&#xff0c;很多时候都会用到行李箱&#xff0c;最晚就是大学时期&#xff0c;肯定会准备一个行李箱&#xff0c;有些人第一次买不知道如何判断行李箱的尺寸&#xff0c;今天小编就教大家怎么自己确定行李箱的尺寸。如何判断行李箱的尺寸?行…

华为手机怎么隐藏按键图标_mac桌面图标怎么快速隐藏?

我们会应为方便而在电脑桌面直接放一些文件&#xff0c;对于处女座而言无论是桌面还是电脑桌面都不希望非常凌乱&#xff0c;那么我们如何隐藏我们的mac电脑桌面图标文件呢&#xff1f;如何才能使电脑看起来干净整洁呢&#xff1f;一、如何在 Finder 中隐藏桌面图标&#xff1f…

bat脚本中如何多次键盘输入并判断_电脑上如何多开微信?PC端多开微信的方法

相信很多人都有多个微信&#xff0c;尤其是那些工作和生活分的比较开的人士&#xff0c;大家都知道一个电脑和可以登录多个QQ的&#xff0c;但是对于微信却不是这样。当你已经登录一个微信时&#xff0c;再打开微信时会自动弹出当前已经登录的微信窗口。本文将教你如何在PC电脑…

win7蓝牙怎么连接_win7添加打印机提示windows无法连接怎么办?正确解决方法分享...

如果有多台电脑&#xff0c;那么一般会把打印机设置成共享&#xff0c;然后其他电脑通过添加网络打印机的方式来使用。有win7纯净版系统用户遇到一个问题&#xff0c;在自己电脑上要添加另一台电脑共享的打印机时&#xff0c;出现“Windows无法连接到打印机。键入的打印机名不正…

一般项目中哪里体现了数据结构_优秀程序员都应该学习的数据结构与算法项目(GitHub 开源清单)...

前言算法为王。想学好前端&#xff0c;先练好内功&#xff0c;内功不行&#xff0c;就算招式练的再花哨&#xff0c;终究成不了高手&#xff1b;只有内功深厚者&#xff0c;前端之路才会走得更远。强烈推荐 GitHub 上值得前端学习的数据结构与算法项目&#xff0c;包含 gif 图的…

matlab 白色像素点,MATLAB 簡單的計算白色輪廓中像素點的個數

近來&#xff0c;有朋友問到&#xff0c;如何計算白色輪廓中的像素點的個數。我在這里就舉一個超級簡單的例子&#xff0c;就是假設一副二值圖片&#xff0c;其背景是黑色的&#xff0c;而你的邊緣是白色的&#xff0c;而且你的白色邊緣中不包含黑色的點&#xff0c;就如附件中…

pb网络编程_可在家中建立三个区域聆听空间,Integra DRX3.3 9.2声道网络影音接收机...

专为满足您的娱乐梦想而研发DRX-3.3可让您在家中建立最多三个区域的聆听空间&#xff0c;升级的四核SoC支持802.11ac(MIMO)高速Wi-Fi规格让多房间无线音频串流更顺畅&#xff0c;同时还可享受最高5.2.4声道沉浸式3D音效的电影与游戏。定制安装特性&#xff1a;• 用于外部控制与…

加载中图片 转圈_对话洛可可平面设计师:平面设计中的效率瓶颈

随着内容创作者时代的到来&#xff0c;消费级个人数据存储容量的需求正在不断变大&#xff0c;同时对消费级存储产品的性能需求也在不断变大。以主流的设计师、后期剪辑等群体为例来说&#xff0c;往往对高性能PC有着极其大的需求&#xff0c;因为创作灵感往往转瞬即逝&#xf…

m 文件 dll matlab 中调用_如何在matlab中调用python程序

现在python很火&#xff0c;很多代码都是python写的&#xff0c;如果你和我一样&#xff0c;习惯了使用matlab&#xff0c;还想在matlab中调用Python的代码&#xff0c;应该怎么办呢&#xff1f;其中一条思路&#xff1a;首先在matlab中调用系统脚本命令&#xff0c;然后再通过…

spring整合atomikos实现分布式事务的方法示例_分布式事务中的XA和JTA

在介绍这两个概念之前&#xff0c;我们先看看是什么是X/Open DTP模型。X/Open X/Open&#xff0c;即现在的open group&#xff0c;是一个独立的组织&#xff0c;主要负责制定各种行业技术标准。X/Open组织主要由各大知名公司或者厂商进行支持&#xff0c;这些组织不光遵循X/Ope…

hadoop 传感器数据_读取模式错误,计算引擎操作复杂……面对Hadoop这些问题该如何应对?...

作者 | Monte Zweben译者 | 天道酬勤&#xff0c;责编 | Carol封图 | CSDN 付费下载自视觉中国Apache Hadoop于2006年出现在IT领域&#xff0c;它使用商品硬件&#xff0c;为组织提供前所未有的数据量存储能力。不仅解决了数据集的大小问题&#xff0c;还解决了数据类型问题&am…

xpath获取标签的属性值_论xpath与css定位方式

例1&#xff1a;<input id"kw" name"wd" class"s_ipt" value"" maxlength"255" autocomplete"off"> 分别使用xpath、css的标签组合定位xpath标签属性组合定位css标签属性组合定位css中#表示id,如#kw&#x…

c语言sort_C语言十大排序算法,让老师对你刮目相看的技巧

排序算法作为数据结构的重要部分&#xff0c;系统地学习一下是很有必要的。十种常见排序算法可以分为两大类&#xff1a;比较类排序&#xff1a;通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此也称为非线性时间比较类排序。非比…

vim复制粘贴_打造一款高逼格的Vim神器

Vim 是一个上古神器&#xff0c;本篇文章主要持续总结使用 Vim 的过程中不得不了解的一些指令和注意事项&#xff0c;以及持续分享一个开发者不得不安装的一些插件&#xff0c;而关于 Vim 的简介&#xff0c;主题的选择&#xff0c;以及为何使用 vim-plug 来管理插件等内容&…

python列表嵌套字典取值_我的 python 学习历程-Day05 字典/字典的嵌套

一、字典的初识为什么要有字典字典与列表同属容器型数据类型&#xff0c;同样可以存储大量的数据&#xff0c;但是&#xff0c;列表的数据关联性不强&#xff0c;并且查询速度比较慢&#xff0c;只能按照顺序存储。什么是字典先说一下什么叫可变与不可变的数据类型分类不可变&a…

s8050三极管经典电路_曝光一个产品级的红外发射电路

作者&#xff1a;瑞生&#xff0c;来源&#xff1a;科技老顽童微信公众号&#xff1a;芯片之家(ID&#xff1a;chiphome-dy今天给大家一个产品级的红外发射电路。为什么说是产品级的&#xff1f;因为这个电路我已经在各类产品上见过多次&#xff01;很多小伙伴学电子有一个误区…