Skip to content

Commit 32464a8

Browse files
committed
C++: Support SQL Injection sinks for Oracle Call Interface (OCI)
1 parent 30ab9b7 commit 32464a8

File tree

6 files changed

+61
-0
lines changed

6 files changed

+61
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.

cpp/ql/lib/ext/Oracle.oci.model.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# partial model of the Oracle Call Interface (OCI) library
2+
extensions:
3+
- addsTo:
4+
pack: codeql/cpp-all
5+
extensible: sinkModel
6+
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
7+
- ["", "", False, "OCIStmtPrepare", "", "", "Argument[*2]", "sql-injection", "manual"]
8+
- ["", "", False, "OCIStmtPrepare2", "", "", "Argument[*3]", "sql-injection", "manual"]

cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
3838

3939
predicate isSink(DataFlow::Node node) {
4040
exists(SqlLikeFunction runSql | runSql.outermostWrapperFunctionCall(asSinkExpr(node), _))
41+
or
42+
// sink defined using models-as-data
43+
sinkNode(node, "sql-injection")
4144
}
4245

4346
predicate isBarrier(DataFlow::Node node) {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The query `cpp/sql-injection` now can be extended using the `sql-injection` Models as Data (MaD) sink kind.

cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ edges
99
| test.c:48:20:48:33 | *globalUsername | test.c:51:18:51:23 | *query1 | provenance | TaintFunction |
1010
| test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | *userInput | provenance | |
1111
| test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | *userInput | provenance | |
12+
| test.c:101:8:101:16 | gets output argument | test.c:106:24:106:29 | *query1 | provenance | TaintFunction Sink:MaD:325 |
13+
| test.c:101:8:101:16 | gets output argument | test.c:107:28:107:33 | *query1 | provenance | TaintFunction Sink:MaD:326 |
1214
| test.cpp:39:27:39:30 | **argv | test.cpp:43:27:43:33 | *access to array | provenance | |
1315
nodes
1416
| test.c:14:27:14:30 | **argv | semmle.label | **argv |
@@ -23,6 +25,9 @@ nodes
2325
| test.c:75:8:75:16 | gets output argument | semmle.label | gets output argument |
2426
| test.c:76:17:76:25 | *userInput | semmle.label | *userInput |
2527
| test.c:77:20:77:28 | *userInput | semmle.label | *userInput |
28+
| test.c:101:8:101:16 | gets output argument | semmle.label | gets output argument |
29+
| test.c:106:24:106:29 | *query1 | semmle.label | *query1 |
30+
| test.c:107:28:107:33 | *query1 | semmle.label | *query1 |
2631
| test.cpp:39:27:39:30 | **argv | semmle.label | **argv |
2732
| test.cpp:43:27:43:33 | *access to array | semmle.label | *access to array |
2833
subpaths

cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,41 @@ void ODBCTests(){
7575
gets(userInput);
7676
SQLPrepare(0, userInput, 100); // BAD
7777
SQLExecDirect(0, userInput, 100); // BAD
78+
}
79+
80+
// Oracle Call Interface (OCI) Routines
81+
int OCIStmtPrepare(
82+
void *arg0,
83+
void *arg1,
84+
const unsigned char *sql,
85+
unsigned int arg3,
86+
unsigned int arg4,
87+
unsigned int arg5);
88+
int OCIStmtPrepare2(
89+
void *arg0,
90+
void **arg1,
91+
void *arg2,
92+
const unsigned char *sql,
93+
unsigned int arg4,
94+
const unsigned char *arg5,
95+
unsigned int arg6,
96+
unsigned int arg7,
97+
unsigned int arg8);
98+
99+
void OCITests(){
100+
char userInput[100];
101+
gets(userInput);
102+
103+
// a string from the user is injected directly into an SQL query.
104+
char query1[1000] = {0};
105+
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userInput);
106+
OCIStmtPrepare(0, 0, query1, 0, 0, 0); // BAD
107+
OCIStmtPrepare2(0, 0, 0, query1, 0, 0, 0, 0, 0); // BAD
108+
109+
// an integer from the user is injected into an SQL query.
110+
int userNumber = atoi(userInput);
111+
char query2[1000] = {0};
112+
snprintf(query2, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber);
113+
OCIStmtPrepare(0, 0, query2, 0, 0, 0); // GOOD
114+
OCIStmtPrepare2(0, 0, 0, query2, 0, 0, 0, 0, 0); // GOOD
78115
}

0 commit comments

Comments
 (0)