SQL簡單語義分析概述

SQL簡單語義分析概述

來自專欄信息安全入門筆記8 人贊了文章

SQL語義引擎總體概述

int libinjection_sqli(const char* input, size_t slen, char fingerprint[])

判斷字元串input是不是SQL注入語句,返回1是,0不是,fingerprint作為指紋出參,其中核心函數如下:

libinjection_sqli_init(&state, input, slen, 0);

issqli = libinjection_is_sqli(&state);

初始化函數:libinjection_sqli_init()

這個函數沒幹啥,主要註冊了一個回調函數

sf->lookup = libinjection_sqli_lookup_word;

處理函數:libinjection_is_sqli()

主要是這個函數判斷是不是SQL注入攻擊,核心函數如下:

libinjection_sqli_fingerprint() (指紋識別函數)

sql_state->lookup() (初始化階段的回調函數)

首先概述指紋識別函數:

libinjection_sqli_reset(sql_state, flags);(狀態重置一下)

tlen = libinjection_sqli_fold(sql_state);(核心階段)

處理一下返回值,實際上核心數據都已經記錄在sql_state

if (tlen > 2 && sql_state->tokenvec[tlen-1].type == TYPE_BAREWORD && sql_state->tokenvec[tlen-1].str_open == CHAR_TICK && sql_state->tokenvec[tlen-1].len == 0 && sql_state->tokenvec[tlen-1].str_close == CHAR_NULL) { sql_state->tokenvec[tlen-1].type = TYPE_COMMENT; }

將所有 tokenvectype 記錄在指紋 fingerprint 中,至此我們計算出字元串的指紋,調用回調函數判斷是否命中指紋庫即可。

for (i = 0; i < tlen; ++i) { sql_state->fingerprint[i] = sql_state->tokenvec[i].type; } sql_state->fingerprint[tlen] = CHAR_NULL;

判斷記錄指紋 fingerprint中是否存在 TYPE_EVIL (無法解析)

如果存在,那麼做如下處理:

if (strchr(sql_state->fingerprint, TYPE_EVIL)) { memset((void*)sql_state->fingerprint, 0, LIBINJECTION_SQLI_MAX_TOKENS + 1); memset((void*)sql_state->tokenvec[0].val, 0, LIBINJECTION_SQLI_TOKEN_SIZE); sql_state->fingerprint[0] = TYPE_EVIL; sql_state->tokenvec[0].type = TYPE_EVIL; sql_state->tokenvec[0].val[0] = TYPE_EVIL; sql_state->tokenvec[1].type = CHAR_NULL; }

返回值是計算出來的指紋

return sql_state->fingerprint;

接下來概述回調函數:

sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, sql_state->fingerprint, strlen(sql_state->fingerprint))

回調函數返回非0,那麼就是SQL注入攻擊,

返回0,就不是。

char libinjection_sqli_lookup_word(struct libinjection_sqli_state *sql_state, int lookup_type, const char* str, size_t len){ if (lookup_type == LOOKUP_FINGERPRINT) { return libinjection_sqli_check_fingerprint(sql_state) ? X : ; } else { return bsearch_keyword_type(str, len, sql_keywords, sql_keywords_sz); }}

libinjection_sqli_check_fingerprint(sql_state)

函數功能:判斷黑名單和非白名單

返回True,那麼是SQL注入

返回False,那麼不是SQL注入

int libinjection_sqli_check_fingerprint(struct libinjection_sqli_state* sql_state){ return libinjection_sqli_blacklist(sql_state) && libinjection_sqli_not_whitelist(sql_state);}

libinjection_sqli_blacklist(sql_state)

int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state){ char fp2[8]; char ch; size_t i; size_t len = strlen(sql_state->fingerprint); int patmatch; fp2[0] = 0; for (i = 0; i < len; ++i) { ch = sql_state->fingerprint[i]; if (ch >= a && ch <= z) { ch -= 0x20; } fp2[i+1] = ch; } fp2[i+1] = ; patmatch = is_keyword(fp2, len + 1) == TYPE_FINGERPRINT; if (!patmatch) { return FALSE; } return TRUE;}

libinjection_sqli_not_whitelist(sql_state)

int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state){ char ch; size_t tlen = strlen(sql_state->fingerprint); if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { if (my_memmem(sql_state->s, sql_state->slen, "sp_password", strlen("sp_password"))) { return TRUE; } } switch (tlen) { case 2:{ if (sql_state->fingerprint[1] == TYPE_UNION) { if (sql_state->stats_tokens == 2) { return FALSE; } else { return TRUE; } } if (sql_state->tokenvec[1].val[0] == #) { return FALSE; } if (sql_state->tokenvec[0].type == TYPE_BAREWORD && sql_state->tokenvec[1].type == TYPE_COMMENT && sql_state->tokenvec[1].val[0] != /) { return FALSE; } if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT && sql_state->tokenvec[1].val[0] == /) { return TRUE; } if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT) { if (sql_state->stats_tokens > 2) { return TRUE; } ch = sql_state->s[sql_state->tokenvec[0].len]; if ( ch <= 32 ) { return TRUE; } if (ch == / && sql_state->s[sql_state->tokenvec[0].len + 1] == *) { return TRUE; } if (ch == - && sql_state->s[sql_state->tokenvec[0].len + 1] == -) { return TRUE; } return FALSE; } if ((sql_state->tokenvec[1].len > 2) && sql_state->tokenvec[1].val[0] == -) { return FALSE; } break; } case 3:{ if (streq(sql_state->fingerprint, "sos") || streq(sql_state->fingerprint, "s&s")) { if ((sql_state->tokenvec[0].str_open == CHAR_NULL) && (sql_state->tokenvec[2].str_close == CHAR_NULL) && (sql_state->tokenvec[0].str_close == sql_state->tokenvec[2].str_open)) { return TRUE; } if (sql_state->stats_tokens == 3) { return FALSE; } return FALSE; } else if (streq(sql_state->fingerprint, "s&n") || streq(sql_state->fingerprint, "n&1") || streq(sql_state->fingerprint, "1&1") || streq(sql_state->fingerprint, "1&v") || streq(sql_state->fingerprint, "1&s")) { if (sql_state->stats_tokens == 3) { return FALSE; } } else if (sql_state->tokenvec[1].type == TYPE_KEYWORD) { if ((sql_state->tokenvec[1].len < 5) || cstrcasecmp("INTO", sql_state->tokenvec[1].val, 4)) { return FALSE; } } break; } case 4: case 5: { break; } } /* end switch */ return TRUE;}

bsearch_keyword_type(str, len, sql_keywords, sql_keywords_sz)

函數功能:判斷str是否命中指紋庫sql_keywords 中的指紋。

返回非0,那麼命中

返回0,那麼沒命中

static char bsearch_keyword_type(const char *key, size_t len, const keyword_t * keywords, size_t numb){ size_t pos; size_t left = 0; size_t right = numb - 1; while (left < right) { // 二分查找 pos = (left + right) >> 1; if (cstrcasecmp(keywords[pos].word, key, len) < 0) { left = pos + 1; } else { right = pos; } } if ((left == right) && cstrcasecmp(keywords[left].word, key, len) == 0) { return keywords[left].type; // 命中 } else { return CHAR_NULL; // 沒有命中 }}

推薦閱讀:

TAG:語義分析 | SQL | 網路安全 |