Tracer 源码阅读(4)
为了记录自己读代码的过程,开设 Tracer 源码阅读系列博客。该系列博客以 ACM CCS 22’ Tracer 的源代码为分析对象,旨在理解论文思路和复现论文结果,为后续在未初始化变量上的改进工作提供思路。
上文记录了对 IntOverflow 漏洞进行实例化的过程,在陆续查看了 CommandInjection 和 IntUnderflow 上实例化的过程后,本文尝试总结出为 Tracer 实现一个新的 checker 的方法。
前置条件
找到当前漏洞所涉及的 source-sink 函数
APIMisuseChecker.ml
在 report 函数中添加对应的报告内容,该内容会显示在最后的 Trace 文件中:
1
2
3
4
| Dom.Cond.Exec c when Dom.Cond.is_user_input cond ->
let ltr_set = TraceSet.make_err_trace c.traces |> Option.some in
report_src_sink_pair cond ~ltr_set "Exec" ;
Dom.CondSet.add (Dom.Cond.reported cond) condset
APIMisuseDomain.ml
在 Cond 模块下添加对应的漏洞类型,Cond 模块会被作为 Summary 传播
1
2
3
4
5
6
7
8
module Cond = struct
type t =
...
| Exec of
{ user_input_elem: UserInput.Elem.t
; loc: Location.t
; traces: (TraceSet.t[@compare.ignore])
; reported: bool }
随后,分别为该模块的成员函数添加 Exec 的 match arm:
1
2
3
4
5
6
7
8
9
(* 设置 reported 属性,去除重复的 Cond *)
reported: Cond.t -> Cond.t
is_symbolic: Cond.t -> bool
get_location: Cond.t -> Location.t
is_reported: Cond.t -> bool
is_user_input: Cond.t -> bool
extract_user_input: Cond.t -> UserInput.Elem.t option
subst: Subst.subst -> Mem.t -> t -> t list
pp: F.formatter -> t -> unit
随后,需要对当前漏洞类型,在 Cond 和 CondSet 中设置构造函数,用于在之后生成报告内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Module Cond = struct
...
let make_exec {Val.traces} user_input_elem loc: Val.t -> UserInput.Elem.t -> Location.t -> t =
Exec {user_input_elem; loc; traces; reported= false}
end
module CondSet = struct
...
let make_exec (v : Val.t) loc =
let user_input_list = UserInput.to_list v.user_input in
List.fold user_input_list ~init:bottom ~f:(fun cs user_input_elem ->
let traces =
TraceSet.filter
(fun tr ->
match user_input_elem with
| UserInput.Elem.Source (_, src_loc) ->
Trace.src_may_match src_loc tr
| UserInput.Elem.Symbol _ ->
true)
v.traces
in
add (Cond.make_exec {v with traces} user_input_elem loc) cs)
end
APIMisuseModels.ml
在 dispatch 函数中,添加当前漏洞所涉及到的 source-sink 函数的签名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
let dispatch : Tenv.t -> Procname.t -> unit ProcnameDispatcher.Call.FuncArg.t list -> 'a =
let open ProcnameDispatcher.Call in
let char_typ = Typ.mk (Typ.Tint Typ.IChar) in
let char_ptr = Typ.mk (Typ.Tptr (char_typ, Pk_pointer)) in
make_dispatcher
[ -"std" &:: "map" < any_typ &+...>:: "operator[]" $ capt_exp $+ capt_exp $--> StdMap.at
; -"std" &:: "map" < any_typ &+...>:: "map" $ capt_exp
$+ capt_exp_of_typ (-"std" &:: "map")
$--> StdMap.copy_constructor
; -"std" &:: "map" < any_typ &+...>:: "map" $ capt_exp $+? any_arg $+? any_arg $+? any_arg
$--> StdMap.constructor
; -"std" &:: "basic_string" < any_typ &+...>:: "basic_string" $ capt_exp
$+ capt_exp_of_prim_typ char_ptr $+ any_arg $--> BasicString.constructor
; -"std" &:: "basic_string" < any_typ &+...>:: "basic_string" $ capt_exp
$+ capt_exp_of_typ (-"std" &:: "basic_string")
$--> BasicString.copy_constructor
; -"std" &:: "basic_string" < any_typ &+...>:: "operator=" $ capt_exp $+ capt_exp
$--> BasicString.assign
; -"std" &:: "basic_string" < any_typ &+...>:: "operator+=" $ capt_exp $+? any_arg $+? any_arg
$--> BasicString.plus_equal
; -"std" &:: "basic_string" < any_typ &+ any_typ &+ any_typ >:: "basic_string" &::.*--> empty
; -"std" &:: "basic_string" < any_typ &+...>:: "basic_string" &::.*--> empty
; -"fread" <>$ capt_exp $+...$--> fread
; -"fgets" <>$ capt_exp $+...$--> fread
; -"malloc" <>$ capt_exp $--> malloc
; -"g_malloc" <>$ capt_exp $--> malloc
; -"__new_array" <>$ capt_exp $--> malloc
; -"realloc" <>$ capt_exp $+ capt_exp $+...$--> realloc
; -"calloc" <>$ capt_exp $+ capt_exp $+...$--> calloc
; -"printf" <>$ capt_exp $+...$--> printf
; -"sprintf" <>$ capt_exp $+ capt_exp $++$--> sprintf
; -"snprintf" <>$ capt_exp $+ capt_exp $+ capt_exp $++$--> snprintf
; -"vsprintf" <>$ capt_exp $+ capt_exp $++$--> sprintf
; -"vsnprintf" <>$ capt_exp $+ capt_exp $+ capt_exp $++$--> snprintf
; -"fprintf" <>$ capt_exp $+ capt_exp $--> fprintf
; -"getc" <>$ capt_exp $--> getc
; -"_IO_getc" <>$ capt_exp $--> getc
; -"getenv" <>$ capt_exp $--> getenv
; -"fgetc" <>$ capt_exp $--> getc
; -"strtok" <>$ capt_exp $+...$--> strtok
; -"strdup" <>$ capt_exp $--> strdup
; -"strcpy" <>$ capt_exp $+ capt_exp $+...$--> strcpy
; -"memcpy" <>$ capt_exp $+ capt_exp $+...$--> strcpy
; -"gnutls_x509_crt_get_subject_alt_name"
<>$ capt_exp $+ capt_exp $+ capt_exp $+...$--> gnutls_x509_crt_get_subject_alt_name
; -"readdir" <>$ capt_exp $--> readdir
; -"getopt" <>$ capt_exp $+ capt_exp $+ capt_exp $+...$--> getopt
; -"atoi" <>$ capt_exp $--> atoi
; -"system" <>$ capt_exp $--> system
; -"execl" <>$ capt_exp $+...$--> system
; -"execv" <>$ capt_exp $+...$--> system
; -"execle" <>$ capt_exp $+...$--> system
; -"execve" <>$ capt_exp $+...$--> system
; -"execlp" <>$ capt_exp $+...$--> system
; -"execvp" <>$ capt_exp $+...$--> system
; -"__infer_print__" <>$ capt_exp $--> infer_print ]
为该签名实现对应的函数模型,即 exec / check 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
let system str =
let check {location; bo_mem_opt} mem condset =
let v = Sem.eval str location bo_mem_opt mem in
let v_powloc = v |> Dom.Val.get_powloc in
let user_input_val =
Dom.PowLocWithIdx.fold
(fun loc v -> Dom.Val.join v (Dom.Mem.find_on_demand loc mem))
v_powloc Dom.Val.bottom
|> Dom.Val.append_trace_elem (Trace.make_exec location)
in
Dom.CondSet.union (Dom.CondSet.make_exec user_input_val location) condset
in
{exec= empty_exec_fun; check}
以上述 check 函数为例,其逻辑为找到当前表达式(Exp.t 类型)所包含的污点信息,并添加到 trace 记录中
APIMisuseTrace.ml
添加 Trace.elem 的类型和对应的构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module Trace = struct
type elem =
| SymbolDecl of AbsLoc.Loc.t
| Input of Procname.t * Location.t
| Store of Exp.t * Exp.t * Location.t
| Prune of Exp.t * Location.t
| Call of Procname.t * Location.t
| Malloc of Location.t
| Printf of Location.t
| Sprintf of Location.t
| Exec of Location.t
[@@deriving compare, yojson_of]
let make_exec loc = Exec loc
然后分别在 make_err_trace 和 pp 中添加对应的解析代码
This post is licensed under CC BY 4.0 by the author.