咱們都知道,學安全,懂SQL注入是重中之重,由於即便是如今SQL注入漏洞依然存在,只是相對於以前如今挖SQL注入變的困難了。並且知識點比較多,因此在這裏總結一下。經過構造有缺陷的代碼,來理解常見的幾種SQL注入。本文只是講解幾種注入原理,沒有詳細的利用過程。
若是想要了解Access的詳細手工注入過程,能夠看個人這篇文章http://www.javashuo.com/article/p-kgpywxsu-nb.html
若是想要了解MySQL的詳細手工注入過程,能夠看個人這篇文章http://www.javashuo.com/article/p-nmtkbjqi-nb.html
若是想要了解SQL server的詳細手工注入過程,能夠看個人這篇文章http://www.javashuo.com/article/p-uhllaflr-nb.htmlphp
SQL注入漏洞的產生須要知足兩個條件html
先看代碼前端
<?php $con=mysqli_connect("localhost","root","XFAICL1314","dvwa"); #鏈接數據庫,我這裏直接鏈接了dvwa的數據庫 if(mysqli_connect_error()) { echo "鏈接失敗:" .mysqli_connect_error(); } $id=$_GET['id']; $result=mysqli_query($con,"select * from users where `user_id`=".$id); $row=mysqli_fetch_array($result); echo $row['user'] . ":" . $row['password']; echo "<br>"; ?>
在union注入頁面中,程序獲取GET參數id,對用戶傳過來的id值沒有進行過濾,直接拼接到SQL語句中,在數據庫中查詢id對應的內容,並將這一條查詢結果中的user和password 輸出到頁面。進行union注入攻擊前提是頁面有回顯。
而後就是注入的常規思路,判斷類型,判斷字段數,使用union查詢相關數據。mysql
先看代碼web
<?php $con=mysqli_connect("localhost","root","XFAICL1314","dvwa"); if(mysqli_connect_error()) { echo "鏈接失敗:" .mysqli_connect_error(); } $id=$_GET['id']; if(preg_match("/union|sleep|benchmark/i",$id)){ exit("on"); } $result=mysqli_query($con,"select * from users where `user_id`=".$id); $row=mysqli_fetch_array($result); if ($row) { exit("yes"); } else{ exit("no"); } ?>
在布爾盲注頁面中,程序先獲取GET參數id,經過preg_match()函數判斷其中是否存在union sleep benchmark等危險字符。而後將參數id拼接到SQL語句,從數據庫查詢,若是有結果,返回yes,不然返回no。因此訪問這個頁面,代碼根據查詢結果返回只返回yes和no,不返回數據庫中的任何結果,因此上一種的union注入在這裏行不通。嘗試利用布爾盲注。
布爾盲注是指構造SQL判斷語句,經過查看頁面的返回結果來推測哪些SQL判斷是成立的。例如,咱們能夠判斷數據庫名的長度構造語句以下。
and length(database())>=1 #依次增長,查看返回結果
經過上面的語句咱們能夠猜到數據庫名長度爲4。
接着使用逐字符判斷的方式獲取數據庫庫名,數據庫庫名範圍通常都是az,字母09。構造語句以下。
and substr(database(),1,1)=要猜解的字母(轉換成16進制)
substr是截取的意思,構造語句的含義是,截取database()的值,從第一個開始,每次返回一個。這裏要注意,要和limit語句區分開,limit從0開始排序,substr從1開始排序。由於我知道數據庫的第一個字母是d,因此直接換成d,轉換成16進制就是0x64。結果以下。
在真實環境中,本身手工的話,工做量有點大,能夠藉助burp的爆破功能爆破要猜解的字母。
一樣,也能夠利用substr()來猜解表名和字段。構造語句
and substr((select table_name from information_schema.tables where table_schema=庫名 limit 0,1),1,1)=要猜解的字母(這裏指表名)
用這樣的方法,能夠猜解出全部的表名和字段,手工會累死,能夠藉助burp或者sqlmap。sql
先看代碼數據庫
<?php $con=mysqli_connect("localhost","root","XFAICL1314","dvwa"); if (mysqli_connect_error()) { echo "鏈接失敗:".mysqli_connect_error(); } $id=$_GET['id']; if($result=mysqli_query($con,"select *from users where `user_id`=".$id)) { echo "ok"; }else{ echo mysqli_error($con); } ?>
查看代碼,在報錯注入頁面中,程序獲取GET參數id後,將id拼接到SQL語句中查詢,若是執行成功,就輸出ok,若是出錯,就經過echo mysqli_error($con)將錯誤信息輸出到頁面。咱們能夠利用這種錯誤回顯,經過updatexml()、floor()等函數將咱們要查詢的內容顯示到頁面上。
例如,咱們經過updatexml()獲取user()的值,構造以下語句。
and updatexml(1,concat(0x7e,(select user()),0x7e),1) #0x7e是~16進制編碼
發現查詢出了user()的值
一樣,咱們也能夠查詢出database()的值
and updatexml(1,concat(0x7e,(select database()),0x7e),1) #0x7e是~16進制編碼
查詢出了數據庫名
咱們能夠用這種方法查詢出剩下的全部表名和字段,只須要構造相關的SQL語句就能夠了。後端
先看代碼安全
<?php $con=mysqli_connect("localhost","root","XFAICL1314","dvwa"); if (mysqli_connect_error()) { echo "鏈接失敗:".mysqli_error(); } $id=$_GET['id']; if (preg_match("/union/i",$id)){ exit("<html><body>no</body></html>"); } $result=mysqli_query($con,"select * from users where `user_id`=".$id); $row=mysqli_fetch_array($result); if ($row){ exit("<html><body>yes</body></html>"); } else{ exit("<html><body>no</body></html>"); } ?>
查看代碼,在時間盲注頁面中,程序獲取GET參數id,經過preg_match()函數判斷是否存在union危險字符,而後將id拼接到SQL語句中,並帶入數據庫查詢。若是有結果返回yes,沒有結果返回no。不返回數據庫中的任何數據。
它與布爾盲注的不一樣在於,時間盲注是利用sleep()或benchmark()等函數讓執行時間變長。通常和if(expr1,expr2,expr3)結合使用,這裏的if語句的含義爲若是expr1爲真,則if()返回expr2,不然返回expr3。因此判斷數據庫的長度,我們構造的語句以下
if (length(database())>3,sleep(5),1) #判斷數據庫長度,若是大於3,休眠5秒,不然查詢1
由上面圖片,咱們經過時間能夠判斷出,數據庫的長度爲4。
獲得長度後,經過substr()來查詢數據庫的第一個字母,這裏和布爾盲注很相似,構造以下語句。
and if (substr(database(),1,1)=庫的第一個字母,sleep(5),1)
依次進行猜解。依次類推,能夠猜解出數據庫完整的庫名,表名,字段名和具體數據。手工的話依舊是一個浩大的工程,通常藉助工具。cookie
今天對union注入、布爾盲注、報錯注入、時間盲注的原理和代碼進行了簡單的分析。在第二篇文章中,會對堆疊注入、二次注入、寬字節注入、cookie注入等進行簡單的分析。 參考文獻:Web安全攻防