mirror of
https://github.com/github/codeql.git
synced 2026-05-04 05:05:12 +02:00
JavaScript: Add tar-stream extraction to ZipSlip query.
This commit is contained in:
@@ -46,6 +46,8 @@ module ZipSlip {
|
||||
private DataFlow::SourceNode parsedArchive() {
|
||||
result = DataFlow::moduleImport("unzip").getAMemberCall("Parse")
|
||||
or
|
||||
result = DataFlow::moduleImport("tar-stream").getAMemberCall("extract")
|
||||
or
|
||||
// `streamProducer.pipe(unzip.Parse())` is a typical (but not
|
||||
// universal) pattern when using nodejs streams, whose return
|
||||
// value is the parsed stream.
|
||||
@@ -56,6 +58,9 @@ module ZipSlip {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a property that is used to get the filename part of an archive entry. */
|
||||
private string getAFilenameProperty() { result = "path" or result = "name" }
|
||||
|
||||
/** A zip archive entry path access, as a source for unsafe zip extraction. */
|
||||
class UnzipEntrySource extends Source {
|
||||
// For example, in
|
||||
@@ -74,9 +79,8 @@ module ZipSlip {
|
||||
exists(DataFlow::CallNode cn |
|
||||
cn = parsedArchive().getAMemberCall("on") and
|
||||
cn.getArgument(0).mayHaveStringValue("entry") and
|
||||
this = cn.getCallback(1)
|
||||
.getParameter(0)
|
||||
.getAPropertyRead("path"))
|
||||
this = cn.getCallback(1).getParameter(0).getAPropertyRead(getAFilenameProperty())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +103,7 @@ module ZipSlip {
|
||||
|
||||
/** An expression that sanitizes by calling path.basename */
|
||||
class BasenameSanitizer extends Sanitizer {
|
||||
BasenameSanitizer() {
|
||||
this = DataFlow::moduleImport("path").getAMemberCall("basename")
|
||||
}
|
||||
BasenameSanitizer() { this = DataFlow::moduleImport("path").getAMemberCall("basename") }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const fs = require('fs');
|
||||
const tar = require('tar-stream');
|
||||
const extract = tar.extract();
|
||||
|
||||
extract.on('entry', (header, stream, next) => {
|
||||
const out = fs.createWriteStream(header.name);
|
||||
stream.pipe(out);
|
||||
stream.on('end', () => {
|
||||
next();
|
||||
})
|
||||
stream.resume();
|
||||
})
|
||||
|
||||
extract.on('finish', () => {
|
||||
console.log('finished');
|
||||
});
|
||||
|
||||
fs.createReadStream('./bad.tar').pipe(extract);
|
||||
@@ -1,4 +1,5 @@
|
||||
nodes
|
||||
| TarSlipBad.js:6:36:6:46 | header.name |
|
||||
| ZipSlipBad2.js:5:9:5:46 | fileName |
|
||||
| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path |
|
||||
| ZipSlipBad2.js:5:37:5:46 | entry.path |
|
||||
@@ -13,5 +14,6 @@ edges
|
||||
| ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName |
|
||||
| ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName |
|
||||
#select
|
||||
| TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:6:36:6:46 | header.name | item path |
|
||||
| ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path |
|
||||
| ZipSlipBad.js:8:37:8:44 | fileName | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:7:22:7:31 | entry.path | item path |
|
||||
|
||||
Reference in New Issue
Block a user