開篇:
最近學習了libinjection庫的sql注入部分,寫篇總結。libinjection在GitHub上作為一個開源的sql注入和xxs攻擊詞法解析庫還是挺流行的,它比較獨特的是沒有使用正則表達式而是一個完善的特征庫來匹配檢查SQL注入。相比傳統正則匹配識別SQL注入在於速度快以及低誤報,低漏報 。
然后就是來自開發者的牛B:
No memory allocation
No threads
No external dependencies
Fixed stack size
>100k checks a second
簡單介紹下SQL注入:
SQL注入攻擊就是通過操作輸入來修改SQL語句,用以達到執行代碼對WEB服務器進行攻擊的方法。 在post/getweb表單、輸入域名或頁面請求的查詢字符串中插入SQL命令,最終使web服務器執行惡意命令的過程。
Web頁面:
后台數據庫查詢:
----> select * from users where username = '輸入' and password = '輸入'
用戶惡意輸入
-----> admin' and 1 = 1; --
SQL語句改變:
---> select * from users where username = 'admin' and 1 = 1; --and password = '輸入'
正文:
libinjection將輸入的數據依據它定義好的特征碼進行轉換, 之后就會得到SQL注入識別特征,或者說指紋, 在特征庫中進行匹配。
這個庫的簡單例子:
源代碼:
#include <stdio.h> #include <strings.h> #include <errno.h> #include "libinjection.h" #include "libinjection_sqli.h" int main(int argc, const char* argv[]) { struct libinjection_sqli_state state; int issqli; const char* input = argv[1]; size_t slen = strlen(input); /* in real-world, you would url-decode the input, etc */ libinjection_sqli_init(&state, input, slen, FLAG_NONE); issqli = libinjection_is_sqli(&state); if (issqli) { fprintf(stderr, "sqli detected with fingerprint of '%s'\n", state.fingerprint); } return issqli; }
編譯運行:
$ gcc -Wall -Wextra examples.c libinjection_sqli.c $ ./a.out "-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" sqli detected with fingerprint of 's&1UE'
接下來介紹一下重要的結構體
----------------------------------------------------------------------------------
解析函數的定義:
typedef size_t (*pt2Function)(sfilter *sf);
static const pt2Function char_parse_map[] = {
&parse_white, /* 0 */
&parse_white, /* 1 */
&parse_white, /* 2 */
&parse_white, /* 3 */
&parse_white, /* 4 */
&parse_white, /* 5 */
&parse_white, /* 6 */
....
&parse_word, /* 252 */
&parse_word, /* 253 */
&parse_word, /* 254 */
&parse_word, /* 255 */
};
這里可以看出有255個解析函數,作為一個程序員應該對這個數字很敏感,剛好一個字節。這里其實會根據你輸入的字符串的字節選擇解析函數;對什么標點符號啊,字母啊,數字和運算符
之類的都有不同的函數處理可以說這種處理方式是很巧妙的。
這里我舉個例子:
-1' and 1=1 union/* foo */select load_file('/etc/passwd')--
你輸入這個字符串,解析按空格分隔開,這里比較重要的點是沒有閉合 ’或“也按字符串處理 -1' 轉換為特征碼s(string);
第二個字串 and 關鍵字 特征碼為 &;
1 = 1這里比較特殊它按數字來轉了(具體可以跟代碼來深入研究) 特征碼為 1;
union 關鍵字聯合查詢 特征碼為 U;
select 關鍵字特征碼為 E;
所以合起來就是s&1UE;
你可以參考下面這個表來推其他類型的特征碼
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_sqli_init()函數將初始化SQL檢測所需的libinjection_sqli_state結構體,這個結構體在后面十分重要。
libinjection_is_sqli()函數主要功能函數,判斷是否為sql注入,返回bool結果
libinjection_sqli_lookup_word()函數從特征庫查找,與生成指紋是否匹配
libinjection_sqli_fingerprint()函數生成SQL語句指紋
結束:
libinjection庫是對payload進行解析的,簡單來說是對用戶輸入進行監控,查找用戶輸入是否有構成SQL注入的可能;還有一點就是它的特征庫是允許用戶修改的(關注 src/fingerprints.txt ),增加或刪除,因此可以定制和完善屬於你自己的SQL注入特征庫。以及使用這個庫的產品 ------------ 開源防火牆ModSecurity。