1 背景
京東SRC(Security Response Center)收錄大量外部白帽子提交的sql注入漏洞,漏洞發生的原因多為sql陳述句拼接和Mybatis使用不當導致,

2 手工檢測
2.1 前置知識
mysql5.0以上版本中存在一個重要的系統資料庫information_schema,通過此資料庫可訪問mysql中存在的資料庫名、表名、欄位名等元資料,information_schema中有三個表成為了sql注入構造的關鍵,
1)infromation_schema.columns:
- table_schema 資料庫名
- table_name 表名
- column_name 列名
2)information_schema.tables
- table_schema 資料庫名
- table_name 表名
3)information_schema.schemata
- schema_name 資料庫名
SQL注入常用SQL函式
- length(str) :回傳字串str的長度
- substr(str, pos, len) :將str從pos位置開始截取len長度的字符進行回傳,注意這里的pos位置是從1開始的,不是陣列的0開始
- mid(str,pos,len) :跟上面的一樣,截取字串
- ascii(str) :回傳字串str的最左面字符的ASCII代碼值
- ord(str) :將字符或布爾型別轉成ascll碼
- if(a,b,c) :a為條件,a為true,回傳b,否則回傳c,如if(1>2,1,0),回傳0
2.2 注入型別
2.2.1 引數型別分類
-
整型注入
例如?id=1,其中id為注入點,型別為int型別, -
字符型注入
例如?id=”1”,其中id為注入點,型別為字符型,要考慮閉合后端sql陳述句中的引號,
2.2.2 注入方式分類
- 盲注
-
- 布爾盲注:只能從應用回傳中推斷陳述句執行后的布林值,
-
- 時間盲注:應用沒有明確的回顯,只能使用特定的時間函式來判斷,例如sleep,benchmark等,
- 報錯注入:應用會顯示全部或者部分的報錯資訊
- 堆疊注入:有的應用可以加入 ; 后一次執行多條陳述句
- 其他
2.3 手動檢測步驟(字符型注入為例)
// sqli vuln code Statement statement = con.createStatement(); String sql = "select * from users where username = '" + username + "'"; logger.info(sql); ResultSet rs = statement.executeQuery(sql); // fix code 如果要使用原始jdbc,請采用預編譯執行 String sql = "select * from users where username = ?"; PreparedStatement st = con.prepareStatement(sql);
使用未預編譯原始jdbc作為demo,注意此demo中sql陳述句引數采用單引號閉合,
2.3.1 確定注入點
對于字符型別注入,通常先嘗試單引號,判斷單引號是否被拼接到SQL陳述句中,推薦使用瀏覽器擴展harkbar作為手工測驗工具,https://chrome.google.com/webstore/detail/hackbar/ginpbkfigcoaokgflihfhhmglmbchinc
正常頁面應該顯示如下:

admin后加單引號導致無資訊回顯,原因是后端sql執行報錯,說明引號被拼接至SQL陳述句中


select * from users where username = 'admin' #正常sqlselect * from users where username = 'admin'' #admin'被帶入sql執行導致報錯無法顯示資訊
2.3.2 判斷欄位數
mysql中使用order by 進行排序,不僅可以是欄位名也可以是欄位序號,所以可以用來判斷表中欄位數,order by 超過欄位個數的數字就會報錯,

判斷欄位數
當order by 超過4時會報錯,所以此表共四個欄位,

后端所執行的sql陳述句
select * from users where username = 'admin' order by 1-- '
此處我們將原本username的值admin替換為admin’ order by 1 —+,其中admin后的單引號用于閉合原本sql陳述句中的前引號,—+用于注釋sql陳述句中的后引號,—后的+號主要作用是提供一個空格,sql陳述句單行注釋后需有空格,+會被解碼為空格,
2.3.3 確定回顯位置
主要用于定位后端sql欄位在前端顯示的位置,采用聯合查詢的方式確定,注意聯合查詢前后欄位需一致,這也就是我們為什么做第二步的原因,
通過下圖可知,后端查詢并回顯的欄位位置為2,3位,

聯合查詢后的欄位可以隨意,本次采用的是數字1到4直觀方便,

2.3.4 利用information_schema庫實作注入
group_concat()函式用于將查詢結果拼接為字串,
- 查看存在資料庫

- 查看當前資料庫中的表

- 查看指定表中欄位

- 利用以上獲取資訊讀取users表中username和password

3 自動化檢測
3.1 sqlmap 使用
sqlmap兼容python2和python3,可以自動化檢測各類注入和幾乎所有資料庫型別,
3.1.1 常用命令
-u 可能存在注入的url鏈接 -r讀取http資料包 --data 指定post資料 --cookie 指定cookie --headers 指定http頭 如采用token認證的情況下 --threads 指定執行緒數 --dbms 指定后端的資料庫 --os 指定后端的作業系統型別 --current-user 當前用戶 --users 所有用戶 --is-dba 是否是dba --sql-shell 互動式的sqlshell -p指定可能存在注入點的引數 --dbs 窮舉系統存在的資料庫 -D指定資料庫 --tables 窮舉存在的表 -T指定表 --column 窮舉欄位 -C指定欄位 --dump dump資料
直接檢測
其中—cookie用于指定cookie,—batch 自動化執行,—dbms指定資料庫型別

檢測結果

讀取系統中存在資料庫
—dbs讀取當前用戶下的資料庫

讀取指定庫下的表
-D java_sec_code —tables

dump users表資料
-D java_sec_code -T users —dump

4 進階
4.1 Mybatis注入
1)$錯誤使用導致注入
//采用#不會導致sql注入,mybatis會使用預編譯執行 @Select("select * from users where username = #{username}") User findByUserName(@Param("username") String username); //采用$作為入參可導致sql注入 @Select("select * from users where username = '${username}'") List<User> findByUserNameVuln01(@Param("username") String username);
2)模糊查詢拼接
//錯誤寫法 <select id="findByUserNameVuln02" parameterType="String" resultMap="User"> select * from users where username like '%${_parameter}%' </select> //正確寫法 <select id="findByUserNameVuln02" parameterType="String" resultMap="User"> select * from users where username like concat(‘%’,#{_parameter}, ‘%’) </select>
3)order by 注入
order by 后若使用#{}會導致報錯,因為#{}默認添加引號會導致找不到欄位從而報錯,
//錯誤寫法 <select id="findByUserNameVuln03" parameterType="String" resultMap="User"> select * from users <if test="order != null"> order by ${order} asc </if> </select> //正確寫法 id指欄位id 此表欄位共四個 所以id為1-4 <select id="OrderByUsername" resultMap="User"> select * from users order by id asc limit 1 </select>
5 文章及資料推薦
slqmap手冊:https://octobug.gitbooks.io/sqlmap-wiki-zhcn/content/Users-manual/Introduction.html
sql注入詳解:http://sqlwiki.radare.cn/#/
作者:羅宇(物流安全小分隊)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/502777.html
標籤:MySQL
