mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
private data file/buffer write
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="PrivateCleartextStorage.qhelp" /></qhelp>
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @name Cleartext storage of private data in buffer
|
||||
* @description Storing private data in cleartext can expose it
|
||||
* to an attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id cpp/private-cleartext-storage-buffer
|
||||
* @tags security
|
||||
* external/cwe/cwe-312
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.BufferWrite
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
import semmle.code.cpp.security.PrivateData
|
||||
import TaintedWithPath
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element tainted) { exists(BufferWrite w | w.getASource() = tainted) }
|
||||
}
|
||||
|
||||
from
|
||||
BufferWrite w, Expr taintedArg, Expr taintSource, PathNode sourceNode, PathNode sinkNode,
|
||||
string taintCause, PrivateDataExpr dest
|
||||
where
|
||||
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
||||
isUserInput(taintSource, taintCause) and
|
||||
w.getASource() = taintedArg and
|
||||
dest = w.getDest()
|
||||
select w, sourceNode, sinkNode,
|
||||
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@",
|
||||
taintSource, "user input (" + taintCause + ")"
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="PrivateCleartextStorage.qhelp" /></qhelp>
|
||||
22
cpp/ql/src/Security/CWE/CWE-359/PrivateCleartextFileWrite.ql
Normal file
22
cpp/ql/src/Security/CWE/CWE-359/PrivateCleartextFileWrite.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @name Cleartext storage of sensitive information in file
|
||||
* @description Storing sensitive information in cleartext can expose it
|
||||
* to an attacker.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id cpp/private-cleartext-storage-file
|
||||
* @tags security
|
||||
* external/cwe/cwe-313
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.PrivateData
|
||||
import semmle.code.cpp.security.FileWrite
|
||||
|
||||
from FileWrite w, PrivateDataExpr source, Expr dest
|
||||
where
|
||||
source = w.getASource() and
|
||||
dest = w.getDest()
|
||||
select w, "This write into file '" + dest.toString() + "' may contain unencrypted data from $@",
|
||||
source, "this source."
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Private data that is stored unencrypted is accessible to an attacker who gains access to the
|
||||
storage.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Ensure that private data is always encrypted before being stored, especially before writing to a file.
|
||||
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
|
||||
|
||||
<p>In general, decrypt private data only at the point where it is necessary for it to be used in
|
||||
cleartext.</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
<!-- LocalWords: CWE
|
||||
-->
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
54
cpp/ql/src/semmle/code/cpp/security/PrivateData.qll
Normal file
54
cpp/ql/src/semmle/code/cpp/security/PrivateData.qll
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying private data and functions for security.
|
||||
*
|
||||
* 'Private' data in general is anything that would compromise user privacy if exposed. This
|
||||
* library tries to guess where private data may either be stored in a variable or produced by a
|
||||
* function.
|
||||
*
|
||||
* This library is not concerned with credentials. See `SensitiveActions` for expressions related
|
||||
* to credentials.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/** A string for `match` that identifies strings that look like they represent private data. */
|
||||
private string privateNames() {
|
||||
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
|
||||
// Government identifiers, such as Social Security Numbers
|
||||
result = "%social%security%number%" or
|
||||
// Contact information, such as home addresses and telephone numbers
|
||||
result = "%postcode%" or
|
||||
result = "%zipcode%" or
|
||||
result = "%telephone%" or
|
||||
// Geographic location - where the user is (or was)
|
||||
result = "%latitude%" or
|
||||
result = "%longitude%" or
|
||||
// Financial data - such as credit card numbers, salary, bank accounts, and debts
|
||||
result = "%creditcard%" or
|
||||
result = "%salary%" or
|
||||
result = "%bankaccount%" or
|
||||
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
|
||||
result = "%email%" or
|
||||
result = "%mobile%" or
|
||||
result = "%employer%" or
|
||||
// Health - medical conditions, insurance status, prescription records
|
||||
result = "%medical%"
|
||||
}
|
||||
|
||||
/** An expression that might contain private data. */
|
||||
abstract class PrivateDataExpr extends Expr { }
|
||||
|
||||
/** A functiond call that might produce private data. */
|
||||
class PrivateFunctionCall extends PrivateDataExpr, FunctionCall {
|
||||
PrivateFunctionCall() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
|
||||
/** An access to a variable that might contain private data. */
|
||||
class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
|
||||
PrivateVariableAccess() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
edges
|
||||
| test.cpp:54:17:54:20 | argv | test.cpp:58:26:58:30 | input |
|
||||
| test.cpp:54:17:54:20 | argv | test.cpp:58:26:58:30 | input |
|
||||
| test.cpp:54:17:54:20 | argv | test.cpp:58:26:58:30 | input |
|
||||
| test.cpp:54:17:54:20 | argv | test.cpp:58:26:58:30 | input |
|
||||
nodes
|
||||
| test.cpp:54:17:54:20 | argv | semmle.label | argv |
|
||||
| test.cpp:54:17:54:20 | argv | semmle.label | argv |
|
||||
| test.cpp:58:26:58:30 | input | semmle.label | input |
|
||||
| test.cpp:58:26:58:30 | input | semmle.label | input |
|
||||
| test.cpp:58:26:58:30 | input | semmle.label | input |
|
||||
#select
|
||||
| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:26:58:30 | input | This write into buffer 'medical' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (argv) |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-359/PrivateCleartextBufferWrite.ql
|
||||
@@ -0,0 +1,3 @@
|
||||
| test.cpp:45:3:45:7 | call to fputs | This write into file 'file' may contain unencrypted data from $@ | test.cpp:45:9:45:16 | theEmail | this source. |
|
||||
| test.cpp:70:32:70:32 | call to operator<< | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:70:35:70:42 | theEmail | this source. |
|
||||
| test.cpp:73:34:73:38 | call to write | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:73:40:73:47 | theEmail | this source. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-359/PrivateCleartextFileWrite.ql
|
||||
@@ -0,0 +1,79 @@
|
||||
#define FILE int
|
||||
#define wchar char
|
||||
#define size_t int
|
||||
typedef int streamsize;
|
||||
|
||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
int fputs(const char *s, FILE *stream);
|
||||
int fputc(int c, FILE *stream);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
typedef charT char_type;
|
||||
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
|
||||
};
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_ofstream : public basic_ostream<charT,traits> {
|
||||
public:
|
||||
};
|
||||
|
||||
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
|
||||
|
||||
typedef basic_ostream<char> ostream;
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *encrypt(char *buffer);
|
||||
|
||||
// test for CleartextFileWrite
|
||||
void file() {
|
||||
char *theEmail = "cleartext email!";
|
||||
FILE *file;
|
||||
|
||||
// BAD: write email to file in cleartext
|
||||
fputs(theEmail, file);
|
||||
|
||||
// GOOD: encrypt first
|
||||
char *encrypted = encrypt(theEmail);
|
||||
fwrite(encrypted, sizeof(encrypted), 1, file);
|
||||
}
|
||||
|
||||
// test for CleartextBufferWrite
|
||||
int main(int argc, char** argv) {
|
||||
char *input = argv[2];
|
||||
char *medical;
|
||||
|
||||
// BAD: write medical to buffer in cleartext
|
||||
sprintf(medical, "%s", input);
|
||||
|
||||
// GOOD: encrypt first
|
||||
sprintf(medical, "%s", encrypt(input));
|
||||
}
|
||||
|
||||
// test for CleartextFileWrite
|
||||
void stream() {
|
||||
char *theEmail = "cleartext email!";
|
||||
ofstream mystream;
|
||||
|
||||
// BAD: write email to file in cleartext
|
||||
mystream << "the email is: " << theEmail;
|
||||
|
||||
// BAD: write email to file in cleartext
|
||||
(mystream << "the email is: ").write(theEmail, strlen(theEmail));
|
||||
|
||||
// GOOD: encrypt first
|
||||
char *encrypted = encrypt(theEmail);
|
||||
mystream << "the email is: " << encrypted;
|
||||
(mystream << "the email is: ").write(encrypted, strlen(encrypted));
|
||||
}
|
||||
Reference in New Issue
Block a user