Commit 41b84a41 by Enkelmann Committed by Thomas Barabosch

Cwe476 (#11)

* improved CWE476-check with dataflow analysis
parent 44cb572a
0.2-dev (2019-XX-XX) 0.2-dev (2019-XX-XX)
===== =====
- Refactoring: Unification of cwe_checker function interface - Refactoring: Unification of cwe_checker function interface
- Refactoring: Created utils module for JSON functionality - Refactoring: Created utils module for JSON functionality
- Added check for CWE 248: Uncaught Exception (PR #5) - Added check for CWE 248: Uncaught Exception (PR #5)
- Added automated test suite (run with make test) (PR #7) - Added automated test suite (run with make test) (PR #7)
- Improved cross compiling for acceptance test cases by using dockcross (PR #8) - Improved cross compiling for acceptance test cases by using dockcross (PR #8)
- Added BAP recipe for standard cwe_checker run (PR #9) - Added BAP recipe for standard cwe_checker run (PR #9)
- Improved check for CWE-476 (NULL Pointer Dereference) using data flow analysis (PR #11)
0.1 (2018-10-08) 0.1 (2018-10-08)
===== =====
......
...@@ -27,10 +27,10 @@ let check_multiplication_before_symbol proj prog sub blk jmp tid_map symbols = ...@@ -27,10 +27,10 @@ let check_multiplication_before_symbol proj prog sub blk jmp tid_map symbols =
(Address_translation.translate_tid_to_assembler_address_string (Term.tid blk) tid_map) (Address_translation.translate_tid_to_assembler_address_string (Term.tid blk) tid_map)
(Symbol_utils.get_symbol_name_from_jmp jmp symbols)) (Symbol_utils.get_symbol_name_from_jmp jmp symbols))
let check_cwe prog proj tid_map symbol_names = let check_cwe prog proj tid_map symbol_names _ =
match symbol_names with match symbol_names with
| hd::[] -> | hd::[] ->
let symbols = Symbol_utils.build_symbols hd prog in let symbols = Symbol_utils.build_symbols hd prog in
let calls = call_finder#run prog [] in let calls = call_finder#run prog [] in
let relevant_calls = filter_calls_to_symbols calls symbols in let relevant_calls = filter_calls_to_symbols calls symbols in
check_calls relevant_calls prog proj tid_map symbols check_multiplication_before_symbol check_calls relevant_calls prog proj tid_map symbols check_multiplication_before_symbol
......
...@@ -3,6 +3,6 @@ CWE-190 (Integer Overflow or Wraparound) ...@@ -3,6 +3,6 @@ CWE-190 (Integer Overflow or Wraparound)
https://cwe.mitre.org/data/definitions/190.html https://cwe.mitre.org/data/definitions/190.html
*) *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -3,17 +3,17 @@ open Bap.Std ...@@ -3,17 +3,17 @@ open Bap.Std
open Unix open Unix
(* TODO: IVG via gitter: (* TODO: IVG via gitter:
I see, so you need the CU information, and yes BAP doesn't provide this. I see, so you need the CU information, and yes BAP doesn't provide this.
The right way to do this thing (a little bit complicated, but it The right way to do this thing (a little bit complicated, but it
will preserve the abstractions), would be the following: will preserve the abstractions), would be the following:
- Define the abstract interface for the CU providers (you can use Source module - Define the abstract interface for the CU providers (you can use Source module
or just define it manually with the interface you like) or just define it manually with the interface you like)
- Write plugins that will provide implementations - Write plugins that will provide implementations
(i.e., using readelf, objdump, IDA, LLVM, or whatever). The implementation shall (i.e., using readelf, objdump, IDA, LLVM, or whatever). The implementation shall
subscribe to Project.Info.file information stream and generate CU information every time a new file is open. subscribe to Project.Info.file information stream and generate CU information every time a new file is open.
Of course, for the prototype your approach will work, Of course, for the prototype your approach will work,
but in general case it is better to use the approach described above. *) but in general case it is better to use the approach described above. *)
let name = "CWE215" let name = "CWE215"
...@@ -29,8 +29,8 @@ let read_lines in_chan = ...@@ -29,8 +29,8 @@ let read_lines in_chan =
In_channel.close in_chan; In_channel.close in_chan;
List.rev !lines List.rev !lines
(* TODO: check if program contains strings like "DEBUG"*) (* TODO: check if program contains strings like "DEBUG"*)
let check_cwe _ project _ _ = let check_cwe _ project _ _ _ =
match Project.get project filename with match Project.get project filename with
| Some fname -> begin | Some fname -> begin
let cmd = Format.sprintf "readelf --debug-dump=decodedline %s | grep CU" fname in let cmd = Format.sprintf "readelf --debug-dump=decodedline %s | grep CU" fname in
...@@ -38,8 +38,7 @@ let check_cwe _ project _ _ = ...@@ -38,8 +38,7 @@ let check_cwe _ project _ _ =
let in_chan = Unix.open_process_in cmd in let in_chan = Unix.open_process_in cmd in
read_lines in_chan |> List.iter ~f:(fun l -> Log_utils.warn "[%s] {%s} (Information Exposure Through Debug Information) %s" name version l) read_lines in_chan |> List.iter ~f:(fun l -> Log_utils.warn "[%s] {%s} (Information Exposure Through Debug Information) %s" name version l)
with with
Unix.Unix_error (e,fm,argm) -> Unix.Unix_error (e,fm,argm) ->
Log_utils.error "[%s] {%s} %s %s %s" name version (Unix.error_message e) fm argm Log_utils.error "[%s] {%s} %s %s %s" name version (Unix.error_message e) fm argm
end end
| _ -> failwith "[CWE215] symbol_names not as expected" | _ -> failwith "[CWE215] symbol_names not as expected"
(** This module checks if a binary contains sensitive debugging information that could be leveraged to (** This module checks if a binary contains sensitive debugging information that could be leveraged to
get a better understanding of it in less time. This is basically CWE-215 (https://cwe.mitre.org/data/definitions/215.html *) get a better understanding of it in less time. This is basically CWE-215 (https://cwe.mitre.org/data/definitions/215.html *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
open Core_kernel.Std open Core_kernel.Std
open Bap.Std open Bap.Std
open Symbol_utils open Symbol_utils
include Self() include Self()
...@@ -30,10 +30,10 @@ let get_call_dests_of_sub sub = ...@@ -30,10 +30,10 @@ let get_call_dests_of_sub sub =
end end
| _ -> [] | _ -> []
let rec check dests symbols = let rec check dests symbols =
match dests with match dests with
| [] -> (List.length symbols) = 0 | [] -> (List.length symbols) = 0
| hd :: tl -> | hd :: tl ->
begin begin
match symbols with match symbols with
| [] -> true | [] -> true
...@@ -45,7 +45,7 @@ let rec check dests symbols = ...@@ -45,7 +45,7 @@ let rec check dests symbols =
end end
let check_route sub symbols = let check_route sub symbols =
let call_dests = get_call_dests_of_sub sub in let call_dests = get_call_dests_of_sub sub in
let res = check call_dests symbols in let res = check call_dests symbols in
if res then res else res if res then res else res
...@@ -62,7 +62,7 @@ let check_path prog tid_map sub path = ...@@ -62,7 +62,7 @@ let check_path prog tid_map sub path =
else else
false false
(** Checks a subfunction for CWE-243. Only functions that actually call "chroot" are considered. (** Checks a subfunction for CWE-243. Only functions that actually call "chroot" are considered.
It checks each of the configured VALID pathes found in config.json, e.g. It checks each of the configured VALID pathes found in config.json, e.g.
"chroot_pathes": [["chroot", "chdir"], ["chdir", "chroot", "setresuid"], ["chdir", "chroot", "seteuid"], "chroot_pathes": [["chroot", "chdir"], ["chdir", "chroot", "setresuid"], ["chdir", "chroot", "seteuid"],
["chdir", "chroot", "setreuid"], ["chdir", "chroot", "setuid"]]. ["chdir", "chroot", "setreuid"], ["chdir", "chroot", "setuid"]].
...@@ -81,10 +81,9 @@ let check_subfunction prog tid_map sub pathes = ...@@ -81,10 +81,9 @@ let check_subfunction prog tid_map sub pathes =
(Term.name sub) (Term.name sub)
end end
let check_cwe prog proj tid_map pathes = let check_cwe prog proj tid_map pathes _ =
let chroot_symbol = find_symbol prog "chroot" in let chroot_symbol = find_symbol prog "chroot" in
match chroot_symbol with match chroot_symbol with
| Some _ -> | Some _ ->
Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog tid_map sub pathes) Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog tid_map sub pathes)
| _ -> () | _ -> ()
(** This module implements a check for CWE-243 (Creation of chroot Jail Without Changing Working Directory). (** This module implements a check for CWE-243 (Creation of chroot Jail Without Changing Working Directory).
According to http://www.unixwiz.net/techtips/chroot-practices.html, there are several ways to achieve the According to http://www.unixwiz.net/techtips/chroot-practices.html, there are several ways to achieve the
safe creation of a chroot jail, e.g. chdir -> chroot -> setuid. They are configurable in config.json. safe creation of a chroot jail, e.g. chdir -> chroot -> setuid. They are configurable in config.json.
See https://cwe.mitre.org/data/definitions/243.html for detailed description. *) See https://cwe.mitre.org/data/definitions/243.html for detailed description. *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -59,7 +59,7 @@ let rec find_uncaught_exceptions subfunction already_checked_functions program ~ ...@@ -59,7 +59,7 @@ let rec find_uncaught_exceptions subfunction already_checked_functions program ~
(* Search for uncatched exceptions for each entry point into the binary. (* Search for uncatched exceptions for each entry point into the binary.
TODO: Exceptions, that are catched when starting from one entry point, but not from another, are masked this TODO: Exceptions, that are catched when starting from one entry point, but not from another, are masked this
way. We should check whether this produces a lot of false negatives. *) way. We should check whether this produces a lot of false negatives. *)
let check_cwe program project tid_map symbol_pairs = let check_cwe program project tid_map symbol_pairs _ =
let entry_points = Symbol_utils.get_program_entry_points program in let entry_points = Symbol_utils.get_program_entry_points program in
let _ = Seq.fold entry_points ~init:[] ~f:(fun already_checked_functions sub -> find_uncaught_exceptions ~tid_map:tid_map sub already_checked_functions program) in let _ = Seq.fold entry_points ~init:[] ~f:(fun already_checked_functions sub -> find_uncaught_exceptions ~tid_map:tid_map sub already_checked_functions program) in
() ()
...@@ -8,4 +8,4 @@ can actually catch the thrown exceptions, thus we generate some false negatives. ...@@ -8,4 +8,4 @@ can actually catch the thrown exceptions, thus we generate some false negatives.
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
open Bap.Std open Bap.Std
open Core_kernel.Std open Core_kernel.Std
open Graph_utils open Graph_utils
open Symbol_utils open Symbol_utils
let name = "CWE332" let name = "CWE332"
let version = "0.1" let version = "0.1"
let check_cwe program proj tid_map symbol_pairs = let check_cwe program proj tid_map symbol_pairs _ =
match Option.both (find_symbol program "srand") (find_symbol program "rand") with match Option.both (find_symbol program "srand") (find_symbol program "rand") with
| None -> begin | None -> begin
match (find_symbol program "rand") with match (find_symbol program "rand") with
...@@ -15,4 +15,3 @@ let check_cwe program proj tid_map symbol_pairs = ...@@ -15,4 +15,3 @@ let check_cwe program proj tid_map symbol_pairs =
| Some _ -> Log_utils.warn "[%s] {%s} (Insufficient Entropy in PRNG) program uses rand without calling srand before" name version | Some _ -> Log_utils.warn "[%s] {%s} (Insufficient Entropy in PRNG) program uses rand without calling srand before" name version
end end
| Some (srand_tid, rand_tid) -> () | Some (srand_tid, rand_tid) -> ()
(** This module implements a check for CWE332 (Insufficient Entropy in PRNG). (** This module implements a check for CWE332 (Insufficient Entropy in PRNG).
This can happen, for instance, if the PRNG is not seeded. A classical example This can happen, for instance, if the PRNG is not seeded. A classical example
would be calling rand without srand. This could lead to predictable random would be calling rand without srand. This could lead to predictable random
numbers and could, for example, weaken crypto functionality. numbers and could, for example, weaken crypto functionality.
See https://cwe.mitre.org/data/definitions/332.html for detailed description. *) See https://cwe.mitre.org/data/definitions/332.html for detailed description. *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> 'a -> 'b -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> 'a -> 'b -> string list list -> 'c -> unit
...@@ -18,14 +18,14 @@ let get_calls_to_symbol symbol_name callsites program = ...@@ -18,14 +18,14 @@ let get_calls_to_symbol symbol_name callsites program =
let get_blk_tid_of_tid sub tid = let get_blk_tid_of_tid sub tid =
let blk = Seq.find (Term.enum blk_t sub) ~f:( let blk = Seq.find (Term.enum blk_t sub) ~f:(
fun b -> fun b ->
match Term.last jmp_t b with match Term.last jmp_t b with
| Some last_term -> tid = (Term.tid last_term) | Some last_term -> tid = (Term.tid last_term)
| None -> false) in | None -> false) in
match blk with match blk with
| Some b -> Term.tid b | Some b -> Term.tid b
| _ -> assert(false) | _ -> assert(false)
let is_reachable sub source sink = let is_reachable sub source sink =
let cfg = Sub.to_graph sub in let cfg = Sub.to_graph sub in
let source_tid = Term.tid source in let source_tid = Term.tid source in
...@@ -57,6 +57,6 @@ let handle_sub sub program tid_map symbols source sink = ...@@ -57,6 +57,6 @@ let handle_sub sub program tid_map symbols source sink =
else else
() ()
let check_cwe program proj tid_map symbol_pairs = let check_cwe program proj tid_map symbol_pairs _ =
let symbols = Symbol_utils.build_symbols ["access"; "open";] in let symbols = Symbol_utils.build_symbols ["access"; "open";] in
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols "access" "open") Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols "access" "open")
...@@ -3,6 +3,6 @@ CWE-367 (Time-of-check Time-of-use (TOCTOU) Race Condition) ...@@ -3,6 +3,6 @@ CWE-367 (Time-of-check Time-of-use (TOCTOU) Race Condition)
https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use
*) *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -20,8 +20,8 @@ let handle_sub sub program tid_map symbols = ...@@ -20,8 +20,8 @@ let handle_sub sub program tid_map symbols =
() ()
end end
else () else ()
let check_cwe program proj tid_map symbols = let check_cwe program proj tid_map symbols _ =
match symbols with match symbols with
| hd::[] -> | hd::[] ->
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map hd) Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map hd)
......
(** This module checks for CWE-426 (Untrusted Search Path) (https://cwe.mitre.org/data/definitions/426.html). Basically, the program searches (** This module checks for CWE-426 (Untrusted Search Path) (https://cwe.mitre.org/data/definitions/426.html). Basically, the program searches
for critical resources on an untrusted search path that can be adjusted by an adversary. For example, see Nebula Level 1 for critical resources on an untrusted search path that can be adjusted by an adversary. For example, see Nebula Level 1
(https://exploit-exercises.com/nebula/level01/). (https://exploit-exercises.com/nebula/level01/).
According to "man system" the following problems can arise: According to "man system" the following problems can arise:
"Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might "Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might
be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in
fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2 fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2
drops privileges on startup. (Debian uses a modified bash which does not do this when invoked as sh.)" drops privileges on startup. (Debian uses a modified bash which does not do this when invoked as sh.)"
*) *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -38,7 +38,7 @@ let get_min_fp_offset arch = ...@@ -38,7 +38,7 @@ let get_min_fp_offset arch =
match arch with match arch with
| `x86 | `x86_64 -> 0x10000 | `x86 | `x86_64 -> 0x10000
| _ -> 0x0 | _ -> 0x0
(*FIXME: this is architecture dependent and ugly*) (*FIXME: this is architecture dependent and ugly*)
let get_fp_of_arch arch = let get_fp_of_arch arch =
match arch with match arch with
...@@ -91,6 +91,6 @@ let check_subfunction prog proj tid_map sub = ...@@ -91,6 +91,6 @@ let check_subfunction prog proj tid_map sub =
end) end)
end end
end) end)
let check_cwe prog proj tid_map symbol_names = let check_cwe prog proj tid_map symbol_names _ =
Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog proj tid_map sub) Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog proj tid_map sub)
...@@ -4,4 +4,4 @@ See https://cwe.mitre.org/data/definitions/457.html for detailed description. *) ...@@ -4,4 +4,4 @@ See https://cwe.mitre.org/data/definitions/457.html for detailed description. *)
val name: string val name: string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
open Core_kernel.Std open Core_kernel.Std
open Bap.Std open Bap.Std
open Symbol_utils open Symbol_utils
let name = "CWE467" let name = "CWE467"
let version = "0.1" let version = "0.1"
let get_pointer_size arch = let get_pointer_size arch =
Size.in_bytes @@ Arch.addr_size arch Size.in_bytes @@ Arch.addr_size arch
let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols = let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols =
Seq.iter (Term.enum def_t blk) ~f:(fun d -> match Exp.eval @@ Def.rhs d with Seq.iter (Term.enum def_t blk) ~f:(fun d -> match Exp.eval @@ Def.rhs d with
...@@ -23,11 +23,11 @@ let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols = ...@@ -23,11 +23,11 @@ let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols =
end end
| _ -> ()) | _ -> ())
let check_cwe prog proj tid_map symbol_names = let check_cwe prog proj tid_map symbol_names _ =
match symbol_names with match symbol_names with
| hd::[] -> | hd::[] ->
let symbols = Symbol_utils.build_symbols hd prog in let symbols = Symbol_utils.build_symbols hd prog in
let calls = call_finder#run prog [] in let calls = call_finder#run prog [] in
let relevant_calls = filter_calls_to_symbols calls symbols in let relevant_calls = filter_calls_to_symbols calls symbols in
check_calls relevant_calls prog proj tid_map symbols check_input_is_pointer_size check_calls relevant_calls prog proj tid_map symbols check_input_is_pointer_size
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
In a nutshell, it before a function call to symbols like malloc and memmove, which In a nutshell, it before a function call to symbols like malloc and memmove, which
take a size parameter and a pointer to data as input, if not accidentally the size take a size parameter and a pointer to data as input, if not accidentally the size
of the pointer instead of the data is passed. This can have severe consequences. of the pointer instead of the data is passed. This can have severe consequences.
The check is quite basic: it checks if before the call an immediate value that The check is quite basic: it checks if before the call an immediate value that
equals the size of a pointer (e.g. 4 bytes on x86) is referenced (e.g. pushed equals the size of a pointer (e.g. 4 bytes on x86) is referenced (e.g. pushed
onto the stack).The symbols are configurable in config.json. onto the stack).The symbols are configurable in config.json.
See https://cwe.mitre.org/data/definitions/467.html for detailed description. *) See https://cwe.mitre.org/data/definitions/467.html for detailed description. *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
(** This module implements a check for CWE-476 (NULL Pointer Dereference). (** This module implements a check for CWE-476 (NULL Pointer Dereference).
It checks if the result of a function that may return a NULL value is checked immediately It checks if the result of a function that may return a NULL value is checked
for NULL. The symbols are configurable in config.json. for NULL before any memory gets accessed using the return values. The symbols
See https://cwe.mitre.org/data/definitions/476.html for detailed description. *) are configurable in config.json. See https://cwe.mitre.org/data/definitions/476.html
val name: string for detailed description.
Parameters:
- strict_call_policy={true, false}: Determines behaviour on call and return instructions.
If false, we assume that the callee, resp. the caller on a return instruction,
checks all unchecked values still contained in the registers. If true, every
unchecked value on a call or return instruction gets reported.
- max_steps=<num>: Max number of steps for the dataflow fixpoint algorithm.
Notes: The check relies on Bap-generated stubs to identify return registers of the
checked functions. Therefore it only works for functions for which Bap generates
these stubs. *)
val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -35,7 +35,7 @@ let resolve_symbols prog symbols = ...@@ -35,7 +35,7 @@ let resolve_symbols prog symbols =
Seq.filter ~f:(fun s -> List.exists ~f:(fun x -> x = Sub.name s) symbols) Seq.filter ~f:(fun s -> List.exists ~f:(fun x -> x = Sub.name s) symbols)
let check_cwe prog proj tid_map symbol_names = let check_cwe prog proj tid_map symbol_names _ =
match symbol_names with match symbol_names with
| hd::[] -> | hd::[] ->
let subfunctions = Term.enum sub_t prog in let subfunctions = Term.enum sub_t prog in
...@@ -43,4 +43,3 @@ let check_cwe prog proj tid_map symbol_names = ...@@ -43,4 +43,3 @@ let check_cwe prog proj tid_map symbol_names =
get_calls_to_symbols cg subfunctions (resolve_symbols prog hd) get_calls_to_symbols cg subfunctions (resolve_symbols prog hd)
|> print_calls ~tid_map:tid_map |> print_calls ~tid_map:tid_map
| _ -> failwith "[CWE676] symbol_names not as expected" | _ -> failwith "[CWE676] symbol_names not as expected"
...@@ -5,4 +5,4 @@ See https://cwe.mitre.org/data/definitions/676.html for detailed description. *) ...@@ -5,4 +5,4 @@ See https://cwe.mitre.org/data/definitions/676.html for detailed description. *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -14,6 +14,6 @@ let handle_sub sub program tid_map symbols = ...@@ -14,6 +14,6 @@ let handle_sub sub program tid_map symbols =
(Address_translation.translate_tid_to_assembler_address_string (Term.tid sub) tid_map) (Address_translation.translate_tid_to_assembler_address_string (Term.tid sub) tid_map)
else else
() ()
let check_cwe program proj tid_map symbols = let check_cwe program proj tid_map symbols _ =
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols) Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols)
...@@ -4,4 +4,4 @@ https://cwe.mitre.org/data/definitions/782.html *) ...@@ -4,4 +4,4 @@ https://cwe.mitre.org/data/definitions/782.html *)
val name : string val name : string
val version : string val version : string
val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit val check_cwe : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit
...@@ -95,6 +95,10 @@ ...@@ -95,6 +95,10 @@
"CWE476": { "CWE476": {
"_comment": "any function that possibly returns a NULL value.", "_comment": "any function that possibly returns a NULL value.",
"_comment1": "included functions of the following libs: stdlib.h, locale.h, stdio.h, cstring.h, wchar.h", "_comment1": "included functions of the following libs: stdlib.h, locale.h, stdio.h, cstring.h, wchar.h",
"parameters": [
"strict_call_policy=true",
"max_steps=100"
],
"symbols": [ "symbols": [
"malloc", "malloc",
"calloc", "calloc",
......
...@@ -7,50 +7,54 @@ open Yojson.Basic.Util ...@@ -7,50 +7,54 @@ open Yojson.Basic.Util
include Self() include Self()
type cwe_module = { type cwe_module = {
cwe_func : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> unit; cwe_func : Bap.Std.program Bap.Std.term -> Bap.Std.project -> Bap.Std.word Bap.Std.Tid.Map.t -> string list list -> string list -> unit;
name : string; name : string;
version : string; version : string;
requires_pairs : bool; requires_pairs : bool;
has_parameters : bool;
} }
let known_modules = [{cwe_func = Cwe_190.check_cwe; name = Cwe_190.name; version = Cwe_190.version; requires_pairs = false}; let known_modules = [{cwe_func = Cwe_190.check_cwe; name = Cwe_190.name; version = Cwe_190.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_215.check_cwe; name = Cwe_215.name; version = Cwe_215.version; requires_pairs = false}; {cwe_func = Cwe_215.check_cwe; name = Cwe_215.name; version = Cwe_215.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_243.check_cwe; name = Cwe_243.name; version = Cwe_243.version; requires_pairs = true}; {cwe_func = Cwe_243.check_cwe; name = Cwe_243.name; version = Cwe_243.version; requires_pairs = true; has_parameters = false};
{cwe_func = Cwe_248.check_cwe; name = Cwe_248.name; version = Cwe_248.version; requires_pairs = false}; {cwe_func = Cwe_248.check_cwe; name = Cwe_248.name; version = Cwe_248.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_332.check_cwe; name = Cwe_332.name; version = Cwe_332.version; requires_pairs = true}; {cwe_func = Cwe_332.check_cwe; name = Cwe_332.name; version = Cwe_332.version; requires_pairs = true; has_parameters = false};
{cwe_func = Cwe_367.check_cwe; name = Cwe_367.name; version = Cwe_367.version; requires_pairs = true}; {cwe_func = Cwe_367.check_cwe; name = Cwe_367.name; version = Cwe_367.version; requires_pairs = true; has_parameters = false};
{cwe_func = Cwe_426.check_cwe; name = Cwe_426.name; version = Cwe_426.version; requires_pairs = false}; {cwe_func = Cwe_426.check_cwe; name = Cwe_426.name; version = Cwe_426.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_457.check_cwe; name = Cwe_457.name; version = Cwe_457.version; requires_pairs = false}; {cwe_func = Cwe_457.check_cwe; name = Cwe_457.name; version = Cwe_457.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_467.check_cwe; name = Cwe_467.name; version = Cwe_467.version; requires_pairs = false}; {cwe_func = Cwe_467.check_cwe; name = Cwe_467.name; version = Cwe_467.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_476.check_cwe; name = Cwe_476.name; version = Cwe_476.version; requires_pairs = false}; {cwe_func = Cwe_476.check_cwe; name = Cwe_476.name; version = Cwe_476.version; requires_pairs = false; has_parameters = true};
{cwe_func = Cwe_676.check_cwe; name = Cwe_676.name; version = Cwe_676.version; requires_pairs = false}; {cwe_func = Cwe_676.check_cwe; name = Cwe_676.name; version = Cwe_676.version; requires_pairs = false; has_parameters = false};
{cwe_func = Cwe_782.check_cwe; name = Cwe_782.name; version = Cwe_782.version; requires_pairs = false}] {cwe_func = Cwe_782.check_cwe; name = Cwe_782.name; version = Cwe_782.version; requires_pairs = false; has_parameters = false}]
let build_version_sexp () = let build_version_sexp () =
List.map known_modules ~f:(fun cwe -> Format.sprintf "(\"%s\" \"%s\")" cwe.name cwe.version) List.map known_modules ~f:(fun cwe -> Format.sprintf "(\"%s\" \"%s\")" cwe.name cwe.version)
|> String.concat ~sep:" " |> String.concat ~sep:" "
let print_module_versions () = let print_module_versions () =
Log_utils.info Log_utils.info
"[cwe_checker] module_versions: (%s)" "[cwe_checker] module_versions: (%s)"
(build_version_sexp ()) (build_version_sexp ())
let execute_cwe_module cwe json program project tid_address_map = let execute_cwe_module cwe json program project tid_address_map =
let parameters = match cwe.has_parameters with
| false -> []
| true -> Json_utils.get_parameter_list_from_json json cwe.name in
if cwe.requires_pairs = true then if cwe.requires_pairs = true then
begin begin
let symbol_pairs = Json_utils.get_symbol_lists_from_json json cwe.name in let symbol_pairs = Json_utils.get_symbol_lists_from_json json cwe.name in
cwe.cwe_func program project tid_address_map symbol_pairs cwe.cwe_func program project tid_address_map symbol_pairs parameters
end end
else else
begin begin
let symbols = Json_utils.get_symbols_from_json json cwe.name in let symbols = Json_utils.get_symbols_from_json json cwe.name in
cwe.cwe_func program project tid_address_map [symbols] cwe.cwe_func program project tid_address_map [symbols] parameters
end end
let partial_run project config modules = let partial_run project config modules =
let program = Project.program project in let program = Project.program project in
let tid_address_map = Address_translation.generate_tid_map program in let tid_address_map = Address_translation.generate_tid_map program in
let json = Yojson.Basic.from_file config in let json = Yojson.Basic.from_file config in
Log_utils.info "[cwe_checker] Just running the following analyses: %s." modules; Log_utils.info "[cwe_checker] Just running the following analyses: %s." modules;
List.iter (String.split modules ~on: ',') ~f:(fun cwe -> try List.iter (String.split modules ~on: ',') ~f:(fun cwe -> try
begin begin
...@@ -59,15 +63,15 @@ let partial_run project config modules = ...@@ -59,15 +63,15 @@ let partial_run project config modules =
execute_cwe_module cwe_mod json program project tid_address_map execute_cwe_module cwe_mod json program project tid_address_map
end end
with Not_found -> failwith "[CWE_CHECKER] Unknown CWE module") with Not_found -> failwith "[CWE_CHECKER] Unknown CWE module")
let full_run project config = let full_run project config =
let program = Project.program project in let program = Project.program project in
let tid_address_map = Address_translation.generate_tid_map program in let tid_address_map = Address_translation.generate_tid_map program in
let json = Yojson.Basic.from_file config in let json = Yojson.Basic.from_file config in
begin begin
List.iter known_modules ~f:(fun cwe -> execute_cwe_module cwe json program project tid_address_map) List.iter known_modules ~f:(fun cwe -> execute_cwe_module cwe json program project tid_address_map)
end end
let main config module_versions partial_update project = let main config module_versions partial_update project =
Log_utils.set_log_level Log_utils.DEBUG; Log_utils.set_log_level Log_utils.DEBUG;
Log_utils.set_output stdout; Log_utils.set_output stdout;
...@@ -89,7 +93,7 @@ let main config module_versions partial_update project = ...@@ -89,7 +93,7 @@ let main config module_versions partial_update project =
partial_run project config partial_update partial_run project config partial_update
end end
end end
module Cmdline = struct module Cmdline = struct
open Config open Config
let config = param string "config" ~doc:"Path to configuration file." let config = param string "config" ~doc:"Path to configuration file."
......
...@@ -23,3 +23,10 @@ let get_symbol_lists_from_json json cwe = ...@@ -23,3 +23,10 @@ let get_symbol_lists_from_json json cwe =
|> filter_member "pairs" |> filter_member "pairs"
|> flatten |> flatten
|> List.map ~f:(fun l -> List.map (to_list l) ~f:to_string) |> List.map ~f:(fun l -> List.map (to_list l) ~f:to_string)
let get_parameter_list_from_json json cwe =
[json]
|> filter_member cwe
|> filter_member "parameters"
|> flatten
|> List.map ~f:to_string
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
val get_symbol_lists_from_json : Yojson.Basic.json -> string -> string list list val get_symbol_lists_from_json : Yojson.Basic.json -> string -> string list list
val get_symbols_from_json : Yojson.Basic.json -> string -> string list val get_symbols_from_json : Yojson.Basic.json -> string -> string list
val get_parameter_list_from_json : Yojson.Basic.json -> string -> string list
#include <stdlib.h> #include <stdlib.h>
void func1(){ void func1(){
void* data = malloc(20); void* data = malloc(20000);
if (data == NULL){ if (data == NULL){
exit(42); exit(42);
} }
...@@ -9,13 +9,14 @@ void func1(){ ...@@ -9,13 +9,14 @@ void func1(){
} }
void func2(){ void func2(){
void* data = malloc(20); int* data = malloc(200000);
printf("%i", data[0]);
free(data); free(data);
} }
void main() { void main() {
func1(); func1();
func2(); func2();
} }
...@@ -10,114 +10,117 @@ CPP_ARM=arm-linux-gnueabi-g++-5 ...@@ -10,114 +10,117 @@ CPP_ARM=arm-linux-gnueabi-g++-5
CPP_MIPS=mips-linux-gnu-g++-5 CPP_MIPS=mips-linux-gnu-g++-5
CPP_PPC=powerpc-linux-gnu-g++-5 CPP_PPC=powerpc-linux-gnu-g++-5
CFLAGS_X64=-O0 -g -fno-stack-protector -std=c11 CFLAGS_X64=-g -fno-stack-protector -std=c11
CFLAGS_X86=-O0 -g -m32 -fno-stack-protector -std=c11 CFLAGS_X86=-g -m32 -fno-stack-protector -std=c11
CFLAGS_ARM=-O0 -g -fno-stack-protector -std=c11 CFLAGS_ARM=-g -fno-stack-protector -std=c11
CFLAGS_MIPS=-O0 -g -fno-stack-protector -std=c11 CFLAGS_MIPS=-g -fno-stack-protector -std=c11
CFLAGS_PPC=-O0 -g -fno-stack-protector -std=c11 CFLAGS_PPC=-g -fno-stack-protector -std=c11
CPPFLAGS_X64=-O0 -g -fno-stack-protector CPPFLAGS_X64=-g -fno-stack-protector
CPPFLAGS_X86=-O0 -g -m32 -fno-stack-protector CPPFLAGS_X86=-g -m32 -fno-stack-protector
CPPFLAGS_ARM=-O0 -g -fno-stack-protector CPPFLAGS_ARM=-g -fno-stack-protector
CPPFLAGS_MIPS=-O0 -g -fno-stack-protector CPPFLAGS_MIPS=-g -fno-stack-protector
CPPFLAGS_PPC=-O0 -g -fno-stack-protector CPPFLAGS_PPC=-g -fno-stack-protector
OPTIMIZE=-O3
NO_OPTIMIZE=-O0
define compile_x64 define compile_x64
@echo "Compiling x64 target:" $(1) @echo "Compiling x64 target:" $(1)
$(CC_x64) $(CFLAGS_X64) -o build/$(1)_x64.out $(1).c $(CC_x64) $(CFLAGS_X64) $(2) -o build/$(1)_x64.out $(1).c
execstack -s build/$(1)_x64.out execstack -s build/$(1)_x64.out
endef endef
define compile_x64_cpp define compile_x64_cpp
@echo "Compiling x64 target:" $(1) @echo "Compiling x64 target:" $(1)
$(CPP_x64) $(CPPFLAGS_X64) -o build/$(1)_x64.out $(1).cpp $(CPP_x64) $(CPPFLAGS_X64) $(2) -o build/$(1)_x64.out $(1).cpp
execstack -s build/$(1)_x64.out execstack -s build/$(1)_x64.out
endef endef
define compile_x86 define compile_x86
@echo "Compiling x86 target:" $(1) @echo "Compiling x86 target:" $(1)
$(CC_X86) $(CFLAGS_X86) -o build/$(1)_x86.out $(1).c $(CC_X86) $(CFLAGS_X86) $(2) -o build/$(1)_x86.out $(1).c
execstack -s build/$(1)_x86.out execstack -s build/$(1)_x86.out
endef endef
define compile_x86_cpp define compile_x86_cpp
@echo "Compiling x86 target:" $(1) @echo "Compiling x86 target:" $(1)
$(CPP_X86) $(CPPFLAGS_X86) -o build/$(1)_x86.out $(1).cpp $(CPP_X86) $(CPPFLAGS_X86) $(2) -o build/$(1)_x86.out $(1).cpp
execstack -s build/$(1)_x86.out execstack -s build/$(1)_x86.out
endef endef
define compile_mips define compile_mips
@echo "Compiling mips target:" $(1) @echo "Compiling mips target:" $(1)
$(CC_MIPS) $(CFLAGS_MIPS) -o build/$(1)_mips.out $(1).c $(CC_MIPS) $(CFLAGS_MIPS) $(2) -o build/$(1)_mips.out $(1).c
execstack -s build/$(1)_mips.out execstack -s build/$(1)_mips.out
endef endef
define compile_mips_cpp define compile_mips_cpp
@echo "Compiling mips target:" $(1) @echo "Compiling mips target:" $(1)
$(CPP_MIPS) $(CPPFLAGS_MIPS) -o build/$(1)_mips.out $(1).cpp $(CPP_MIPS) $(CPPFLAGS_MIPS) $(2) -o build/$(1)_mips.out $(1).cpp
execstack -s build/$(1)_mips.out execstack -s build/$(1)_mips.out
endef endef
define compile_arm define compile_arm
@echo "Compiling arm target:" $(1) @echo "Compiling arm target:" $(1)
$(CC_ARM) $(CFLAGS_ARM) -o build/$(1)_arm.out $(1).c $(CC_ARM) $(CFLAGS_ARM) $(2) -o build/$(1)_arm.out $(1).c
execstack -s build/$(1)_arm.out execstack -s build/$(1)_arm.out
endef endef
define compile_arm_cpp define compile_arm_cpp
@echo "Compiling arm target:" $(1) @echo "Compiling arm target:" $(1)
$(CPP_ARM) $(CPPFLAGS_ARM) -o build/$(1)_arm.out $(1).cpp $(CPP_ARM) $(CPPFLAGS_ARM) $(2) -o build/$(1)_arm.out $(1).cpp
execstack -s build/$(1)_arm.out execstack -s build/$(1)_arm.out
endef endef
define compile_ppc define compile_ppc
@echo "Compiling ppc target:" $(1) @echo "Compiling ppc target:" $(1)
$(CC_PPC) $(CFLAGS_PPC) -o build/$(1)_ppc.out $(1).c $(CC_PPC) $(CFLAGS_PPC) $(2) -o build/$(1)_ppc.out $(1).c
execstack -s build/$(1)_ppc.out execstack -s build/$(1)_ppc.out
endef endef
define compile_ppc_cpp define compile_ppc_cpp
@echo "Compiling ppc target:" $(1) @echo "Compiling ppc target:" $(1)
$(CPP_PPC) $(CPPFLAGS_PPC) -o build/$(1)_ppc.out $(1).cpp $(CPP_PPC) $(CPPFLAGS_PPC) $(2) -o build/$(1)_ppc.out $(1).cpp
execstack -s build/$(1)_ppc.out execstack -s build/$(1)_ppc.out
endef endef
define compile_all define compile_all
$(shell mkdir -p "build") $(shell mkdir -p "build")
$(call compile_x64,$(1)) $(call compile_x64,$(1),$(2))
$(call compile_x86,$(1)) $(call compile_x86,$(1),$(2))
$(call compile_arm,$(1)) $(call compile_arm,$(1),$(2))
$(call compile_mips,$(1)) $(call compile_mips,$(1),$(2))
$(call compile_ppc,$(1)) $(call compile_ppc,$(1),$(2))
endef endef
define compile_all_cpp define compile_all_cpp
$(shell mkdir -p "build") $(shell mkdir -p "build")
$(call compile_x64_cpp,$(1)) $(call compile_x64_cpp,$(1),$(2))
$(call compile_x86_cpp,$(1)) $(call compile_x86_cpp,$(1),$(2))
$(call compile_arm_cpp,$(1)) $(call compile_arm_cpp,$(1),$(2))
$(call compile_mips_cpp,$(1)) $(call compile_mips_cpp,$(1),$(2))
$(call compile_ppc_cpp,$(1)) $(call compile_ppc_cpp,$(1),$(2))
endef endef
all: all:
$(call compile_all,c_constructs) $(call compile_all,c_constructs,$(NO_OPTIMIZE))
$(call compile_all,cwe_190) $(call compile_all,cwe_190,$(NO_OPTIMIZE))
$(call compile_all,cwe_243) $(call compile_all,cwe_243,$(NO_OPTIMIZE))
$(call compile_all,cwe_243_clean) $(call compile_all,cwe_243_clean,$(NO_OPTIMIZE))
$(call compile_all_cpp,cwe_248) $(call compile_all_cpp,cwe_248,$(NO_OPTIMIZE))
$(call compile_all,cwe_332) $(call compile_all,cwe_332,$(NO_OPTIMIZE))
$(call compile_all,cwe_367) $(call compile_all,cwe_367,$(NO_OPTIMIZE))
$(call compile_all,cwe_415) $(call compile_all,cwe_415,$(NO_OPTIMIZE))
$(call compile_all,cwe_426) $(call compile_all,cwe_426,$(NO_OPTIMIZE))
$(call compile_all,cwe_457) $(call compile_all,cwe_457,$(NO_OPTIMIZE))
$(call compile_all,cwe_467) $(call compile_all,cwe_467,$(NO_OPTIMIZE))
$(call compile_all,cwe_476) $(call compile_all,cwe_476,$(OPTIMIZE))
$(call compile_all,cwe_478) $(call compile_all,cwe_478,$(NO_OPTIMIZE))
$(call compile_all,cwe_676) $(call compile_all,cwe_676,$(NO_OPTIMIZE))
$(call compile_x64,cwe_782) $(call compile_x64,cwe_782,$(NO_OPTIMIZE))
$(call compile_all,arrays) $(call compile_all,arrays,$(NO_OPTIMIZE))
$(call compile_all,memory_access) $(call compile_all,memory_access,$(NO_OPTIMIZE))
clean: clean:
rm -rf build rm -rf build
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment