Add query for detecting potential DOS form a tainted .length property

This commit is contained in:
Erik Krogh Kristensen
2019-09-10 14:02:05 +01:00
parent df1bf4a95b
commit 97fc10e669
17 changed files with 885 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
nodes
| TaintedLengthBad.js:8:10:8:17 | req.body |
| TaintedLengthBad.js:10:12:10:19 | req.body |
| TaintedLengthBad.js:12:22:12:29 | req.body |
| TaintedLengthBad.js:14:16:14:23 | req.body |
| TaintedLengthBad.js:17:18:17:20 | val |
| TaintedLengthBad.js:21:22:21:24 | val |
| TaintedLengthBad.js:26:20:26:22 | val |
| TaintedLengthBad.js:30:13:30:15 | val |
| TaintedLengthBad.js:37:30:37:32 | val |
| TaintedLengthBad.js:40:12:40:14 | val |
| TaintedLengthBad.js:49:24:49:26 | val |
| TaintedLengthBad.js:54:22:54:24 | val |
| TaintedLengthExitBad.js:8:9:8:16 | req.body |
| TaintedLengthExitBad.js:10:9:10:16 | req.body |
| TaintedLengthExitBad.js:12:10:12:17 | req.body |
| TaintedLengthExitBad.js:14:14:14:21 | req.body |
| TaintedLengthExitBad.js:17:17:17:19 | val |
| TaintedLengthExitBad.js:20:22:20:24 | val |
| TaintedLengthExitBad.js:30:17:30:19 | val |
| TaintedLengthExitBad.js:33:22:33:24 | val |
| TaintedLengthExitBad.js:46:18:46:20 | val |
| TaintedLengthExitBad.js:49:22:49:24 | val |
| TaintedLengthExitBad.js:59:22:59:24 | val |
| TaintedLengthExitBad.js:60:8:60:10 | val |
| TaintedLengthLodash.js:9:10:9:17 | req.body |
| TaintedLengthLodash.js:14:18:14:20 | val |
| TaintedLengthLodash.js:15:10:15:12 | val |
edges
| TaintedLengthBad.js:8:10:8:17 | req.body | TaintedLengthBad.js:17:18:17:20 | val |
| TaintedLengthBad.js:10:12:10:19 | req.body | TaintedLengthBad.js:26:20:26:22 | val |
| TaintedLengthBad.js:12:22:12:29 | req.body | TaintedLengthBad.js:37:30:37:32 | val |
| TaintedLengthBad.js:14:16:14:23 | req.body | TaintedLengthBad.js:49:24:49:26 | val |
| TaintedLengthBad.js:17:18:17:20 | val | TaintedLengthBad.js:21:22:21:24 | val |
| TaintedLengthBad.js:26:20:26:22 | val | TaintedLengthBad.js:30:13:30:15 | val |
| TaintedLengthBad.js:37:30:37:32 | val | TaintedLengthBad.js:40:12:40:14 | val |
| TaintedLengthBad.js:49:24:49:26 | val | TaintedLengthBad.js:54:22:54:24 | val |
| TaintedLengthExitBad.js:8:9:8:16 | req.body | TaintedLengthExitBad.js:17:17:17:19 | val |
| TaintedLengthExitBad.js:10:9:10:16 | req.body | TaintedLengthExitBad.js:30:17:30:19 | val |
| TaintedLengthExitBad.js:12:10:12:17 | req.body | TaintedLengthExitBad.js:46:18:46:20 | val |
| TaintedLengthExitBad.js:14:14:14:21 | req.body | TaintedLengthExitBad.js:59:22:59:24 | val |
| TaintedLengthExitBad.js:17:17:17:19 | val | TaintedLengthExitBad.js:20:22:20:24 | val |
| TaintedLengthExitBad.js:30:17:30:19 | val | TaintedLengthExitBad.js:33:22:33:24 | val |
| TaintedLengthExitBad.js:46:18:46:20 | val | TaintedLengthExitBad.js:49:22:49:24 | val |
| TaintedLengthExitBad.js:59:22:59:24 | val | TaintedLengthExitBad.js:60:8:60:10 | val |
| TaintedLengthLodash.js:9:10:9:17 | req.body | TaintedLengthLodash.js:14:18:14:20 | val |
| TaintedLengthLodash.js:14:18:14:20 | val | TaintedLengthLodash.js:15:10:15:12 | val |
#select
| TaintedLengthBad.js:21:22:21:24 | val | TaintedLengthBad.js:8:10:8:17 | req.body | TaintedLengthBad.js:21:22:21:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:8:10:8:17 | req.body | here |
| TaintedLengthBad.js:30:13:30:15 | val | TaintedLengthBad.js:10:12:10:19 | req.body | TaintedLengthBad.js:30:13:30:15 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:10:12:10:19 | req.body | here |
| TaintedLengthBad.js:40:12:40:14 | val | TaintedLengthBad.js:12:22:12:29 | req.body | TaintedLengthBad.js:40:12:40:14 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:12:22:12:29 | req.body | here |
| TaintedLengthBad.js:54:22:54:24 | val | TaintedLengthBad.js:14:16:14:23 | req.body | TaintedLengthBad.js:54:22:54:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:14:16:14:23 | req.body | here |
| TaintedLengthExitBad.js:20:22:20:24 | val | TaintedLengthExitBad.js:8:9:8:16 | req.body | TaintedLengthExitBad.js:20:22:20:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:8:9:8:16 | req.body | here |
| TaintedLengthExitBad.js:33:22:33:24 | val | TaintedLengthExitBad.js:10:9:10:16 | req.body | TaintedLengthExitBad.js:33:22:33:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:10:9:10:16 | req.body | here |
| TaintedLengthExitBad.js:49:22:49:24 | val | TaintedLengthExitBad.js:12:10:12:17 | req.body | TaintedLengthExitBad.js:49:22:49:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:12:10:12:17 | req.body | here |
| TaintedLengthExitBad.js:60:8:60:10 | val | TaintedLengthExitBad.js:14:14:14:21 | req.body | TaintedLengthExitBad.js:60:8:60:10 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:14:14:14:21 | req.body | here |
| TaintedLengthLodash.js:15:10:15:12 | val | TaintedLengthLodash.js:9:10:9:17 | req.body | TaintedLengthLodash.js:15:10:15:12 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthLodash.js:9:10:9:17 | req.body | here |

