Skip to content

Commit 5b1d255

Browse files
authored
Merge pull request github#3979 from max-schaefer/js/more-comand-injection-models
Approved by asgerf
2 parents 437baf1 + 91762ec commit 5b1d255

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
77
- [bluebird](http://bluebirdjs.com/)
88
- [express](https://www.npmjs.com/package/express)
9+
- [execa](https://www.npmjs.com/package/execa)
910
- [fancy-log](https://www.npmjs.com/package/fancy-log)
1011
- [fastify](https://www.npmjs.com/package/fastify)
12+
- [foreground-child](https://www.npmjs.com/package/foreground-child)
1113
- [fstream](https://www.npmjs.com/package/fstream)
1214
- [jGrowl](https://github.com/stanlemon/jGrowl)
1315
- [jQuery](https://jquery.com/)
@@ -17,6 +19,7 @@
1719
- [mssql](https://www.npmjs.com/package/mssql)
1820
- [mysql](https://www.npmjs.com/package/mysql)
1921
- [npmlog](https://www.npmjs.com/package/npmlog)
22+
- [opener](https://www.npmjs.com/package/opener)
2023
- [pg](https://www.npmjs.com/package/pg)
2124
- [sequelize](https://www.npmjs.com/package/sequelize)
2225
- [spanner](https://www.npmjs.com/package/spanner)

javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::I
3232
(method = "command" or method = "commandSync")
3333
) and
3434
cmdArg = 0
35+
or
36+
mod = "execa" and
37+
method = "node" and
38+
cmdArg = 0 and
39+
optionsArg = 1 and
40+
shell = false
3541
|
3642
callee = DataFlow::moduleMember(mod, method) and
3743
sync = getSync(method)
@@ -59,6 +65,12 @@ private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::I
5965
|
6066
this = callee.getACall()
6167
)
68+
or
69+
this = DataFlow::moduleImport("foreground-child").getACall() and
70+
cmdArg = 0 and
71+
optionsArg = 1 and
72+
shell = false and
73+
sync = true
6274
}
6375

6476
override DataFlow::Node getACommandArgument() { result = getArgument(cmdArg) }
@@ -123,3 +135,15 @@ private class RemoteCommandExecutor extends SystemCommandExecution, DataFlow::In
123135

124136
override DataFlow::Node getOptionsArg() { none() }
125137
}
138+
139+
private class Opener extends SystemCommandExecution, DataFlow::InvokeNode {
140+
Opener() { this = DataFlow::moduleImport("opener").getACall() }
141+
142+
override DataFlow::Node getACommandArgument() { result = getOptionArgument(1, "command") }
143+
144+
override predicate isShellInterpreted(DataFlow::Node arg) { none() }
145+
146+
override predicate isSync() { none() }
147+
148+
override DataFlow::Node getOptionsArg() { none() }
149+
}

javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ nodes
109109
| other.js:23:28:23:30 | cmd |
110110
| other.js:26:34:26:36 | cmd |
111111
| other.js:26:34:26:36 | cmd |
112+
| other.js:28:27:28:29 | cmd |
113+
| other.js:28:27:28:29 | cmd |
114+
| other.js:30:33:30:35 | cmd |
115+
| other.js:30:33:30:35 | cmd |
116+
| other.js:34:44:34:46 | cmd |
117+
| other.js:34:44:34:46 | cmd |
112118
| third-party-command-injection.js:5:20:5:26 | command |
113119
| third-party-command-injection.js:5:20:5:26 | command |
114120
| third-party-command-injection.js:6:21:6:27 | command |
@@ -213,6 +219,12 @@ edges
213219
| other.js:5:9:5:49 | cmd | other.js:23:28:23:30 | cmd |
214220
| other.js:5:9:5:49 | cmd | other.js:26:34:26:36 | cmd |
215221
| other.js:5:9:5:49 | cmd | other.js:26:34:26:36 | cmd |
222+
| other.js:5:9:5:49 | cmd | other.js:28:27:28:29 | cmd |
223+
| other.js:5:9:5:49 | cmd | other.js:28:27:28:29 | cmd |
224+
| other.js:5:9:5:49 | cmd | other.js:30:33:30:35 | cmd |
225+
| other.js:5:9:5:49 | cmd | other.js:30:33:30:35 | cmd |
226+
| other.js:5:9:5:49 | cmd | other.js:34:44:34:46 | cmd |
227+
| other.js:5:9:5:49 | cmd | other.js:34:44:34:46 | cmd |
216228
| other.js:5:15:5:38 | url.par ... , true) | other.js:5:15:5:44 | url.par ... ).query |
217229
| other.js:5:15:5:44 | url.par ... ).query | other.js:5:15:5:49 | url.par ... ry.path |
218230
| other.js:5:15:5:49 | url.par ... ry.path | other.js:5:9:5:49 | cmd |
@@ -261,4 +273,7 @@ edges
261273
| other.js:22:21:22:23 | cmd | other.js:5:25:5:31 | req.url | other.js:22:21:22:23 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
262274
| other.js:23:28:23:30 | cmd | other.js:5:25:5:31 | req.url | other.js:23:28:23:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
263275
| other.js:26:34:26:36 | cmd | other.js:5:25:5:31 | req.url | other.js:26:34:26:36 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
276+
| other.js:28:27:28:29 | cmd | other.js:5:25:5:31 | req.url | other.js:28:27:28:29 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
277+
| other.js:30:33:30:35 | cmd | other.js:5:25:5:31 | req.url | other.js:30:33:30:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
278+
| other.js:34:44:34:46 | cmd | other.js:5:25:5:31 | req.url | other.js:34:44:34:46 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
264279
| third-party-command-injection.js:6:21:6:27 | command | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | This command depends on $@. | third-party-command-injection.js:5:20:5:26 | command | a server-provided value |

javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ syncCommand
5656
| other.js:7:5:7:36 | require ... nc(cmd) |
5757
| other.js:9:5:9:35 | require ... nc(cmd) |
5858
| other.js:12:5:12:30 | require ... nc(cmd) |
59+
| other.js:30:5:30:36 | require ... ")(cmd) |
5960
| third-party-command-injection.js:6:9:6:28 | cp.execSync(command) |
6061
| tst_shell-command-injection-from-environment.js:4:2:4:62 | cp.exec ... emp")]) |
6162
| tst_shell-command-injection-from-environment.js:5:2:5:54 | cp.exec ... temp")) |

javascript/ql/test/query-tests/Security/CWE-078/other.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var http = require("http"),
22
url = require("url");
33

4-
var server = http.createServer(function(req, res) {
4+
var server = http.createServer(function (req, res) {
55
let cmd = url.parse(req.url, true).query.path;
66

77
require("cross-spawn").sync(cmd); // NOT OK
@@ -24,4 +24,12 @@ var server = http.createServer(function(req, res) {
2424

2525
const SSH2Stream = require("ssh2-streams").SSH2Stream;
2626
new SSH2Stream().exec(false, cmd); // NOT OK
27+
28+
require("execa").node(cmd); // NOT OK
29+
30+
require("foreground-child")(cmd); // NOT OK
31+
32+
const opener = require("opener");
33+
opener("http://github.com/" + url.parse(req.url, true).query.user); // OK
34+
opener("http://github.com", { command: cmd }); // NOT OK
2735
});

0 commit comments

Comments
 (0)