Skip to content

Commit 2014599

Browse files
authored
Merge pull request #8318 from geoffw0/cwe497b
C++: New query cpp/potential-system-data-exposure
2 parents b75ac4e + 9f3fd57 commit 2014599

22 files changed

+945
-320
lines changed

cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.qhelp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
"qhelp.dtd">
44
<qhelp>
55
<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>
6+
<p>Exposing system data or debugging information may help a malicious user 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 the software.</p>
77

8-
<p>This query finds locations where system configuration information might be revealed to a user.</p>
8+
<p>This query finds locations where system configuration information might be revealed to a remote user.</p>
99
</overview>
1010

1111
<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>
12+
<p>Do not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
1313
</recommendation>
1414

1515
<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>
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 a malicious user who does not have legitimate access to that information.</p>
1717

1818
<sample src="ExposedSystemDataIncorrect.cpp" />
1919

cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql

Lines changed: 3 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Exposure of system data to an unauthorized control sphere
33
* @description Exposing system data or debugging information helps
4-
* an adversary learn about the system and form an
4+
* a malicious user learn about the system and form an
55
* attack plan.
66
* @kind path-problem
77
* @problem.severity warning
@@ -13,284 +13,15 @@
1313
*/
1414

1515
import cpp
16-
import semmle.code.cpp.commons.Environment
1716
import semmle.code.cpp.ir.dataflow.TaintTracking
1817
import semmle.code.cpp.models.interfaces.FlowSource
1918
import DataFlow::PathGraph
20-
21-
/**
22-
* An element that should not be exposed to an adversary.
23-
*/
24-
abstract class SystemData extends Element {
25-
/**
26-
* Gets an expression that is part of this `SystemData`.
27-
*/
28-
abstract Expr getAnExpr();
29-
}
30-
31-
/**
32-
* Data originating from the environment.
33-
*/
34-
class EnvData extends SystemData {
35-
EnvData() {
36-
// identify risky looking environment variables only
37-
this.(EnvironmentRead)
38-
.getEnvironmentVariable()
39-
.toLowerCase()
40-
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
41-
}
42-
43-
override Expr getAnExpr() { result = this }
44-
}
45-
46-
/**
47-
* Data originating from a call to `mysql_get_client_info()`.
48-
*/
49-
class SqlClientInfo extends SystemData {
50-
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
51-
52-
override Expr getAnExpr() { result = this }
53-
}
54-
55-
private predicate sqlConnectInfo(FunctionCall source, VariableAccess use) {
56-
(
57-
source.getTarget().hasName("mysql_connect") or
58-
source.getTarget().hasName("mysql_real_connect")
59-
) and
60-
use = source.getAnArgument()
61-
}
62-
63-
/**
64-
* Data passed into an SQL connect function.
65-
*/
66-
class SqlConnectInfo extends SystemData {
67-
SqlConnectInfo() { sqlConnectInfo(this, _) }
68-
69-
override Expr getAnExpr() { sqlConnectInfo(this, result) }
70-
}
71-
72-
private predicate posixSystemInfo(FunctionCall source, Element use) {
73-
// size_t confstr(int name, char *buf, size_t len)
74-
// - various OS / system strings, such as the libc version
75-
// int statvfs(const char *__path, struct statvfs *__buf)
76-
// int fstatvfs(int __fd, struct statvfs *__buf)
77-
// - various filesystem parameters
78-
// int uname(struct utsname *buf)
79-
// - OS name and version
80-
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs", "uname"]) and
81-
use = source.getArgument(1)
82-
}
83-
84-
/**
85-
* Data obtained from a POSIX system information call.
86-
*/
87-
class PosixSystemInfo extends SystemData {
88-
PosixSystemInfo() { posixSystemInfo(this, _) }
89-
90-
override Expr getAnExpr() { posixSystemInfo(this, result) }
91-
}
92-
93-
private predicate posixPWInfo(FunctionCall source, Element use) {
94-
// struct passwd *getpwnam(const char *name);
95-
// struct passwd *getpwuid(uid_t uid);
96-
// struct passwd *getpwent(void);
97-
// struct group *getgrnam(const char *name);
98-
// struct group *getgrgid(gid_t);
99-
// struct group *getgrent(void);
100-
source
101-
.getTarget()
102-
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
103-
use = source
104-
or
105-
// int getpwnam_r(const char *name, struct passwd *pwd,
106-
// char *buf, size_t buflen, struct passwd **result);
107-
// int getpwuid_r(uid_t uid, struct passwd *pwd,
108-
// char *buf, size_t buflen, struct passwd **result);
109-
// int getgrgid_r(gid_t gid, struct group *grp,
110-
// char *buf, size_t buflen, struct group **result);
111-
// int getgrnam_r(const char *name, struct group *grp,
112-
// char *buf, size_t buflen, struct group **result);
113-
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
114-
use = source.getArgument([1, 2, 4])
115-
or
116-
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
117-
// struct passwd **result);
118-
// int getgrent_r(struct group *gbuf, char *buf,
119-
// size_t buflen, struct group **gbufp);
120-
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
121-
use = source.getArgument([0, 1, 3])
122-
}
123-
124-
/**
125-
* Data obtained from a POSIX user/password/group database information call.
126-
*/
127-
class PosixPWInfo extends SystemData {
128-
PosixPWInfo() { posixPWInfo(this, _) }
129-
130-
override Expr getAnExpr() { posixPWInfo(this, result) }
131-
}
132-
133-
private predicate windowsSystemInfo(FunctionCall source, Element use) {
134-
// DWORD WINAPI GetVersion(void);
135-
source.getTarget().hasGlobalName("GetVersion") and
136-
use = source
137-
or
138-
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
139-
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
140-
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
141-
source
142-
.getTarget()
143-
.hasGlobalName([
144-
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
145-
]) and
146-
use = source.getArgument(0)
147-
}
148-
149-
/**
150-
* Data obtained from a Windows system information call.
151-
*/
152-
class WindowsSystemInfo extends SystemData {
153-
WindowsSystemInfo() { windowsSystemInfo(this, _) }
154-
155-
override Expr getAnExpr() { windowsSystemInfo(this, result) }
156-
}
157-
158-
private predicate windowsFolderPath(FunctionCall source, Element use) {
159-
// BOOL SHGetSpecialFolderPath(
160-
// HWND hwndOwner,
161-
// _Out_ LPTSTR lpszPath,
162-
// _In_ int csidl,
163-
// _In_ BOOL fCreate
164-
// );
165-
source
166-
.getTarget()
167-
.hasGlobalName([
168-
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
169-
]) and
170-
use = source.getArgument(1)
171-
or
172-
// HRESULT SHGetKnownFolderPath(
173-
// _In_ REFKNOWNFOLDERID rfid,
174-
// _In_ DWORD dwFlags,
175-
// _In_opt_ HANDLE hToken,
176-
// _Out_ PWSTR *ppszPath
177-
// );
178-
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
179-
use = source.getArgument(3)
180-
or
181-
// HRESULT SHGetFolderPath(
182-
// _In_ HWND hwndOwner,
183-
// _In_ int nFolder,
184-
// _In_ HANDLE hToken,
185-
// _In_ DWORD dwFlags,
186-
// _Out_ LPTSTR pszPath
187-
// );
188-
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
189-
use = source.getArgument(4)
190-
or
191-
// HRESULT SHGetFolderPathAndSubDir(
192-
// _In_ HWND hwnd,
193-
// _In_ int csidl,
194-
// _In_ HANDLE hToken,
195-
// _In_ DWORD dwFlags,
196-
// _In_ LPCTSTR pszSubDir,
197-
// _Out_ LPTSTR pszPath
198-
// );
199-
source
200-
.getTarget()
201-
.hasGlobalName([
202-
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
203-
]) and
204-
use = source.getArgument(5)
205-
}
206-
207-
/**
208-
* Data obtained about Windows special paths (for example, the
209-
* location of `System32`).
210-
*/
211-
class WindowsFolderPath extends SystemData {
212-
WindowsFolderPath() { windowsFolderPath(this, _) }
213-
214-
override Expr getAnExpr() { windowsFolderPath(this, result) }
215-
}
216-
217-
private predicate logonUser(FunctionCall source, VariableAccess use) {
218-
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
219-
use = source.getAnArgument()
220-
}
221-
222-
/**
223-
* Data passed into a `LogonUser` (Windows) function.
224-
*/
225-
class LogonUser extends SystemData {
226-
LogonUser() { logonUser(this, _) }
227-
228-
override Expr getAnExpr() { logonUser(this, result) }
229-
}
230-
231-
private predicate regQuery(FunctionCall source, VariableAccess use) {
232-
// LONG WINAPI RegQueryValue(
233-
// _In_ HKEY hKey,
234-
// _In_opt_ LPCTSTR lpSubKey,
235-
// _Out_opt_ LPTSTR lpValue,
236-
// _Inout_opt_ PLONG lpcbValue
237-
// );
238-
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
239-
use = source.getArgument(2)
240-
or
241-
// LONG WINAPI RegQueryMultipleValues(
242-
// _In_ HKEY hKey,
243-
// _Out_ PVALENT val_list,
244-
// _In_ DWORD num_vals,
245-
// _Out_opt_ LPTSTR lpValueBuf,
246-
// _Inout_opt_ LPDWORD ldwTotsize
247-
// );
248-
source
249-
.getTarget()
250-
.hasGlobalName([
251-
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
252-
]) and
253-
use = source.getArgument(3)
254-
or
255-
// LONG WINAPI RegQueryValueEx(
256-
// _In_ HKEY hKey,
257-
// _In_opt_ LPCTSTR lpValueName,
258-
// _Reserved_ LPDWORD lpReserved,
259-
// _Out_opt_ LPDWORD lpType,
260-
// _Out_opt_ LPBYTE lpData,
261-
// _Inout_opt_ LPDWORD lpcbData
262-
// );
263-
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
264-
use = source.getArgument(4)
265-
or
266-
// LONG WINAPI RegGetValue(
267-
// _In_ HKEY hkey,
268-
// _In_opt_ LPCTSTR lpSubKey,
269-
// _In_opt_ LPCTSTR lpValue,
270-
// _In_opt_ DWORD dwFlags,
271-
// _Out_opt_ LPDWORD pdwType,
272-
// _Out_opt_ PVOID pvData,
273-
// _Inout_opt_ LPDWORD pcbData
274-
// );
275-
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
276-
use = source.getArgument(5)
277-
}
278-
279-
/**
280-
* Data read from the Windows registry.
281-
*/
282-
class RegQuery extends SystemData {
283-
RegQuery() { regQuery(this, _) }
284-
285-
override Expr getAnExpr() { regQuery(this, result) }
286-
}
19+
import SystemData
28720

