-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUnsafeUnpack.ql
More file actions
56 lines (50 loc) · 2.22 KB
/
UnsafeUnpack.ql
File metadata and controls
56 lines (50 loc) · 2.22 KB
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
/**
* @name Arbitrary file write during a remotely downloaded tarball extraction
* @description Extracting files from a malicious tarball using `shutil.unpack_archive()` without validating
* that the destination file path is within the destination directory can cause files outside
* the destination directory to be overwritten. More precisely, if the tarball comes from a remote location.
* @kind path-problem
* @id py/unsafe-unpacking
* @problem.severity error
* @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-022bis
*/
import python
import experimental.semmle.python.Concepts
import DataFlow::PathGraph
import semmle.python.ApiGraphs
import semmle.python.dataflow.new.internal.Attributes
import semmle.python.dataflow.new.DataFlow
import semmle.python.ApiGraphs
import semmle.python.dataflow.new.TaintTracking
import semmle.python.Concepts
class UnsafeUnpackingConfig extends TaintTracking::Configuration {
UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" }
override predicate isSource(DataFlow::Node source) {
// A source coming from a remote location
exists(Http::Client::Request request | source = request) and
not source.getScope().getLocation().getFile().inStdlib()
}
override predicate isSink(DataFlow::Node sink) {
// A sink capturing method calls to `unpack_archive`.
sink =
API::moduleImport("shutil").getMember("unpack_archive").getACall().getParameter(0).asSink() and
not sink.getScope().getLocation().getFile().inStdlib()
}
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Writing the response data to the archive
exists(API::CallNode call, MethodCallNode w |
nodeTo = call.getArg(0) and
call = API::builtin("open").getACall() and
w.getMethodName() = "write" and
w.getObject() = call.getReturn().getAValueReachableFromSource() and
nodeFrom = w.getArg(0)
)
}
}
from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select source.getNode(), source, sink, "Unsafe extraction from a malicious tarball, is used in a $@",
source.getAQlClass(), "during archive unpacking."