如何分析SQL注入語義分析庫Libinjection,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
發(fā)展壯大離不開廣大客戶長期以來的信賴與支持,我們將始終秉承“誠信為本、服務(wù)至上”的服務(wù)理念,堅(jiān)持“二合一”的優(yōu)良服務(wù)模式,真誠服務(wù)每家企業(yè),認(rèn)真做好每個細(xì)節(jié),不斷完善自我,成就企業(yè),實(shí)現(xiàn)共贏。行業(yè)涉及成都加固等,在成都網(wǎng)站建設(shè)、成都全網(wǎng)營銷推廣、WAP手機(jī)網(wǎng)站、VI設(shè)計(jì)、軟件開發(fā)等項(xiàng)目上具有豐富的設(shè)計(jì)經(jīng)驗(yàn)。
這次主要講開源SQL注入語義分析庫libinjection,如果有發(fā)現(xiàn)其他開源SQL語義分析庫的歡迎告知。libinjection的程序分析由Simon友情提供,需要看完整報告的可以加群看。
從流程圖上看,libinjection首先是初始化issqlii變量,接著設(shè)置數(shù)據(jù)結(jié)構(gòu)并初始化變量state,libinjection_sqli_init()函數(shù)將初始化SQL檢測所需的結(jié)構(gòu)體,之后通過libinjection_is_sqli()函數(shù)進(jìn)行具體分析,如果存在issqli,則將SQL注入識別特征復(fù)制進(jìn)fingerprint變量并返回,如果不存在則將fingerprint變量設(shè)置為空并返回。
上圖是總的函數(shù)關(guān)系圖,libinjection_sqli_init()函數(shù)的主要工作是將 SQL注入識別特征碼(指紋)加載進(jìn)結(jié)構(gòu)體,并完成各種內(nèi)置變量的初始化。libinjection_is_sqli()的處理代碼如下,根據(jù)代碼來分析
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。(即沒有發(fā)現(xiàn)SQL注入)
2.執(zhí)行SQL注入識別函數(shù)(libinjection_sqli_fingerprint,無引號,標(biāo)準(zhǔn)SQL語法),獲取字符串識別特征碼
3.執(zhí)行結(jié)構(gòu)體內(nèi)的查詢函數(shù)(這里為libinjection_sqli_lookup_word,二分查找算法),對比第二步獲取的識別特征是否與SQL注入識別特征匹配。
4.如果第三步發(fā)現(xiàn)SQL注入特征匹配結(jié)果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結(jié)構(gòu)體,
5.如果檢測失敗,則調(diào)用reparse_as_mysql()函數(shù)判斷是否存在“(dash-dash-[notwhite]) 注釋”或“'#' 運(yùn)算符號”,如果存在則再次執(zhí)行SQL識別函數(shù)(libinjection_sqli_fingerprint,無引號,MYSQL語法),
6. 同時執(zhí)行結(jié)構(gòu)體的分析函數(shù)(libinjection_sqli_lookup_word,二分查找算法)進(jìn)行特征匹配檢測,如果結(jié)果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結(jié)構(gòu)體。
7.如果前面的判斷沒有返回結(jié)果,將掃描參數(shù)(即用戶輸入的字符串)查找是否存在單
引號。如果為真接著重復(fù)上述檢測步驟。
8.如果前面的判斷依舊沒有返回結(jié)果,將掃描參數(shù)(即用戶輸入的字符串)查找是否存
在雙引號。如果為真則接著執(zhí)行SQL注入識別函數(shù)
(libinjection_sqli_fingerprint,雙引號,MYSQL語法)
同時執(zhí)行結(jié)構(gòu)體的分析函數(shù)(libinjection_sqli_lookup_word,二分查找算法)進(jìn)行特征匹配檢測結(jié)果為真,則返回true,并將SQL注入識別特征匹配到的fingerprint寫入結(jié)構(gòu)體。
9.如果前面三種判斷均無結(jié)果則默認(rèn)該參數(shù)(用戶輸入的字符串)不存在SQL注入。
上面已經(jīng)對libinjection的程序進(jìn)行了簡單的分析,下面通過一個具體的例子來了解libinjecton的處理流程。
首先來看libinjection對特征碼的定義
typedef enum { TYPE_NONE = 0 /*無實(shí)際意義,僅對位數(shù)進(jìn)行填充*/ , 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' /*所有數(shù)字會被識別為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將輸入的數(shù)據(jù)依據(jù)上述的定義進(jìn)行轉(zhuǎn)換,之后就會得到SQL注入識別特征,或者說指紋,然后通過二分查找算法,在特征庫中進(jìn)行匹配,匹配到則報SQL注入漏洞。
例如:
我們輸入SQL注入的檢測語句
‘ and 1=1
libinjection會將其轉(zhuǎn)換為s&1,其中單引號依據(jù)定義被轉(zhuǎn)換為s,and被轉(zhuǎn)換為&,數(shù)字被轉(zhuǎn)換為1
' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL--
libinjection會將其轉(zhuǎn)換為sUEvc,其中單引號依據(jù)定義被轉(zhuǎn)換為s,UNION ALL被轉(zhuǎn)換為U,SELECT被轉(zhuǎn)換為E,NULL被轉(zhuǎn)換為v,后面相同的NULL合并為一個v,--注釋符被轉(zhuǎn)換為c
libinjection在轉(zhuǎn)換完后,通過二分查找算法對內(nèi)置的8000多個特征進(jìn)行匹配,匹配到則將SQL注入識別特征復(fù)制進(jìn)fingerprint變量并返回。
通過上述兩個例子就可以知道libinjection對數(shù)據(jù)的轉(zhuǎn)換邏輯,其中針對一些特殊情況會有特殊處理,文章篇幅有限這里不講,有興趣可以去看代碼。
SQL注入語義分析庫libinjection相比傳統(tǒng)正則匹配識別SQL注入的好處在于速度快以及低誤報,低漏報 。
速度快體現(xiàn)在該庫全程比較耗性能的就一二分查找算法,相對于正則對性能的消耗來說可以忽略不計(jì),這點(diǎn)從火焰圖上可以很明顯的看出來,所以無論特征數(shù)是800,8000還是80000,對處理速度來說都不會有太大影響,而正則匹配規(guī)則達(dá)到千條以上就能明顯感覺到性能的變化。
低誤報呢,以前在測試modsecurity2.0的owasp規(guī)則的時候,那個誤報率簡直感人。但是如果要把規(guī)則寫細(xì),降低誤報率的話,那規(guī)則數(shù)必然會上去進(jìn)而對性能產(chǎn)生一些影響。SQL注入語義好就好在,要想滿足他的匹配規(guī)則,一般來說必須滿足三個特征以上,比如s&1或者sUEvc,而每個特征要么是特殊字符,要么是SQL語句的保留字,所以正常情況下用戶輸入,很少會出現(xiàn)這種誤報這種情況。
關(guān)于如何分析SQL注入語義分析庫Libinjection問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。