Skip to content

Commit bd1e708

Browse files
committed
C++: First version of cpp/non-https-url.
1 parent 618d135 commit bd1e708

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @name Failure to use HTTPS URLs
3+
* @description Non-HTTPS connections can be intercepted by third parties.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @precision medium
7+
* @id cpp/non-https-url
8+
* @tags security
9+
* external/cwe/cwe-319
10+
*/
11+
12+
import cpp
13+
import semmle.code.cpp.dataflow.TaintTracking
14+
import DataFlow::PathGraph
15+
16+
/**
17+
* A string matching private host names of IPv4 and IPv6, which only matches
18+
* the host portion therefore checking for port is not necessary.
19+
* Several examples are localhost, reserved IPv4 IP addresses including
20+
* 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses
21+
* including [0:0:0:0:0:0:0:1] and [::1]
22+
*/
23+
class PrivateHostName extends string {
24+
bindingset[this]
25+
PrivateHostName() {
26+
this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?")
27+
}
28+
}
29+
30+
/**
31+
* A string containing an HTTP URL not in a private domain.
32+
*/
33+
class HttpStringLiteral extends StringLiteral {
34+
HttpStringLiteral() {
35+
exists(string s | this.getValue() = s |
36+
s = "http"
37+
or
38+
s.matches("http://%") and
39+
not s.substring(7, s.length()) instanceof PrivateHostName and
40+
not TaintTracking::localExprTaint(any(StringLiteral p |
41+
p.getValue() instanceof PrivateHostName
42+
), this.getParent*())
43+
)
44+
}
45+
}
46+
47+
/**
48+
* Taint tracking configuration for HTTP connections.
49+
*/
50+
class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
51+
HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" }
52+
53+
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpStringLiteral }
54+
55+
override predicate isSink(DataFlow::Node sink) {
56+
exists(FunctionCall fc |
57+
fc.getTarget().getName() = ["system", "gethostbyname"] and
58+
sink.asExpr() = fc.getArgument(0)
59+
or
60+
fc.getTarget().getName() = ["send", "URLDownloadToFile"] and
61+
sink.asExpr() = fc.getArgument(1)
62+
or
63+
fc.getTarget().getName() = "ShellExecute" and
64+
sink.asExpr() = fc.getArgument(3)
65+
)
66+
}
67+
}
68+
69+
from
70+
HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
71+
HttpStringLiteral str
72+
where
73+
config.hasFlowPath(source, sink) and
74+
str = source.getNode().asExpr()
75+
select str, source, sink, "A URL may be constructed with the HTTP protocol."

0 commit comments

Comments
 (0)