Skip to content

Commit

Permalink
Merge pull request #74 from AikidoSec/patch-move
Browse files Browse the repository at this point in the history
Move functions to separate files
  • Loading branch information
hansott authored Mar 11, 2024
2 parents f76ef5a + bf35574 commit ecb70ec
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 90 deletions.
2 changes: 1 addition & 1 deletion library/src/sinks/MySQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Context } from "../agent/Context";
import { Hooks } from "../agent/hooks/Hooks";
import { InterceptorResult } from "../agent/hooks/MethodInterceptor";
import { Wrapper } from "../agent/Wrapper";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/detectSQLInjection";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/checkContextForSqlInjection";

export class MySQL implements Wrapper {
private inspectQuery(
Expand Down
2 changes: 1 addition & 1 deletion library/src/sinks/MySQL2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Context } from "../agent/Context";
import { Hooks } from "../agent/hooks/Hooks";
import { InterceptorResult } from "../agent/hooks/MethodInterceptor";
import { Wrapper } from "../agent/Wrapper";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/detectSQLInjection";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/checkContextForSqlInjection";

export class MySQL2 implements Wrapper {
private inspectQuery(
Expand Down
2 changes: 1 addition & 1 deletion library/src/sinks/Postgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Hooks } from "../agent/hooks/Hooks";
import { InterceptorResult } from "../agent/hooks/MethodInterceptor";
import { Wrapper } from "../agent/Wrapper";
import { Context } from "../agent/Context";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/detectSQLInjection";
import { checkContextForSqlInjection } from "../vulnerabilities/sql-injection/checkContextForSqlInjection";

export class Postgres implements Wrapper {
private inspectQuery(args: unknown[], context: Context): InterceptorResult {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Context } from "../../agent/Context";
import { InterceptorResult } from "../../agent/hooks/MethodInterceptor";
import { Source } from "../../agent/Source";
import { extractStringsFromUserInput } from "../../helpers/extractStringsFromUserInput";
import { detectSQLInjection } from "./detectSQLInjection";

/**
* This function goes over all the different input types in the context and checks
* if it's a possible SQL Injection, if so the function returns an InterceptorResult
*/
export function checkContextForSqlInjection({
sql,
operation,
context,
}: {
sql: string;
operation: string;
context: Context;
}): InterceptorResult {
for (const source of ["body", "query", "headers", "cookies"] as Source[]) {
if (context[source]) {
const userInput = extractStringsFromUserInput(context[source]);
for (const str of userInput) {
if (detectSQLInjection(sql, str)) {
return {
operation: operation,
kind: "sql_injection",
source: source,
pathToPayload: "UNKOWN",
metadata: {},
};
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { basename, join } from "path";
import * as t from "tap";
import { readFileSync } from "fs";
import * as path from "path";
import { dangerousCharsInInput } from "./dangerousCharsInInput";
import {
detectSQLInjection,
userInputOccurrencesSafelyEncapsulated,
queryContainsUserInput,
} from "./detectSQLInjection";
import { detectSQLInjection } from "./detectSQLInjection";
import { queryContainsUserInput } from "./queryContainsUserInput";
import { userInputOccurrencesSafelyEncapsulated } from "./userInputOccurrencesSafelyEncapsulated";

const BAD_SQL_COMMANDS = [
// Check for SQL Commands like : INSERT or DROP
Expand Down
83 changes: 2 additions & 81 deletions library/src/vulnerabilities/sql-injection/detectSQLInjection.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Agent } from "../../agent/Agent";
import { Context } from "../../agent/Context";
import { InterceptorResult } from "../../agent/hooks/MethodInterceptor";
import { sourceHumanName, Source } from "../../agent/Source";
import { extractStringsFromUserInput } from "../../helpers/extractStringsFromUserInput";
import { SQL_STRING_CHARS } from "./config";
import { dangerousCharsInInput } from "./dangerousCharsInInput";
import { queryContainsUserInput } from "./queryContainsUserInput";
import { userInputContainsSQLSyntax } from "./userInputContainsSQLSyntax";
import { userInputOccurrencesSafelyEncapsulated } from "./userInputOccurrencesSafelyEncapsulated";

/**
* This function executes 2 checks to see if something is or is not an SQL Injection :
Expand Down Expand Up @@ -42,78 +38,3 @@ export function detectSQLInjection(query: string, userInput: string) {
// Executing our final check with the massive RegEx :
return userInputContainsSQLSyntax(userInput);
}

/**
* This function is the first step to determine if an SQL Injection is happening,
* If the sql statement contains user input, this function returns true (case-insensitive)
* @param query The SQL Statement you want to check it against
* @param userInput The user input you want to check
* @returns True when the sql statement contains the input
*/
export function queryContainsUserInput(query: string, userInput: string) {
const lowercaseSql = query.toLowerCase();
const lowercaseInput = userInput.toLowerCase();

return lowercaseSql.includes(lowercaseInput);
}

/**
* This function is the third step to determine if an SQL Injection is happening,
* This checks if **all** occurrences of our input are encapsulated as strings.
* @param query The SQL Statement
* @param userInput The user input you want to check is encapsulated
* @returns True if the input is always encapsulated inside a string
*/
export function userInputOccurrencesSafelyEncapsulated(
query: string,
userInput: string
) {
const queryWithoutUserInput = query.split(userInput);
for (let i = 0; i + 1 < queryWithoutUserInput.length; i++) {
// Get the last character of this segment
const lastChar = queryWithoutUserInput[i].slice(-1);
// Get the first character of the next segment
const firstCharNext = queryWithoutUserInput[i + 1].slice(0, 1);

if (!SQL_STRING_CHARS.includes(lastChar)) {
return false; // If the character is not one of these, it's not a string.
}

if (lastChar != firstCharNext) {
return false; // String is not encapsulated by the same type of quotes.
}
}

return true;
}

/**
* This function goes over all the different input types in the context and checks
* if it's a possible SQL Injection, if so the function returns an InterceptorResult
*/
export function checkContextForSqlInjection({
sql,
operation,
context,
}: {
sql: string;
operation: string;
context: Context;
}): InterceptorResult {
for (const source of ["body", "query", "headers", "cookies"] as Source[]) {
if (context[source]) {
const userInput = extractStringsFromUserInput(context[source]);
for (const str of userInput) {
if (detectSQLInjection(sql, str)) {
return {
operation: operation,
kind: "sql_injection",
source: source,
pathToPayload: "UNKOWN",
metadata: {},
};
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* This function is the first step to determine if an SQL Injection is happening,
* If the sql statement contains user input, this function returns true (case-insensitive)
* @param query The SQL Statement you want to check it against
* @param userInput The user input you want to check
* @returns True when the sql statement contains the input
*/
export function queryContainsUserInput(query: string, userInput: string) {
const lowercaseSql = query.toLowerCase();
const lowercaseInput = userInput.toLowerCase();

return lowercaseSql.includes(lowercaseInput);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { SQL_STRING_CHARS } from "./config";

/**
* This function is the third step to determine if an SQL Injection is happening,
* This checks if **all** occurrences of our input are encapsulated as strings.
* @param query The SQL Statement
* @param userInput The user input you want to check is encapsulated
* @returns True if the input is always encapsulated inside a string
*/
export function userInputOccurrencesSafelyEncapsulated(
query: string,
userInput: string
) {
const queryWithoutUserInput = query.split(userInput);
for (let i = 0; i + 1 < queryWithoutUserInput.length; i++) {
// Get the last character of this segment
const lastChar = queryWithoutUserInput[i].slice(-1);
// Get the first character of the next segment
const firstCharNext = queryWithoutUserInput[i + 1].slice(0, 1);

if (!SQL_STRING_CHARS.includes(lastChar)) {
return false; // If the character is not one of these, it's not a string.
}

if (lastChar != firstCharNext) {
return false; // String is not encapsulated by the same type of quotes.
}
}

return true;
}

0 comments on commit ecb70ec

Please sign in to comment.