This commit is contained in:
Erik Krogh Kristensen 2020-01-30 14:04:04 +01:00
Родитель 7637ebcc03
Коммит 162c19c348
6 изменённых файлов: 70 добавлений и 42 удалений

Просмотреть файл

@ -17,7 +17,7 @@ abstract class LoggerCall extends DataFlow::CallNode {
/**
* Gets a log level name that is used in RFC5424, `npm`, `console`.
*/
private string getAStandardLoggerMethodName() {
string getAStandardLoggerMethodName() {
result = "crit" or
result = "debug" or
result = "error" or

Просмотреть файл

@ -16,27 +16,21 @@ module ExceptionXss {
* Gets the name of a method that does not leak taint from its arguments if an exception is thrown by the method.
*/
private string getAnUnlikelyToThrowMethodName() {
result = "getElementById" or
result = "indexOf" or
result = "stringify" or
result = "assign" or
// fs methods. (The callback argument to the async functions are vulnerable, but its unlikely that the callback is the user-controlled part).
result = "existsSync" or
result = "exists" or
result = "writeFileSync" or
result = "writeFile" or
result = "appendFile" or
result = "appendFileSync" or
result = "pick" or
// log.info etc.
result = "info" or
result = "warn" or
result = "error" or
result = "join" or
result = "getElementById" or // document.getElementById
result = "indexOf" or // String.prototype.indexOf
result = "assign" or // Object.assign
result = "pick" or // _.pick
result = getAStandardLoggerMethodName() or // log.info etc.
result = "val" or // $.val
result = "parse" or // JSON.parse
result = "push" or // Array.prototype.push
result = "test" // RegExp.prototype.test
result = "stringify" or // JSON.stringify
result = "test" or // RegExp.prototype.test
result = "setItem" or // localStorage.setItem
result = "existsSync" or
// the "fs" methods are a mix of "this is safe" and "you have bigger problems".
exists(ExternalMemberDecl decl | decl.hasQualifiedName("fs", result)) or
// Array methods are generally exception safe.
exists(ExternalMemberDecl decl | decl.hasQualifiedName("Array", result))
}
/**
@ -104,7 +98,7 @@ module ExceptionXss {
}
/**
* Get the parameter in the callback that contains an error.
* Gets the parameter in the callback that contains an error.
* In the current implementation this is always the first parameter.
*/
DataFlow::Node getErrorParam() { result = errorParameter }

Просмотреть файл

@ -51,24 +51,6 @@ module Shared {
)
}
}
/**
* A property read from a safe property is considered a sanitizer.
*/
class SafePropertyReadSanitizer extends Sanitizer, DataFlow::Node {
SafePropertyReadSanitizer() {
exists(PropAccess pacc | pacc = this.asExpr() |
isSafeLocationProperty(pacc)
or
// `$(location.hash)` is a fairly common and safe idiom
// (because `location.hash` always starts with `#`),
// so we mark `hash` as safe for the purposes of this query
pacc.getPropertyName() = "hash"
or
pacc.getPropertyName() = "length"
)
}
}
}
/** Provides classes and predicates for the DOM-based XSS query. */
@ -277,6 +259,24 @@ module DomBasedXss {
}
}
/**
* A property read from a safe property is considered a sanitizer.
*/
class SafePropertyReadSanitizer extends Sanitizer, DataFlow::Node {
SafePropertyReadSanitizer() {
exists(PropAccess pacc | pacc = this.asExpr() |
isSafeLocationProperty(pacc)
or
// `$(location.hash)` is a fairly common and safe idiom
// (because `location.hash` always starts with `#`),
// so we mark `hash` as safe for the purposes of this query
pacc.getPropertyName() = "hash"
or
pacc.getPropertyName() = "length"
)
}
}
/**
* A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
* XSS vulnerabilities.
@ -287,8 +287,6 @@ module DomBasedXss {
private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { }
private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { }
private class SafePropertyReadSanitizer extends Sanitizer, Shared::SafePropertyReadSanitizer {}
}
/** Provides classes and predicates for the reflected XSS query. */

Просмотреть файл

@ -9,6 +9,9 @@ nodes
| etherpad.js:9:16:9:53 | req.que ... e + ")" |
| etherpad.js:11:12:11:19 | response |
| etherpad.js:11:12:11:19 | response |
| exception-xss.js:190:12:190:24 | req.params.id |
| exception-xss.js:190:12:190:24 | req.params.id |
| exception-xss.js:190:12:190:24 | req.params.id |
| formatting.js:4:9:4:29 | evil |
| formatting.js:4:16:4:29 | req.query.evil |
| formatting.js:4:16:4:29 | req.query.evil |
@ -77,6 +80,7 @@ edges
| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:53 | req.que ... e + ")" |
| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:53 | req.que ... e + ")" |
| etherpad.js:9:16:9:53 | req.que ... e + ")" | etherpad.js:9:5:9:53 | response |
| exception-xss.js:190:12:190:24 | req.params.id | exception-xss.js:190:12:190:24 | req.params.id |
| formatting.js:4:9:4:29 | evil | formatting.js:6:43:6:46 | evil |
| formatting.js:4:9:4:29 | evil | formatting.js:7:49:7:52 | evil |
| formatting.js:4:16:4:29 | req.query.evil | formatting.js:4:9:4:29 | evil |
@ -131,6 +135,7 @@ edges
#select
| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value |
| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value |
| exception-xss.js:190:12:190:24 | req.params.id | exception-xss.js:190:12:190:24 | req.params.id | exception-xss.js:190:12:190:24 | req.params.id | Cross-site scripting vulnerability due to $@. | exception-xss.js:190:12:190:24 | req.params.id | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| partial.js:10:14:10:18 | x + y | partial.js:13:42:13:48 | req.url | partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |

Просмотреть файл

@ -1,4 +1,5 @@
| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value |
| exception-xss.js:190:12:190:24 | req.params.id | Cross-site scripting vulnerability due to $@. | exception-xss.js:190:12:190:24 | req.params.id | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |

Просмотреть файл

@ -183,4 +183,34 @@ app.get('/user/:id', function (req, res) {
}
$('myId').html(res); // NOT OK!
});
});
});
app.get('/user/:id', function (req, res) {
try {
res.send(req.params.id);
} catch(err) {
res.send(err); // OK (the above `res.send()` is already reported by js/xss)
}
});
var fs = require("fs");
(function () {
var foo = document.location.search;
try {
// A series of functions does not throw tainted exceptions.
Object.assign(foo, foo)
_.pick(foo, foo);
[foo, foo].join(join);
$.val(foo);
JSON.parse(foo);
/bla/.test(foo);
console.log(foo);
log.info(foo);
localStorage.setItem(foo);
} catch (e) {
$('myId').html(e); // OK
}
})();