Python: Add additional taint steps for containers

This commit is contained in:
Rasmus Wriedt Larsen
2020-08-26 19:19:14 +02:00
parent b6049765a8
commit b974dadca1
3 changed files with 59 additions and 22 deletions

View File

@@ -32,6 +32,8 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
stringManipulation(nodeFrom, nodeTo)
or
jsonStep(nodeFrom, nodeTo)
or
containerStep(nodeFrom, nodeTo)
}
/**
@@ -135,3 +137,38 @@ predicate jsonStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
call.getArg(0) = nodeFrom.getNode()
)
}
/**
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to containers
* (lists/sets/dictionaries): literals, constructor invocation, methods. Note that this
* is currently very imprecise, as an example, since we model `dict.get`, we treat any
* `<tainted object>.get(<arg>)` will be tainted, whether it's true or not.
*/
predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
// construction by literal
// TODO: Not limiting the content argument here feels like a BIG hack, but we currently get nothing for free :|
storeStep(nodeFrom, _, nodeTo)
or
// constructor call
exists(CallNode call | call = nodeTo.getNode() |
call.getFunction().(NameNode).getId() in ["list", "set", "frozenset", "dict", "defaultdict", "tuple"] and
call.getArg(0) = nodeFrom.getNode()
)
or
// functions operating on collections
exists(CallNode call | call = nodeTo.getNode() |
call.getFunction().(NameNode).getId() in ["sorted", "reversed", "iter", "next"] and
call.getArg(0) = nodeFrom.getNode()
)
or
// methods
exists(CallNode call, string name | call = nodeTo.getNode() |
name in [
// general
"copy", "pop",
// dict
"values", "items", "get", "popitem"
] and
call.getFunction().(AttrNode).getObject(name) = nodeFrom.getNode()
)
}

View File

@@ -1,7 +1,7 @@
| collections.py:16 | fail | test_access | tainted_list.copy() |
| collections.py:16 | ok | test_access | tainted_list.copy() |
| string.py:17 | ok | str_methods | ts.casefold() |
| string.py:19 | ok | str_methods | ts.format_map(..) |
| string.py:20 | fail | str_methods | "{unsafe}".format_map(..) |
| string.py:20 | ok | str_methods | "{unsafe}".format_map(..) |
| string.py:31 | fail | binary_decode_encode | base64.a85encode(..) |
| string.py:32 | fail | binary_decode_encode | base64.a85decode(..) |
| string.py:35 | fail | binary_decode_encode | base64.b85encode(..) |

View File

@@ -1,23 +1,23 @@
| collections.py:24 | ok | test_construction | tainted_string |
| collections.py:25 | fail | test_construction | tainted_list |
| collections.py:26 | fail | test_construction | tainted_tuple |
| collections.py:27 | fail | test_construction | tainted_set |
| collections.py:28 | fail | test_construction | tainted_dict |
| collections.py:32 | fail | test_construction | list(..) |
| collections.py:33 | fail | test_construction | list(..) |
| collections.py:34 | fail | test_construction | list(..) |
| collections.py:35 | fail | test_construction | list(..) |
| collections.py:36 | fail | test_construction | list(..) |
| collections.py:38 | fail | test_construction | tuple(..) |
| collections.py:39 | fail | test_construction | set(..) |
| collections.py:40 | fail | test_construction | frozenset(..) |
| collections.py:25 | ok | test_construction | tainted_list |
| collections.py:26 | ok | test_construction | tainted_tuple |
| collections.py:27 | ok | test_construction | tainted_set |
| collections.py:28 | ok | test_construction | tainted_dict |
| collections.py:32 | ok | test_construction | list(..) |
| collections.py:33 | ok | test_construction | list(..) |
| collections.py:34 | ok | test_construction | list(..) |
| collections.py:35 | ok | test_construction | list(..) |
| collections.py:36 | ok | test_construction | list(..) |
| collections.py:38 | ok | test_construction | tuple(..) |
| collections.py:39 | ok | test_construction | set(..) |
| collections.py:40 | ok | test_construction | frozenset(..) |
| collections.py:48 | ok | test_access | tainted_list[0] |
| collections.py:49 | ok | test_access | tainted_list[x] |
| collections.py:50 | ok | test_access | tainted_list[Slice] |
| collections.py:52 | fail | test_access | sorted(..) |
| collections.py:53 | fail | test_access | reversed(..) |
| collections.py:54 | fail | test_access | iter(..) |
| collections.py:55 | fail | test_access | next(..) |
| collections.py:52 | ok | test_access | sorted(..) |
| collections.py:53 | ok | test_access | reversed(..) |
| collections.py:54 | ok | test_access | iter(..) |
| collections.py:55 | ok | test_access | next(..) |
| collections.py:56 | fail | test_access | copy(..) |
| collections.py:57 | ok | test_access | deepcopy(..) |
| collections.py:61 | fail | test_access | a |
@@ -26,9 +26,9 @@
| collections.py:64 | fail | test_access | h |
| collections.py:66 | fail | test_access | i |
| collections.py:73 | ok | test_dict_access | tainted_dict["name"] |
| collections.py:74 | fail | test_dict_access | tainted_dict.get(..) |
| collections.py:74 | ok | test_dict_access | tainted_dict.get(..) |
| collections.py:75 | ok | test_dict_access | tainted_dict[x] |
| collections.py:76 | fail | test_dict_access | tainted_dict.copy() |
| collections.py:76 | ok | test_dict_access | tainted_dict.copy() |
| collections.py:80 | fail | test_dict_access | v |
| collections.py:82 | fail | test_dict_access | v |
| collections.py:90 | fail | test_named_tuple | point[0] |
@@ -70,7 +70,7 @@
| string.py:49 | ok | str_methods | "{}".format(..) |
| string.py:50 | ok | str_methods | "{unsafe}".format(..) |
| string.py:52 | ok | str_methods | ts.join(..) |
| string.py:53 | fail | str_methods | "".join(..) |
| string.py:53 | ok | str_methods | "".join(..) |
| string.py:55 | ok | str_methods | ts.ljust(..) |
| string.py:56 | ok | str_methods | ts.lstrip() |
| string.py:57 | ok | str_methods | ts.lower() |
@@ -99,7 +99,7 @@
| string.py:100 | fail | non_syntactic | _str(..) |
| string.py:109 | ok | percent_fmt | BinaryExpr |
| string.py:110 | ok | percent_fmt | BinaryExpr |
| string.py:111 | fail | percent_fmt | BinaryExpr |
| string.py:111 | ok | percent_fmt | BinaryExpr |
| string.py:121 | fail | binary_decode_encode | base64.b64encode(..) |
| string.py:122 | fail | binary_decode_encode | base64.b64decode(..) |
| string.py:124 | fail | binary_decode_encode | base64.standard_b64encode(..) |