Skip to content

Commit fdd4f7f

Browse files
committed
attempt to use typetracker in rb/hardcoded-credentials
1 parent c530ba5 commit fdd4f7f

3 files changed

Lines changed: 115 additions & 30 deletions

File tree

ql/src/queries/security/cwe-798/HardcodedCredentials.ql

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
import ruby
1616
import codeql_ruby.DataFlow
1717
import DataFlow::PathGraph
18-
private import codeql_ruby.dataflow.SSA
19-
private import codeql_ruby.CFG
18+
private import codeql_ruby.typetracking.TypeTracker
19+
private import codeql_ruby.controlflow.CfgNodes
2020

2121
bindingset[char, fraction]
2222
predicate fewer_characters_than(StringLiteral str, string char, float fraction) {
@@ -82,32 +82,47 @@ private string getACredentialRegex() {
8282
result = "(?i).*(cert)(?!.*(format|name)).*"
8383
}
8484

85-
private predicate isCredentialSink(Expr e) {
86-
exists(string name |
87-
name.regexpMatch(getACredentialRegex()) and
88-
not name.suffix(name.length() - 4) = "file"
89-
|
90-
// A method call with a parameter that may hold a credential
91-
exists(Method m, NamedParameter p, int idx, MethodCall mc |
92-
// Include keyword argument values etc.
93-
mc.getArgument(idx).getAChild*() = e and
94-
p = m.getParameter(idx) and
95-
p.getName() = name and
96-
// TODO: link call w/ method more precisely
97-
mc.getMethodName() = m.getName()
98-
)
85+
bindingset[name]
86+
private predicate maybeCredentialName(string name) {
87+
name.regexpMatch(getACredentialRegex()) and
88+
not name.suffix(name.length() - 4) = "file"
89+
}
90+
91+
private DataFlow::LocalSourceNode credentialParameter(TypeTracker t) {
92+
t.start() and
93+
exists(Method m, NamedParameter p, int idx |
94+
// TODO: this does not capture keyword params
95+
result.asParameter() = p and
96+
p = m.getParameter(idx) and
97+
maybeCredentialName(p.getName())
98+
)
99+
or
100+
exists(TypeTracker t2 | result = credentialParameter(t2).track(t2, t))
101+
}
102+
103+
private DataFlow::Node credentialParameter() {
104+
credentialParameter(TypeTracker::end()).flowsTo(result)
105+
}
106+
107+
// An equality check against a credential value
108+
private Expr credentialComparison() {
109+
exists(EqualityOperation op, VariableReadAccess vra |
110+
maybeCredentialName(vra.getVariable().getName()) and
111+
op.getLeftOperand() = result and
112+
op.getRightOperand() = vra
99113
or
100-
// An equality check against a credential value
101-
exists(EqualityOperation op, VariableReadAccess vra | vra.getVariable().getName() = name |
102-
op.getLeftOperand() = e and op.getRightOperand() = vra
103-
or
104-
op.getLeftOperand() = vra and op.getRightOperand() = e
105-
)
114+
op.getLeftOperand() = vra and op.getRightOperand() = result
106115
)
107116
}
108117

118+
private predicate isCredentialSink(DataFlow::Node node) {
119+
node = credentialParameter()
120+
or
121+
node.asExpr().getExpr() = credentialComparison()
122+
}
123+
109124
class CredentialSink extends DataFlow::Node {
110-
CredentialSink() { isCredentialSink(this.asExpr().getExpr()) }
125+
CredentialSink() { isCredentialSink(this) }
111126
}
112127

113128
class HardcodedCredentialsConfiguration extends DataFlow::Configuration {
@@ -116,8 +131,20 @@ class HardcodedCredentialsConfiguration extends DataFlow::Configuration {
116131
override predicate isSource(DataFlow::Node source) { source instanceof HardcodedValueSource }
117132

118133
override predicate isSink(DataFlow::Node sink) { sink instanceof CredentialSink }
134+
135+
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
136+
// e.g. string concatenation
137+
exists(ExprNodes::BinaryOperationCfgNode binop |
138+
(
139+
binop.getLeftOperand() = node1.asExpr() or
140+
binop.getRightOperand() = node1.asExpr()
141+
) and
142+
binop = node2.asExpr()
143+
)
144+
}
119145
}
120146

121147
from DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedCredentialsConfiguration conf
122148
where conf.hasFlowPath(source, sink)
123149
select sink.getNode(), source, sink, "Use of $@.", source.getNode(), "hardcoded credentials"
150+
// TODO: debug duplicate rows
Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
edges
2+
| HardcodedCredentials.rb:1:23:1:30 | password : | HardcodedCredentials.rb:1:23:1:30 | password |
3+
| HardcodedCredentials.rb:1:23:1:30 | password : | HardcodedCredentials.rb:8:18:8:25 | password |
4+
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password |
5+
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password : |
6+
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | HardcodedCredentials.rb:1:23:1:30 | password |
7+
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | HardcodedCredentials.rb:1:23:1:30 | password : |
8+
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:18:19:18:72 | ... + ... : |
9+
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:23:19:23:20 | pw : |
10+
| HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:23:19:23:20 | pw : |
11+
| HardcodedCredentials.rb:23:19:23:20 | pw : | HardcodedCredentials.rb:1:23:1:30 | password |
12+
| HardcodedCredentials.rb:23:19:23:20 | pw : | HardcodedCredentials.rb:1:23:1:30 | password : |
13+
| HardcodedCredentials.rb:31:18:31:23 | passwd : | HardcodedCredentials.rb:31:18:31:23 | passwd |
14+
| HardcodedCredentials.rb:31:18:31:23 | passwd : | HardcodedCredentials.rb:32:7:32:12 | passwd |
15+
| HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | HardcodedCredentials.rb:31:18:31:23 | passwd |
16+
| HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | HardcodedCredentials.rb:31:18:31:23 | passwd : |
217
nodes
18+
| HardcodedCredentials.rb:1:23:1:30 | password | semmle.label | password |
19+
| HardcodedCredentials.rb:1:23:1:30 | password | semmle.label | password |
20+
| HardcodedCredentials.rb:1:23:1:30 | password : | semmle.label | password : |
321
| HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | semmle.label | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." |
22+
| HardcodedCredentials.rb:8:18:8:25 | password | semmle.label | password |
423
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | semmle.label | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." |
5-
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | semmle.label | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." |
6-
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | semmle.label | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." |
7-
| HardcodedCredentials.rb:18:27:18:72 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | semmle.label | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." |
24+
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | semmle.label | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : |
25+
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | semmle.label | ... + ... : |
26+
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | semmle.label | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : |
27+
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | semmle.label | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : |
28+
| HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | semmle.label | "4fQuzXef4f2yow8KWvIJTA==" : |
29+
| HardcodedCredentials.rb:23:19:23:20 | pw : | semmle.label | pw : |
30+
| HardcodedCredentials.rb:31:18:31:23 | passwd | semmle.label | passwd |
31+
| HardcodedCredentials.rb:31:18:31:23 | passwd | semmle.label | passwd |
32+
| HardcodedCredentials.rb:31:18:31:23 | passwd : | semmle.label | passwd : |
33+
| HardcodedCredentials.rb:32:7:32:12 | passwd | semmle.label | passwd |
34+
| HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | semmle.label | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : |
835
#select
36+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
37+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
38+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | hardcoded credentials |
39+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | hardcoded credentials |
40+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | hardcoded credentials |
41+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | hardcoded credentials |
42+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | hardcoded credentials |
43+
| HardcodedCredentials.rb:1:23:1:30 | password | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | hardcoded credentials |
944
| HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | Use of $@. | HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | hardcoded credentials |
45+
| HardcodedCredentials.rb:8:18:8:25 | password | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:8:18:8:25 | password | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
46+
| HardcodedCredentials.rb:8:18:8:25 | password | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:8:18:8:25 | password | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | hardcoded credentials |
47+
| HardcodedCredentials.rb:8:18:8:25 | password | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:8:18:8:25 | password | Use of $@. | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | hardcoded credentials |
48+
| HardcodedCredentials.rb:8:18:8:25 | password | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:8:18:8:25 | password | Use of $@. | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | hardcoded credentials |
1049
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | Use of $@. | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | hardcoded credentials |
11-
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
12-
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | Use of $@. | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | hardcoded credentials |
13-
| HardcodedCredentials.rb:18:27:18:72 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:18:27:18:72 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:18:27:18:72 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
50+
| HardcodedCredentials.rb:31:18:31:23 | passwd | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | HardcodedCredentials.rb:31:18:31:23 | passwd | Use of $@. | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." | hardcoded credentials |
51+
| HardcodedCredentials.rb:31:18:31:23 | passwd | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | HardcodedCredentials.rb:31:18:31:23 | passwd | Use of $@. | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." | hardcoded credentials |
52+
| HardcodedCredentials.rb:32:7:32:12 | passwd | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." : | HardcodedCredentials.rb:32:7:32:12 | passwd | Use of $@. | HardcodedCredentials.rb:38:40:38:85 | "kdW/xVhiv6y1fQQNevDpUaq+2rfPK..." | hardcoded credentials |

ql/test/query-tests/security/cwe-798/HardcodedCredentials.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,27 @@ def authenticate(uid, password, cert: nil)
1515
authenticate(456, nil, cert: "WLC17dLQ9P8YlQvqm77qplOMm5pd1q25Q2onWqu78JI=")
1616

1717
# concatenation involving literal
18-
authenticate(789, "pw:" + "4NQX/CqB5Ae98zFUmwj1DMpF7azshxSvb0Jo4gIFmIQ=")
18+
authenticate(789, "pw:" + "ogH6qSYWGdbR/2WOGYa7eZ/tObL+GtqDPx6q37BTTRQ=")
19+
20+
pw_left = "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+ZXFj2qw6asRARTV2deAXFKkMTVOoaFYom1Q"
21+
pw_right = "4fQuzXef4f2yow8KWvIJTA=="
22+
pw = pw_left + pw_right
23+
authenticate(999, pw)
1924

2025
passwd = gets.chomp
2126
# call with hardcoded credential-like value, but not to a potential credential sink (should not be flagged)
2227
authenticate("gowLsSGfPbh/ZS60k+LQQBhcq1tsh/YgbvNmDauQr5Q=", passwd)
28+
29+
module Passwords
30+
class KnownPasswords
31+
def include?(passwd)
32+
passwd == "foo"
33+
end
34+
end
35+
end
36+
37+
# Call to object method
38+
Passwords::KnownPasswords.new.include?("kdW/xVhiv6y1fQQNevDpUaq+2rfPKfh+teE/45zS7bc=")
39+
40+
# Call to unrelated method with same name (should not be flagged)
41+
"foobar".include?("foo")

0 commit comments

Comments
 (0)