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

Skip to content

Commit d95b56f

Browse files
committed
C++: Create prototype query.
1 parent 67aa144 commit d95b56f

2 files changed

Lines changed: 247 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Exposing system data or debugging information may help an adversary to learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in these technologies.</p>
7+
8+
<p>This query finds locations where system configuration information might be revealed to a user.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to an adversary.</p>
13+
</recommendation>
14+
15+
<example>
16+
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to an adversary who does not have legitimate access to that information.</p>
17+
18+
<sample src="ExposedSystemDataIncorrect.cpp" />
19+
20+
<p>The message should be rephrased without this information, for example:</p>
21+
22+
<sample src="ExposedSystemDataCorrect.cpp" />
23+
</example>
24+
25+
<references>
26+
</references>
27+
28+
</qhelp>
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/**
2+
* @name Potential exposure of sensitive system data to an unauthorized control sphere
3+
* @description Exposing sensitive system data helps
4+
* an adversary learn about the system and form an
5+
* attack plan.
6+
* @kind problem
7+
* @problem.severity warning
8+
* @security-severity TODO
9+
* @precision medium
10+
* @id cpp/potential-system-data-exposure
11+
* @tags security
12+
* external/cwe/cwe-497
13+
*/
14+
15+
/*
16+
* These queries are closely related:
17+
* - `cpp/system-data-exposure`, which flags exposure of system information
18+
* to a remote sink (i.e. focusses on qualiy of the sink).
19+
* - `cpp/potential-system-data-exposure`, which flags on exposure of the most
20+
* sensitive information to a local sink (i.e. focusses on quality of the
21+
* sensitive information).
22+
*
23+
* This used to be a single query with neither focus, which was too noisy and
24+
* gave the user less control.
25+
*/
26+
27+
// TODO: use a library to reduce duplication between the queries.
28+
import cpp
29+
import semmle.code.cpp.commons.Environment
30+
import semmle.code.cpp.ir.dataflow.TaintTracking
31+
import semmle.code.cpp.models.interfaces.FlowSource
32+
import semmle.code.cpp.security.OutputWrite
33+
import DataFlow::PathGraph
34+
35+
/**
36+
* An element that should not be exposed to an adversary.
37+
*/
38+
abstract class SystemData extends Element {
39+
/**
40+
* Gets an expression that is part of this `SystemData`.
41+
*/
42+
abstract Expr getAnExpr();
43+
}
44+
45+
/**
46+
* Data that is likely to be sensitive, originating from the environment.
47+
*/
48+
class EnvData extends SystemData {
49+
EnvData() {
50+
// identify risky looking environment variables only
51+
this.(EnvironmentRead)
52+
.getEnvironmentVariable()
53+
.toLowerCase()
54+
.regexpMatch(".*(pass|token|key).*")
55+
}
56+
57+
override Expr getAnExpr() { result = this }
58+
}
59+
60+
/**
61+
* Data originating from a call to `mysql_get_client_info()`.
62+
*/
63+
class SQLClientInfo extends SystemData {
64+
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
65+
66+
override Expr getAnExpr() { result = this }
67+
}
68+
69+
private predicate sqlConnectInfo(FunctionCall source, VariableAccess use) {
70+
(
71+
source.getTarget().hasName("mysql_connect") or
72+
source.getTarget().hasName("mysql_real_connect")
73+
) and
74+
use = source.getArgument(3) // passwd
75+
}
76+
77+
/**
78+
* Sensitive data passed into an SQL connect function.
79+
*/
80+
class SQLConnectInfo extends SystemData {
81+
SQLConnectInfo() { sqlConnectInfo(this, _) }
82+
83+
override Expr getAnExpr() { sqlConnectInfo(this, result) }
84+
}
85+
86+
private predicate posixPWInfo(FunctionCall source, Element use) {
87+
// struct passwd *getpwnam(const char *name);
88+
// struct passwd *getpwuid(uid_t uid);
89+
// struct passwd *getpwent(void);
90+
// struct group *getgrnam(const char *name);
91+
// struct group *getgrgid(gid_t);
92+
// struct group *getgrent(void);
93+
source
94+
.getTarget()
95+
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
96+
use = source
97+
or
98+
// int getpwnam_r(const char *name, struct passwd *pwd,
99+
// char *buf, size_t buflen, struct passwd **result);
100+
// int getpwuid_r(uid_t uid, struct passwd *pwd,
101+
// char *buf, size_t buflen, struct passwd **result);
102+
// int getgrgid_r(gid_t gid, struct group *grp,
103+
// char *buf, size_t buflen, struct group **result);
104+
// int getgrnam_r(const char *name, struct group *grp,
105+
// char *buf, size_t buflen, struct group **result);
106+
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
107+
use = source.getArgument([1, 2, 4])
108+
or
109+
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
110+
// struct passwd **result);
111+
// int getgrent_r(struct group *gbuf, char *buf,
112+
// size_t buflen, struct group **gbufp);
113+
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
114+
use = source.getArgument([0, 1, 3])
115+
}
116+
117+
/**
118+
* Data obtained from a POSIX user/password/group database information call.
119+
*/
120+
class PosixPWInfo extends SystemData {
121+
PosixPWInfo() { posixPWInfo(this, _) }
122+
123+
override Expr getAnExpr() { posixPWInfo(this, result) }
124+
}
125+
126+
private predicate logonUser(FunctionCall source, VariableAccess use) {
127+
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
128+
use = source.getAnArgument()
129+
}
130+
131+
/**
132+
* Data passed into a `LogonUser` (Windows) function.
133+
*/
134+
class LogonUser extends SystemData {
135+
LogonUser() { logonUser(this, _) }
136+
137+
override Expr getAnExpr() { logonUser(this, result) }
138+
}
139+
140+
private predicate regQuery(FunctionCall source, VariableAccess use) {
141+
// LONG WINAPI RegQueryValue(
142+
// _In_ HKEY hKey,
143+
// _In_opt_ LPCTSTR lpSubKey,
144+
// _Out_opt_ LPTSTR lpValue,
145+
// _Inout_opt_ PLONG lpcbValue
146+
// );
147+
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
148+
use = source.getArgument(2)
149+
or
150+
// LONG WINAPI RegQueryMultipleValues(
151+
// _In_ HKEY hKey,
152+
// _Out_ PVALENT val_list,
153+
// _In_ DWORD num_vals,
154+
// _Out_opt_ LPTSTR lpValueBuf,
155+
// _Inout_opt_ LPDWORD ldwTotsize
156+
// );
157+
source
158+
.getTarget()
159+
.hasGlobalName([
160+
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
161+
]) and
162+
use = source.getArgument(3)
163+
or
164+
// LONG WINAPI RegQueryValueEx(
165+
// _In_ HKEY hKey,
166+
// _In_opt_ LPCTSTR lpValueName,
167+
// _Reserved_ LPDWORD lpReserved,
168+
// _Out_opt_ LPDWORD lpType,
169+
// _Out_opt_ LPBYTE lpData,
170+
// _Inout_opt_ LPDWORD lpcbData
171+
// );
172+
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
173+
use = source.getArgument(4)
174+
or
175+
// LONG WINAPI RegGetValue(
176+
// _In_ HKEY hkey,
177+
// _In_opt_ LPCTSTR lpSubKey,
178+
// _In_opt_ LPCTSTR lpValue,
179+
// _In_opt_ DWORD dwFlags,
180+
// _Out_opt_ LPDWORD pdwType,
181+
// _Out_opt_ PVOID pvData,
182+
// _Inout_opt_ LPDWORD pcbData
183+
// );
184+
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
185+
use = source.getArgument(5)
186+
}
187+
188+
/**
189+
* Data read from the Windows registry.
190+
*/
191+
class RegQuery extends SystemData {
192+
RegQuery() { regQuery(this, _) }
193+
194+
override Expr getAnExpr() {
195+
regQuery(this, result) and
196+
this.(FunctionCall).getAnArgument().getValue().toLowerCase().regexpMatch(".*(pass|token|key).*")
197+
}
198+
}
199+
200+
class PotentiallyExposedSystemDataConfiguration extends TaintTracking::Configuration {
201+
PotentiallyExposedSystemDataConfiguration() { this = "PotentiallyExposedSystemDataConfiguration" }
202+
203+
override predicate isSource(DataFlow::Node source) {
204+
source.asExpr() = any(SystemData sd).getAnExpr()
205+
}
206+
207+
override predicate isSink(DataFlow::Node sink) {
208+
exists(OutputWrite ow | ow.getASource() = sink.asExpr())
209+
// TODO: eliminate duplication on remote flow sources?
210+
}
211+
}
212+
213+
from
214+
PotentiallyExposedSystemDataConfiguration config, DataFlow::PathNode source,
215+
DataFlow::PathNode sink
216+
where config.hasFlowPath(source, sink)
217+
select sink, source, sink,
218+
"This operation potentially exposes sensitive system data (a password or token) from $@.", source,
219+
source.getNode().toString()

0 commit comments

Comments
 (0)