![90763f680a782ede24c6638aa5dac6e2.png](https://i-blog.csdnimg.cn/blog_migrate/db21bef56eefd67f0248a7276de61170.jpeg)
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;
}
将所有 tokenvec
的 type
记录在指纹 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' : '0';
} 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] = '0';
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; // 没有命中
}
}