如何分析SQL注入語義分析庫Libinjection,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
這次主要講開源SQL注入語義分析庫libinjection,如果有發現其他開源SQL語義分析庫的歡迎告知。libinjection的程序分析由Simon友情提供,需要看完整報告的可以加群看。

從流程圖上看,libinjection首先是初始化issqlii變量,接著設置數據結構并初始化變量state,libinjection_sqli_init()函數將初始化SQL檢測所需的結構體,之后通過libinjection_is_sqli()函數進行具體分析,如果存在issqli,則將SQL注入識別特征復制進fingerprint變量并返回,如果不存在則將fingerprint變量設置為空并返回。

上圖是總的函數關系圖,libinjection_sqli_init()函數的主要工作是將 SQL注入識別特征碼(指紋)加載進結構體,并完成各種內置變量的初始化。libinjection_is_sqli()的處理代碼如下,根據代碼來分析
int libinjection_is_sqli(struct libinjection_sqli_state * sql_state)
{
const char *s = sql_state->s;
size_t slen = sql_state->slen;
if (slen == 0) {
return FALSE;
}
libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_ANSI);
if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
sql_state->fingerprint, strlen(sql_state->fingerprint))) {
return TRUE;
} else if (reparse_as_mysql(sql_state)) {
libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_MYSQL);
if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
sql_state->fingerprint, strlen(sql_state->fingerprint))) {
return TRUE;
}
}
if (memchr(s, CHAR_SINGLE, slen)) {
libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI);
if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
sql_state->fingerprint, strlen(sql_state->fingerprint))) {
return TRUE;
} else if (reparse_as_mysql(sql_state)) {
libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL);
if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
sql_state->fingerprint, strlen(sql_state->fingerprint))) {
return TRUE;
}
}
}
if (memchr(s, CHAR_DOUBLE, slen)) {
libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL);
if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
sql_state->fingerprint, strlen(sql_state->fingerprint))) {
return TRUE;
}
}
return FALSE;
}1.判斷用戶輸入的字符串長度是否合法,為零則返回FALSE。(即沒有發現SQL注入)
2.執行SQL注入識別函數(libinjection_sqli_fingerprint,無引號,標準SQL語法),獲取字符串識別特征碼
3.執行結構體內的查詢函數(這里為libinjection_sqli_lookup_word,二分查找算法),對比第二步獲取的識別特征是否與SQL注入識別特征匹配。
4.如果第三步發現SQL注入特征匹配結果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結構體,
5.如果檢測失敗,則調用reparse_as_mysql()函數判斷是否存在“(dash-dash-[notwhite]) 注釋”或“'#' 運算符號”,如果存在則再次執行SQL識別函數(libinjection_sqli_fingerprint,無引號,MYSQL語法),
6. 同時執行結構體的分析函數(libinjection_sqli_lookup_word,二分查找算法)進行特征匹配檢測,如果結果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結構體。
7.如果前面的判斷沒有返回結果,將掃描參數(即用戶輸入的字符串)查找是否存在單
引號。如果為真接著重復上述檢測步驟。
8.如果前面的判斷依舊沒有返回結果,將掃描參數(即用戶輸入的字符串)查找是否存
在雙引號。如果為真則接著執行SQL注入識別函數
(libinjection_sqli_fingerprint,雙引號,MYSQL語法)
同時執行結構體的分析函數(libinjection_sqli_lookup_word,二分查找算法)進行特征匹配檢測結果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結構體。
9.如果前面三種判斷均無結果則默認該參數(用戶輸入的字符串)不存在SQL注入。
上面已經對libinjection的程序進行了簡單的分析,下面通過一個具體的例子來了解libinjecton的處理流程。
首先來看libinjection對特征碼的定義
typedef enum {
TYPE_NONE = 0 /*無實際意義,僅對位數進行填充*/
, TYPE_KEYWORD = (int)'k' /*例如COLUMN,DATABASES,DEC等會被識別為該值*/
, TYPE_UNION = (int)'U' /*EXCEPT,INTERSECT,UNION等會被識別為該值*/
, TYPE_GROUP = (int)'B' /*GROUP BY,LIMIT,HAVING*/
, TYPE_EXPRESSION = (int)'E' /*INSERT,SELECT,SET*/
, TYPE_SQLTYPE = (int)'t' /*SMALLINT,TEXT,TRY*/
, TYPE_FUNCTION = (int)'f' /*UPPER,UTL_HTTP.REQUEST,UUID*/
, TYPE_BAREWORD = (int)'n' /*WAITFOR,BY,CHECK*/
, TYPE_NUMBER = (int)'1' /*所有數字會被識別為1*/
, TYPE_VARIABLE = (int)'v' /*CURRENT_TIME,LOCALTIME,NULL*/
, TYPE_STRING = (int)'s' /*單引號和雙引號*/
, TYPE_OPERATOR = (int)'o' /*+=,-=,!>*/
, TYPE_LOGIC_OPERATOR = (int)'&' /*&&,AND,OR*/
, TYPE_COMMENT = (int)'c' /*注釋符*/
, TYPE_COLLATE = (int)'A' /* COLLATE*/
, TYPE_LEFTPARENS = (int)'('
, TYPE_RIGHTPARENS = (int)')' /* not used? */
, TYPE_LEFTBRACE = (int)'{'
, TYPE_RIGHTBRACE = (int)'}'
, TYPE_DOT = (int)'.'
, TYPE_COMMA = (int)','
, TYPE_COLON = (int)':'
, TYPE_SEMICOLON = (int)';'
, TYPE_TSQL = (int)'T' /* TSQL start */ /*DECLARE,DELETE,DROP*/
, TYPE_UNKNOWN = (int)'?'
, TYPE_EVIL = (int)'X' /* unparsable, abort */ /* “/*!*/” */
, TYPE_FINGERPRINT = (int)'F' /* not really a token */
, TYPE_BACKSLASH = (int)'\\'
} sqli_token_types;libinjection將輸入的數據依據上述的定義進行轉換,之后就會得到SQL注入識別特征,或者說指紋,然后通過二分查找算法,在特征庫中進行匹配,匹配到則報SQL注入漏洞。
例如:
我們輸入SQL注入的檢測語句
‘ and 1=1
libinjection會將其轉換為s&1,其中單引號依據定義被轉換為s,and被轉換為&,數字被轉換為1
' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL--
libinjection會將其轉換為sUEvc,其中單引號依據定義被轉換為s,UNION ALL被轉換為U,SELECT被轉換為E,NULL被轉換為v,后面相同的NULL合并為一個v,--注釋符被轉換為c
libinjection在轉換完后,通過二分查找算法對內置的8000多個特征進行匹配,匹配到則將SQL注入識別特征復制進fingerprint變量并返回。
通過上述兩個例子就可以知道libinjection對數據的轉換邏輯,其中針對一些特殊情況會有特殊處理,文章篇幅有限這里不講,有興趣可以去看代碼。
SQL注入語義分析庫libinjection相比傳統正則匹配識別SQL注入的好處在于速度快以及低誤報,低漏報 。
速度快體現在該庫全程比較耗性能的就一二分查找算法,相對于正則對性能的消耗來說可以忽略不計,這點從火焰圖上可以很明顯的看出來,所以無論特征數是800,8000還是80000,對處理速度來說都不會有太大影響,而正則匹配規則達到千條以上就能明顯感覺到性能的變化。
低誤報呢,以前在測試modsecurity2.0的owasp規則的時候,那個誤報率簡直感人。但是如果要把規則寫細,降低誤報率的話,那規則數必然會上去進而對性能產生一些影響。SQL注入語義好就好在,要想滿足他的匹配規則,一般來說必須滿足三個特征以上,比如s&1或者sUEvc,而每個特征要么是特殊字符,要么是SQL語句的保留字,所以正常情況下用戶輸入,很少會出現這種誤報這種情況。
關于如何分析SQL注入語義分析庫Libinjection問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。