28821
class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
28922
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" }
29023

291-
override predicate isSource(DataFlow::Node source) {
292-
source.asConvertedExpr() = any(SystemData sd).getAnExpr()
293-
}
24+
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
29425

29526
override predicate isSink(DataFlow::Node sink) {
29627
exists(FunctionCall fc, FunctionInput input, int arg |

cpp/ql/src/Security/CWE/CWE-497/ExposedSystemDataCorrect.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ char* path = getenv("PATH");
22

33
//...
44

5-
fprintf(stderr, "A required executable file could not be found. " \
6-
"Please ensure that the software has been installed " \
7-
"correctly or contact a system administrator.\n");
5+
message = "An internal error has occurred. Please try again or contact a system administrator.\n";
6+
send(socket, message, strlen(message), 0);

cpp/ql/src/Security/CWE/CWE-497/ExposedSystemDataIncorrect.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ char* path = getenv("PATH");
22

33
//...
44

5-
fprintf(stderr, "cannot find exe on path %s\n", path);
5+
sprintf(buffer, "Cannot find exe on path: %s", path);
6+
send(socket, buffer, strlen(buffer), 0);
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 a malicious user 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 the software.</p>
7+
8+
<p>This query finds locations where system configuration information that is particularly sensitive 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 a malicious user.</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 a malicious user who does not have legitimate access to that information.</p>
17+
18+
<sample src="PotentiallyExposedSystemDataIncorrect.cpp" />
19+
20+
<p>The message should be rephrased without this information, for example:</p>
21+
22+
<sample src="PotentiallyExposedSystemDataCorrect.cpp" />
23+
</example>
24+
25+
<references>
26+
</references>
27+
28+
</qhelp>

0 commit comments

Comments
 (0)