0x01 前言
前幾天看一些面經的時候,看到sql注入的二次注入,當時沒一下子反應過來,好家伙,趕緊再次去那個靶場sqli-labs/Less24復現一下二次注入。
0x02 什么是二次注入?
二次注入可以理解為,攻擊者構造的惡意數據存儲在數據庫后,惡意數據被讀取並進入到SQL查詢語句所導致的注入。防御者即使對用戶輸入的惡意數據進行轉義,當數據插入到數據庫中時被處理的數據又被還原,Web程序調用存儲在數據庫中的惡意數據並執行SQL查詢時,就發生了SQL二次注入。
也就是說一次攻擊造成不了什么,但是兩次配合起來就會早成注入漏洞。
0x03 注入條件
兩次注入分別是插入惡意數據、利用惡意數據
所以也就是滿足這兩個條件即可
- 用戶向數據庫插入惡意數據,即使后端對語句做了轉義,如mysql_escape_string、mysql_real_escape_string等函數
- 數據庫能夠將惡意數據取出
0x04 靶場實例
首先進入靶場,可以看到與其他靶場不同,這里多了忘記密碼和注冊密碼選項
嘗試常規post注入,未果。
這里看到后端源碼會發現使用了轉義函數mysql_real_escape_string,常規SQL注入流程無法走了
既然可以注冊賬戶那就去注冊一下,這里直接注冊admin'#
。
用注冊的賬號登錄進去后發現可以修改密碼
修改密碼這個模塊也可以利用,我們不妨想一下修改密碼后端實現的邏輯,使用的肯定是sql增刪改查中的改語句,於是猜想對應sql語句可能會是這樣
update users set password='$new_pass' where username='$user' and password='$old_pass';
(當然閉合方式不一定就是單引號,這里需要碰運氣吧。。)
如果我們注冊一個這樣的賬號 admin'#
上述sql語句就變成這樣
update users set password='$new_pass' where username='admin'# and password='$old_pass';
顯而易見,語句原義被破壞,本來修改的是admin'#
用戶的賬號和密碼,現在卻是變成了直接修改admin用戶的密碼!
那就隨便輸入個密碼123456修改后再拿它去嘗試登錄admin賬戶,發現成功登入。
說明數據庫中admin用戶的密碼已經被成功改為123456
0x05 如何防御二次注入?
- 對輸入一視同仁,無論輸入來自用戶還是存儲,在進入到 SQL 查詢前都對其進行過濾、轉義。
- 使用MySQLi參數化更新,事先編譯的PHP代碼能夠帶來高效的防護效果