View File

@@ -0,0 +1 @@
Security/CWE-834/TaintedLength.ql

View File

@@ -0,0 +1,59 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
rootRoute.post(function(req, res) {
problem(req.body);
whileLoop(req.body);
useLengthIndirectly(req.body);
noNullPointer(req.body);
});
function problem(val) {
var ret = [];
// Potential DOS! .length property could have been set to an arbitrary
// value!
for (var i = 0; i < val.length; i++) {
ret.push(val[i]);
}
}
function whileLoop(val) {
var ret = [];
var i = 0;
// Potential DOS! .length property could have been set to an arbitrary
// value!
while (i < val.length) {
ret.push(val[i]);
i++;
}
}
function useLengthIndirectly(val) {
var ret = [];
var len = val.length;
// Same as above, but the .length access happens outside the loop.
for (var i = 0; i < len; i++) {
ret.push(val[i]);
}
}
// the obvious null-pointer detection should not hit this one.
function noNullPointer(val) {
var ret = [];
const c = 0;
for (var i = 0; i < val.length; i++) {
ret.push(val[c].foo); // constantly accessing element 0, therefore not
// guaranteed null-pointer.
}
}

View File

@@ -0,0 +1,70 @@
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
var _ = require("lodash");
rootRoute.post(function (req, res) {
breaks(req.body);
throws(req.body);
returns(req.body);
lodashThrow(req.body);
});
function breaks(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
for (var k = 0; k < 2; k++) {
if (k == 3) {
// Does not prevent DOS, because this is inside an inner loop.
break;
}
}
ret.push(val[i]);
}
}
function throws(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
if (val[i] == null) {
try {
throw 2; // Is catched, and therefore the DOS is not prevented.
} catch(e) {
// ignored
}
}
ret.push(val[i]);
}
}
// the obvious null-pointer detection should not hit this one.
function returns(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
if (val[i] == null) {
(function (i) {
return i+2; // Does not prevent DOS.
})(i);
}
ret.push(val[i]);
}
}
function lodashThrow(val) {
_.map(val, function (e) {
if (!e) {
try {
throw new Error(); // Does not prevent DOS
} catch(e) {
// ignored.
}
}
})
}

View File

