mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Python: Tarslip query; Add sink for members and sanitizers for tarinfo objects.
This commit is contained in:
@@ -49,6 +49,9 @@ class TarfileOpen extends TaintSource {
|
||||
* this tarfile is safe.
|
||||
*/
|
||||
not this.(CallNode).getAnArg().refersTo(any(StringObject str))
|
||||
and
|
||||
/* Ignore opens within the tarfile module itself */
|
||||
not this.(ControlFlowNode).getLocation().getFile().getBaseName() = "tarfile.py"
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
@@ -73,13 +76,33 @@ class TarFileInfo extends TaintKind {
|
||||
}
|
||||
|
||||
|
||||
/* For efficiency we don't want to track the flow of taint
|
||||
* around the tarfile module. */
|
||||
class ExcludeTarFilePy extends Sanitizer {
|
||||
|
||||
ExcludeTarFilePy() {
|
||||
this = "Tar sanitizer"
|
||||
}
|
||||
|
||||
override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
|
||||
node.getLocation().getFile().getBaseName() = "tarfile.py" and
|
||||
(
|
||||
taint instanceof OpenTarFile
|
||||
or
|
||||
taint instanceof TarFileInfo
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Any call to an extractall method */
|
||||
class ExtractAllSink extends TaintSink {
|
||||
|
||||
CallNode call;
|
||||
|
||||
ExtractAllSink() {
|
||||
this = call.getFunction().(AttrNode).getObject("extractall")
|
||||
this = call.getFunction().(AttrNode).getObject("extractall") and
|
||||
count(call.getAnArg()) = 0
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
@@ -104,6 +127,25 @@ class ExtractSink extends TaintSink {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Members argument to extract method */
|
||||
class ExtractMembersSink extends TaintSink {
|
||||
|
||||
CallNode call;
|
||||
|
||||
ExtractMembersSink() {
|
||||
call.getFunction().(AttrNode).getName() = "extractall" and
|
||||
(this = call.getArg(0) or this = call.getArgByName("members"))
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind.(SequenceKind).getItem() instanceof TarFileInfo
|
||||
or
|
||||
kind instanceof OpenTarFile
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TarFileInfoSanitizer extends Sanitizer {
|
||||
|
||||
TarFileInfoSanitizer() {
|
||||
@@ -114,33 +156,35 @@ class TarFileInfoSanitizer extends Sanitizer {
|
||||
path_sanitizing_test(test.getTest()) and
|
||||
taint instanceof TarFileInfo
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private predicate path_sanitizing_test(ControlFlowNode test) {
|
||||
checks_not_absolute(test) and
|
||||
test.getAChild+().getNode().(StrConst).getText() = ".."
|
||||
}
|
||||
|
||||
private predicate checks_not_absolute(ControlFlowNode test) {
|
||||
test.getAChild+().(CallNode).getFunction().pointsTo(Module::named("os.path").attr("absfile"))
|
||||
/* Assume that any test with "path" in it is a sanitizer */
|
||||
test.getAChild+().(AttrNode).getName() = "path"
|
||||
or
|
||||
test.getAChild+().getNode().(StrConst).getText() = "/"
|
||||
test.getAChild+().(NameNode).getId() = "path"
|
||||
}
|
||||
|
||||
|
||||
class TarSlipConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
TarSlipConfiguration() { this = "TarSlip configuration" }
|
||||
|
||||
override predicate isSource(TaintTracking::Source source) { source instanceof TarfileOpen }
|
||||
|
||||
override predicate isSink(TaintTracking::Sink sink) {
|
||||
sink instanceof ExtractSink or sink instanceof ExtractAllSink
|
||||
override predicate isSink(TaintTracking::Sink sink) {
|
||||
sink instanceof ExtractSink or
|
||||
sink instanceof ExtractAllSink or
|
||||
sink instanceof ExtractMembersSink
|
||||
}
|
||||
|
||||
override predicate isSanitizer(Sanitizer sanitizer) {
|
||||
sanitizer instanceof TarFileInfoSanitizer
|
||||
or
|
||||
sanitizer instanceof ExcludeTarFilePy
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -148,4 +192,3 @@ from TarSlipConfiguration config, TaintedPathSource src, TaintedPathSink sink
|
||||
where config.hasFlowPath(src, sink)
|
||||
select sink.getSink(), src, sink, "Extraction of tarfile from $@", src.getSource(), "a potentially untrusted source"
|
||||
|
||||
|
||||
|
||||
@@ -703,7 +703,7 @@ class TaintedNode extends TTaintedNode {
|
||||
/** Holds if the underlying CFG node for this node is a vulnerable node
|
||||
* and is vulnerable to this node's taint.
|
||||
*/
|
||||
predicate isVulnerableSink() {
|
||||
predicate isSink() {
|
||||
exists(TaintedNode src, TaintSink vuln |
|
||||
src.isSource() and
|
||||
src.getASuccessor*() = this and
|
||||
@@ -712,6 +712,13 @@ class TaintedNode extends TTaintedNode {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED -- Use `TaintedNode.isSink()` instead
|
||||
* Sinks are not necessarily vulnerable
|
||||
* For removal 2020-07-01 */
|
||||
deprecated predicate isVulnerableSink() {
|
||||
this.isSink()
|
||||
}
|
||||
|
||||
TaintFlowImplementation::TrackedTaint fromAttribute(string name) {
|
||||
result = this.getTrackedValue().(TaintFlowImplementation::TrackedAttribute).fromAttribute(name)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
edges
|
||||
| tarslip.py:12:7:12:39 | tarfile.open | tarslip.py:13:1:13:3 | tarfile.open |
|
||||
| tarslip.py:12:7:12:39 | tarfile.open | tarslip.py:14:1:14:3 | tarfile.open |
|
||||
| tarslip.py:16:7:16:39 | tarfile.open | tarslip.py:17:14:17:16 | tarfile.open |
|
||||
| tarslip.py:16:7:16:39 | tarfile.open | tarslip.py:18:5:18:7 | tarfile.open |
|
||||
| tarslip.py:17:5:17:9 | tarfile.entry | tarslip.py:18:17:18:21 | tarfile.entry |
|
||||
| tarslip.py:17:14:17:16 | tarfile.open | tarslip.py:17:5:17:9 | tarfile.entry |
|
||||
| tarslip.py:26:7:26:39 | tarfile.open | tarslip.py:27:14:27:16 | tarfile.open |
|
||||
| tarslip.py:26:7:26:39 | tarfile.open | tarslip.py:30:5:30:7 | tarfile.open |
|
||||
| tarslip.py:27:5:27:9 | tarfile.entry | tarslip.py:28:22:28:26 | tarfile.entry |
|
||||
| tarslip.py:27:14:27:16 | tarfile.open | tarslip.py:27:5:27:9 | tarfile.entry |
|
||||
| tarslip.py:28:22:28:26 | tarfile.entry | tarslip.py:28:22:28:31 | tarfile.entry |
|
||||
| tarslip.py:33:7:33:39 | tarfile.open | tarslip.py:34:14:34:16 | tarfile.open |
|
||||
| tarslip.py:33:7:33:39 | tarfile.open | tarslip.py:37:5:37:7 | tarfile.open |
|
||||
| tarslip.py:34:5:34:9 | tarfile.entry | tarslip.py:35:16:35:20 | tarfile.entry |
|
||||
| tarslip.py:34:5:34:9 | tarfile.entry | tarslip.py:37:17:37:21 | tarfile.entry |
|
||||
| tarslip.py:34:14:34:16 | tarfile.open | tarslip.py:34:5:34:9 | tarfile.entry |
|
||||
| tarslip.py:35:16:35:20 | tarfile.entry | tarslip.py:35:16:35:25 | tarfile.entry |
|
||||
| tarslip.py:40:7:40:39 | tarfile.open | tarslip.py:41:1:41:3 | tarfile.open |
|
||||
| tarslip.py:40:7:40:39 | tarfile.open | tarslip.py:41:24:41:26 | tarfile.open |
|
||||
| tarslip.py:45:17:45:23 | tarfile.open | tarslip.py:46:17:46:23 | tarfile.open |
|
||||
| tarslip.py:46:9:46:12 | tarfile.entry | tarslip.py:47:20:47:23 | tarfile.entry |
|
||||
| tarslip.py:46:9:46:12 | tarfile.entry | tarslip.py:49:15:49:18 | tarfile.entry |
|
||||
| tarslip.py:46:17:46:23 | tarfile.open | tarslip.py:46:9:46:12 | tarfile.entry |
|
||||
| tarslip.py:51:7:51:39 | tarfile.open | tarslip.py:52:1:52:3 | tarfile.open |
|
||||
| tarslip.py:51:7:51:39 | tarfile.open | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
| tarslip.py:52:36:52:38 | tarfile.open | tarslip.py:45:17:45:23 | tarfile.open |
|
||||
parents
|
||||
| tarslip.py:45:17:45:23 | tarfile.open | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
| tarslip.py:46:9:46:12 | tarfile.entry | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
| tarslip.py:46:17:46:23 | tarfile.open | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
| tarslip.py:47:20:47:23 | tarfile.entry | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
| tarslip.py:49:15:49:18 | tarfile.entry | tarslip.py:52:36:52:38 | tarfile.open |
|
||||
#select
|
||||
| tarslip.py:13:1:13:3 | Taint sink | tarslip.py:12:7:12:39 | tarfile.open | tarslip.py:13:1:13:3 | tarfile.open | Extraction of tarfile from $@ | tarslip.py:12:7:12:39 | Taint source | a potentially untrusted source |
|
||||
| tarslip.py:18:17:18:21 | Taint sink | tarslip.py:16:7:16:39 | tarfile.open | tarslip.py:18:17:18:21 | tarfile.entry | Extraction of tarfile from $@ | tarslip.py:16:7:16:39 | Taint source | a potentially untrusted source |
|
||||
| tarslip.py:37:17:37:21 | Taint sink | tarslip.py:33:7:33:39 | tarfile.open | tarslip.py:37:17:37:21 | tarfile.entry | Extraction of tarfile from $@ | tarslip.py:33:7:33:39 | Taint source | a potentially untrusted source |
|
||||
| tarslip.py:41:24:41:26 | Taint sink | tarslip.py:40:7:40:39 | tarfile.open | tarslip.py:41:24:41:26 | tarfile.open | Extraction of tarfile from $@ | tarslip.py:40:7:40:39 | Taint source | a potentially untrusted source |
|
||||
|
||||
@@ -35,3 +35,18 @@ for entry in tar:
|
||||
if ".." in entry.name:
|
||||
raise ValueError("Illegal tar archive entry")
|
||||
tar.extract(entry, "/tmp/unpack/")
|
||||
|
||||
#Unsanitized members
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(members=tar)
|
||||
|
||||
|
||||
#Sanitize members
|
||||
def safemembers(members):
|
||||
for info in members:
|
||||
if badpath(info):
|
||||
raise
|
||||
yield info
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(members=safemembers(tar))
|
||||
|
||||
Reference in New Issue
Block a user