Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5b49131

Browse files
committed
add simple query for detecting sensitive files downloaded over unsecure connection
1 parent df79f2a commit 5b49131

6 files changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Placeholder
8+
</p>
9+
10+
</overview>
11+
<recommendation>
12+
13+
<p>
14+
Placeholder
15+
</p>
16+
17+
</recommendation>
18+
<example>
19+
20+
<p>
21+
Placeholder
22+
</p>
23+
24+
</example>
25+
26+
<references>
27+
</references>
28+
29+
</qhelp>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @name Download of sensitive file through unsecure connection
3+
* @description Downloading executeables and other sensitive files over an unsecure connection
4+
* opens up for potential man-in-the-middle attacks.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @precision high
8+
* @id js/unsecure-download
9+
* @tags security
10+
* external/cwe/cwe-829
11+
*/
12+
13+
// TODO:
14+
// package.json urls (ALL package.json urls are sensitive.) - put in separate non-path query?
15+
// Other protocols?
16+
// Customizations module
17+
// An integrity-check is a sanitizer (but what does such a check look like?)
18+
import javascript
19+
import DataFlow::PathGraph
20+
21+
class Configuration extends DataFlow::Configuration {
22+
Configuration() { this = "HTTP/HTTPS" }
23+
24+
override predicate isSource(DataFlow::Node source) {
25+
exists(string str | str = source.getStringValue() |
26+
str.regexpMatch("http://.*|ftp://.'") and
27+
exists(string suffix | suffix = unsafeSuffix() |
28+
str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix
29+
)
30+
)
31+
}
32+
33+
override predicate isSink(DataFlow::Node sink) {
34+
exists(ClientRequest request | sink = request.getUrl())
35+
or
36+
exists(SystemCommandExecution cmd |
37+
cmd.getACommandArgument().getStringValue() = "curl" or
38+
cmd
39+
.getACommandArgument()
40+
.(StringOps::ConcatenationRoot)
41+
.getConstantStringParts()
42+
.regexpMatch("curl .*")
43+
|
44+
sink = cmd.getArgumentList().getALocalSource().getAPropertyWrite().getRhs() or
45+
sink = cmd.getACommandArgument().(StringOps::ConcatenationRoot).getALeaf()
46+
)
47+
}
48+
}
49+
50+
/**
51+
* Gets a file-suffix
52+
*/
53+
string unsafeSuffix() {
54+
// including arcives, because they often contain source-code.
55+
result =
56+
["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", "tar.gz",
57+
"zip"]
58+
}
59+
60+
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
61+
where cfg.hasFlowPath(source, sink)
62+
select sink.getNode(), source, sink, "Download of file from $@.", source.getNode(), "HTTP source"

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,4 +620,17 @@ module ClientRequest {
620620

621621
override DataFlow::Node getADataNode() { none() }
622622
}
623+
624+
/**
625+
* A call to `nugget` that downloads one of more files to a destination determined by an options object given as the second argument.
626+
*/
627+
class Nugget extends ClientRequest::Range, DataFlow::CallNode {
628+
Nugget() { this = DataFlow::moduleImport("nugget").getACall() }
629+
630+
override DataFlow::Node getUrl() { result = getArgument(0) }
631+
632+
override DataFlow::Node getHost() { none() }
633+
634+
override DataFlow::Node getADataNode() { none() }
635+
}
623636
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
nodes
2+
| unsecure-download.js:5:16:5:28 | installer.url |
3+
| unsecure-download.js:5:16:5:28 | installer.url |
4+
| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' |
5+
| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' |
6+
| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl |
7+
| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
8+
| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
9+
| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
10+
| unsecure-download.js:36:9:36:45 | url |
11+
| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" |
12+
| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" |
13+
| unsecure-download.js:37:23:37:25 | url |
14+
| unsecure-download.js:37:23:37:25 | url |
15+
| unsecure-download.js:39:26:39:28 | url |
16+
| unsecure-download.js:39:26:39:28 | url |
17+
edges
18+
| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl |
19+
| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl |
20+
| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url |
21+
| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url |
22+
| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
23+
| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url |
24+
| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url |
25+
| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url |
26+
| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url |
27+
| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url |
28+
| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url |
29+
#select
30+
| unsecure-download.js:5:16:5:28 | installer.url | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:5:16:5:28 | installer.url | Download of file from $@. | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source |
31+
| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | Download of file from $@. | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source |
32+
| unsecure-download.js:37:23:37:25 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:37:23:37:25 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source |
33+
| unsecure-download.js:39:26:39:28 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:39:26:39:28 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE-829/UnsecureDownload.ql
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const nugget = require('nugget');
2+
3+
function foo() {
4+
function downloadTools(installer) {
5+
nugget(installer.url, {}, () => { }) // NOT OK
6+
}
7+
var constants = {
8+
buildTools: {
9+
installerUrl: 'http://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe'
10+
}
11+
}
12+
function getBuildToolsInstallerPath() {
13+
const buildTools = constants.buildTools
14+
return {
15+
url: buildTools.installerUrl
16+
}
17+
}
18+
19+
downloadTools(getBuildToolsInstallerPath())
20+
}
21+
22+
23+
const request = require('request');
24+
25+
function bar() {
26+
request('http://www.google.com', function () { }); // OK
27+
28+
nugget("https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe") // OK
29+
30+
nugget("http://example.org/unsafe.APK") // NOT OK
31+
}
32+
33+
var cp = require("child_process")
34+
35+
function baz() {
36+
var url = "http://example.org/unsafe.APK";
37+
cp.exec("curl " + url, function () {}); // NOT OK
38+
39+
cp.execFile("curl", [url], function () {}); // NOT OK
40+
}

0 commit comments

Comments
 (0)