@@ -0,0 +1,57 @@
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
var _ = require("lodash");
rootRoute.post(function (req, res) {
breaks(req.body);
throws(req.body);
returns(req.body);
lodashThrow(req.body);
});
function breaks(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
if (val[i] == null) {
break; // prevents DOS.
}
ret.push(val[i]);
}
}
function throws(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
if (val[i] == null) {
throw 2; // prevents DOS.
}
ret.push(val[i]);
}
}
// the obvious null-pointer detection should not hit this one.
function returns(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
if (val[i] == null) {
return 2; // prevents DOS.
}
ret.push(val[i]);
}
}
function lodashThrow(val) {
_.map(val, function (e) {
if (!e) {
throw new Error(); // prevents DOS.
}
})
}

View File

@@ -0,0 +1,73 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
rootRoute.post(function(req, res) {
sanitized(req.body);
sanitized2(req.body);
sanitized3(req.body);
sanitized4(req.body);
});
function sanitized(val) {
var ret = [];
if (!Array.isArray(val)) {
return [];
}
// At this point we know that val must be an Array, and an attacked is
// therefore not able to send a cheap request that spends a lot of time
// inside the loop.
for (var i = 0; i < val.length; i++) {
ret.push(val[i] + 42);
}
}
function sanitized2(val) {
var ret = [];
if (typeof val === "object") {
return [];
}
// Val can only be a primitive. Therefore no issue!
for (var i = 0; i < val.length; i++) {
ret.push(val[i] + 42);
}
}
function isArray(foo) {
return foo instanceof Array;
}
function sanitized3(val) {
var ret = [];
if (!isArray(val)) {
return [];
}
// At this point we know that val must be an Array, and an attacked is
// therefore not able to send a cheap request that spends a lot of time
// inside the loop.
for (var i = 0; i < val.length; i++) {
ret.push(val[i] + 42);
}
}
function sanitized4(val) {
var ret = [];
if (!(val instanceof Array)) {
return [];
}
// At this point we know that val must be an Array, and an attacked is
// therefore not able to send a cheap request that spends a lot of time
// inside the loop.
for (var i = 0; i < val.length; i++) {
ret.push(val[i] + 42);
}
}

View File

@@ -0,0 +1,17 @@
'use strict';
var _ = require('lodash');
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
rootRoute.post(function(req, res) {
problem(req.body);
useLengthIndirectly(req.body);
});
function problem(val) {
// can take an arbitrary amount of time with a tainted .length property
_.chunk(val, 2);
}

View File

@@ -0,0 +1,13 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
var global;
rootRoute.post(function(req, res) {
for (i = 0; i < req.body.personas.length; i++) {
req.body.personas[i].parentesco.id;
}
});

View File

@@ -0,0 +1,22 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
rootRoute.post(function(req, res) {
problem(req.body);
});
function problem(val) {
var ret = [];
// Prevents DOS
if (val.length > 100) {
return [];
}
for (var i = 0; i < val.length; i++) {
ret.push(val[i]);
}
}

View File

@@ -0,0 +1,58 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
var _ = require("lodash");
rootRoute.post(function(req, res) {
nullPointer(req.body);
nullPointer2(req.body);
nullPointer3(req.body);
lodashPointer(req.body);
lodashArrowFunc(req.body);
});
function nullPointer(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
ret.push(val[i].foo + 42);
}
}
function nullPointer2(val) {
var ret = [];
for (var i = 0; i < val.length; i++) {
var element = val[i];
ret.push(element.foo + 42);
}
}
function nullPointer3(val) {
let arr = val.messaging
for (let i = 0; i < arr.length; i++) {
let event = val.messaging[i]
let sender = event.sender.id
}
}
function lodashPointer(val) {
return _.map(val, function(e) {
return e.foo;
})
}
function lodashArrowFunc(val) {
return _.map(val, (e) => {
return e.foo;
});
}

View File

@@ -0,0 +1,24 @@
'use strict';
var express = require('express');
var router = new express.Router();
var rootRoute = router.route('foobar');
var _ = require("lodash");
rootRoute.post(function(req, res) {
nullPointer(req.body);
});
function nullPointer(val) {
var ret = [];
// Has obvious null-pointer. And guards the next loop.
for (var i = 0; i < val.length; i++) {
ret.push(val[i].foo);
}
for (var i = 0; i < val.length; i++) {
ret.push(val[i]);
}
}