mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge pull request #1095 from xiemaisi/js/base64
Approved by esben-semmle
This commit is contained in:
@@ -6,6 +6,7 @@ import semmle.javascript.Aliases
|
||||
import semmle.javascript.AMD
|
||||
import semmle.javascript.AST
|
||||
import semmle.javascript.BasicBlocks
|
||||
import semmle.javascript.Base64
|
||||
import semmle.javascript.CFG
|
||||
import semmle.javascript.Classes
|
||||
import semmle.javascript.Closure
|
||||
|
||||
200
javascript/ql/src/semmle/javascript/Base64.qll
Normal file
200
javascript/ql/src/semmle/javascript/Base64.qll
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with base64 encoders and decoders.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
module Base64 {
|
||||
/** A call to a base64 encoder. */
|
||||
class Encode extends DataFlow::Node {
|
||||
Encode::Range encode;
|
||||
|
||||
Encode() { this = encode }
|
||||
|
||||
/** Gets the input passed to the encoder. */
|
||||
DataFlow::Node getInput() { result = encode.getInput() }
|
||||
|
||||
/** Gets the base64-encoded output of the encoder. */
|
||||
DataFlow::Node getOutput() { result = encode.getOutput() }
|
||||
}
|
||||
|
||||
module Encode {
|
||||
/**
|
||||
* A data flow node that should be considered a call to a base64 encoder.
|
||||
*
|
||||
* New base64 encoding functions can be supported by extending this class.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the input passed to the encoder. */
|
||||
abstract DataFlow::Node getInput();
|
||||
|
||||
/** Gets the base64-encoded output of the encoder. */
|
||||
abstract DataFlow::Node getOutput();
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a base64 decoder. */
|
||||
class Decode extends DataFlow::Node {
|
||||
Decode::Range encode;
|
||||
|
||||
Decode() { this = encode }
|
||||
|
||||
/** Gets the base64-encoded input passed to the decoder. */
|
||||
DataFlow::Node getInput() { result = encode.getInput() }
|
||||
|
||||
/** Gets the output of the decoder. */
|
||||
DataFlow::Node getOutput() { result = encode.getOutput() }
|
||||
}
|
||||
|
||||
module Decode {
|
||||
/**
|
||||
* A data flow node that should be considered a call to a base64 decoder.
|
||||
*
|
||||
* New base64 decoding functions can be supported by extending this class.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the base64-encoded input passed to the decoder. */
|
||||
abstract DataFlow::Node getInput();
|
||||
|
||||
/** Gets the output of the decoder. */
|
||||
abstract DataFlow::Node getOutput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base64 decoding step, viewed as a taint-propagating data flow edge.
|
||||
*
|
||||
* Note that we currently do not model base64 encoding as a taint-propagating data flow edge
|
||||
* to avoid false positives.
|
||||
*/
|
||||
private class Base64DecodingStep extends TaintTracking::AdditionalTaintStep {
|
||||
Decode dec;
|
||||
|
||||
Base64DecodingStep() { this = dec }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = dec.getInput() and
|
||||
succ = dec.getOutput()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `btoa`. */
|
||||
private class Btoa extends Base64::Encode::Range, DataFlow::CallNode {
|
||||
Btoa() { this = DataFlow::globalVarRef("btoa").getACall() }
|
||||
|
||||
override DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
/** A call to `atob`. */
|
||||
private class Atob extends Base64::Decode::Range, DataFlow::CallNode {
|
||||
Atob() { this = DataFlow::globalVarRef("atob").getACall() }
|
||||
|
||||
override DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Buffer.prototype.toString` with encoding `base64`, approximated by
|
||||
* looking for calls to `toString` where the first argument is the string `"base64"`.
|
||||
*/
|
||||
private class Buffer_toString extends Base64::Encode::Range, DataFlow::MethodCallNode {
|
||||
Buffer_toString() {
|
||||
getMethodName() = "toString" and
|
||||
getArgument(0).mayHaveStringValue("base64")
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput() { result = getReceiver() }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
/** A call to `Buffer.from` with encoding `base64`. */
|
||||
private class Buffer_from extends Base64::Decode::Range, DataFlow::CallNode {
|
||||
Buffer_from() {
|
||||
this = DataFlow::globalVarRef("Buffer").getAMemberCall("from") and
|
||||
getArgument(1).mayHaveStringValue("base64")
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a base64 encoding function from one of the npm packages
|
||||
* `base-64`, `js-base64`, `Base64`, or `base64-js`.
|
||||
*/
|
||||
private class NpmBase64Encode extends Base64::Encode::Range, DataFlow::CallNode {
|
||||
NpmBase64Encode() {
|
||||
exists(DataFlow::SourceNode enc |
|
||||
enc = DataFlow::moduleImport("b64u") or
|
||||
enc = DataFlow::moduleImport("b64url") or
|
||||
enc = DataFlow::moduleImport("btoa") or
|
||||
enc = DataFlow::moduleMember("Base64", "btoa") or
|
||||
enc = DataFlow::moduleMember("abab", "btoa") or
|
||||
enc = DataFlow::moduleMember("b2a", "btoa") or
|
||||
enc = DataFlow::moduleMember("b64-lite", "btoa") or
|
||||
enc = DataFlow::moduleMember("b64-lite", "toBase64") or
|
||||
enc = DataFlow::moduleMember("b64u", "encode") or
|
||||
enc = DataFlow::moduleMember("b64u", "toBase64") or
|
||||
enc = DataFlow::moduleMember("b64u-lite", "toBase64Url") or
|
||||
enc = DataFlow::moduleMember("b64u-lite", "toBinaryString") or
|
||||
enc = DataFlow::moduleMember("b64url", "encode") or
|
||||
enc = DataFlow::moduleMember("b64url", "toBase64") or
|
||||
enc = DataFlow::moduleMember("base-64", "encode") or
|
||||
enc = DataFlow::moduleMember("base64-js", "toByteArray") or
|
||||
enc = DataFlow::moduleMember("base64-url", "encode") or
|
||||
enc = DataFlow::moduleMember("base64url", "encode") or
|
||||
enc = DataFlow::moduleMember("base64url", "toBase64") or
|
||||
enc = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("encode") or
|
||||
enc = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("encodeURI") or
|
||||
enc = DataFlow::moduleMember("urlsafe-base64", "encode")
|
||||
|
|
||||
this = enc.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a base64 decoding function from one of the npm packages
|
||||
* `base-64`, `js-base64`, `Base64`, or `base64-js`.
|
||||
*/
|
||||
private class NpmBase64Decode extends Base64::Decode::Range, DataFlow::CallNode {
|
||||
NpmBase64Decode() {
|
||||
exists(DataFlow::SourceNode dec |
|
||||
dec = DataFlow::moduleImport("atob") or
|
||||
dec = DataFlow::moduleMember("Base64", "atob") or
|
||||
dec = DataFlow::moduleMember("abab", "atob") or
|
||||
dec = DataFlow::moduleMember("b2a", "atob") or
|
||||
dec = DataFlow::moduleMember("b64-lite", "atob") or
|
||||
dec = DataFlow::moduleMember("b64-lite", "fromBase64") or
|
||||
dec = DataFlow::moduleMember("b64u", "decode") or
|
||||
dec = DataFlow::moduleMember("b64u", "fromBase64") or
|
||||
dec = DataFlow::moduleMember("b64u-lite", "fromBase64Url") or
|
||||
dec = DataFlow::moduleMember("b64u-lite", "fromBinaryString") or
|
||||
dec = DataFlow::moduleMember("b64url", "decode") or
|
||||
dec = DataFlow::moduleMember("b64url", "fromBase64") or
|
||||
dec = DataFlow::moduleMember("base-64", "decode") or
|
||||
dec = DataFlow::moduleMember("base64-js", "fromByteArray") or
|
||||
dec = DataFlow::moduleMember("base64-url", "decode") or
|
||||
dec = DataFlow::moduleMember("base64url", "decode") or
|
||||
dec = DataFlow::moduleMember("base64url", "fromBase64") or
|
||||
dec = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("decode") or
|
||||
dec = DataFlow::moduleMember("urlsafe-base64", "decode")
|
||||
|
|
||||
this = dec.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
@@ -443,7 +443,7 @@ module TaintTracking {
|
||||
(mce.getMethodName() = "fromCharCode" or mce.getMethodName() = "fromCodePoint")
|
||||
)
|
||||
or
|
||||
// `(encode|decode)URI(Component)?` and `escape` propagate taint
|
||||
// `(encode|decode)URI(Component)?` propagate taint
|
||||
exists(DataFlow::CallNode c, string name |
|
||||
this = c and
|
||||
c = DataFlow::globalVarRef(name).getACall() and
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Provides predicates for reasoning about DOM types.
|
||||
* Provides predicates for reasoning about DOM types and methods.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
Reference in New Issue
Block a user