前言
最近由于作業需要在看libinjection的原始碼,查到一位師傅發了一篇繞過libinjection的文章,
https://www.o2oxy.cn/2772.html
由于URL編碼和HEX編碼的問題,感覺這位師傅寫的不是很對,就發評論跟他討論,當然他整個libinjection的流程分析還是很不錯的,
討論了半天,這位師傅又拋出了一個payload,說libinjection也檢測不出來
1={date(if(mid((updatexml(1,concat(0x7e,(select user()),0x7e),1)),1,1)='1',2,1))}
嘗試了一下的確如此:

翻看MySQL語法分析的產生式
很久之前看到過這種注入的手法,當時沒有深究,這次打算好好研究一下,
mysql的SQL決議語法檔案:
https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L9899
(這個是yacc的產生式檔案,有興趣的師傅可以去找找lex&yacc的資料,順便看看編譯原理更佳~)
PS:開頭注釋表明5.7之后語法分析就沒有變過
看這個檔案懵逼了很久,最后直接搜索’{’(三個字符)找到了關鍵點:

'{' 標志符 運算式 '}'是simple_expr(簡單運算式)的一種,走PTI_odbc_date這個類的決議方法
https://github.com/mysql/mysql-server/blob/8.0/sql/parse_tree_items.cc#L619
通過注釋可以看出,該功能是為了決議ODBC的轉義形式語法而寫的,并且最后如果標志符部分不是d、t、ts,就會直接回傳運算式的內容,

實際上效果上來說,標志符部分可以任意寫,運算式部分都可以正常執行

所以可以嘗試通過這種形式進行SQL注入防御的繞過,
MySQL手冊相關
https://dev.mysql.com/doc/refman/8.0/en/expressions.html
https://downloads.mysql.com/docs/refman-4.1-en.a4.pdf
這塊感謝同事donky16師傅,實際上手冊中有寫這種用法,之前搜關鍵詞braces和curly brackets,就是沒搜curly braces,,,,:

上面那波分析,多少有點走彎路了,
從手冊中可以看出,從3.23開始就已經存在了ODBC轉義語法,
回到Payload
1={date(if(mid((updatexml(1,concat(0x7e,(select user()),0x7e),1)),1,1)='1',2,1))}
payload中,date并不代表一個函式,而是一個識別符號, 后面整個括號包裹的if部分是運算式,并且可以不適用括號分割而,轉而使用空格之類的進行分割:


可以看到兩個效果是一樣的,都可以正常觸發報錯,說明updatexml函式已經被執行了,
但是后一種寫法是可以被libinjection檢測出來的:

而libinjection中實際上已經考慮了ODBC轉義的情況:

原因分析
libinjection中有種token型別為bareword
bareword可能被認為:label 、 句柄 、函式 、 普通字串
libinjection特定位置上只有非關鍵字串列(方法名、變數名、select union之類的關鍵字)才會被認為是bareword,
在libjection的token折疊函式中,’{’+BAREWORD的組合會進行折疊,而像’{date’這種形式會被決議成’{’+FUNCTION的Token串,不會被折疊導致了繞過,
{foo expr}
而在ODBC轉義語法的語境中,上述foo位置都會被認為是識別符號或者說bareword,
所以此處解決辦法有兩個:
- 加特征,將’{’+FUNCTION的情況包進去
- 優化折疊代碼,考慮’{’+FUNCTION的情況
最后選用了第二種方法進行完善,可以正常的檢測出來該SQL注入:

參考內容
libinjection原始碼(語意分析SQL注入檢測):
https://github.com/client9/libinjection
感謝這位師傅,漲知識了~:
https://www.o2oxy.cn/2772.html
MySQL原始碼:
https://github.com/mysql/mysql-server/
MySQL手冊:
https://dev.mysql.com/doc/refman/8.0/en/expressions.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/78701.html
標籤:其他
