一、介紹
1.什么是SQL注入?
sql 注入是一種將 sql 代碼添加到輸入引數中,傳遞到 sql 服務器決議并執行的一種攻擊手法,
2.SQL注入的原理
SQL 是操作資料庫資料的結構化查詢語言,網頁的應用資料和后臺資料庫中的資料進行互動時會采用 SQL,而 SQL 注入是將 Web 頁面的原 URL、表單域或資料包輸入的引數,修改拼接成 SQL 陳述句,傳遞給 Web 服務器,進而傳給資料庫服務器以執行資料庫命令,
3.形成SQL注入的原因
用戶輸入的資料被 SQL 解釋器執行,
4.SQL注入的危害
1、攻擊者未經授權可以訪問資料庫中的資料,盜取用戶的隱私以及個人資訊,造成用戶的資訊泄露,
2、通過操作資料庫對某些網頁進行篡改;
3、修改資料庫一些欄位的值,嵌入網馬鏈接,進行掛馬攻擊,
4、服務器被遠程控制,被安裝后門,可以對資料庫的資料進行增加或洗掉操作,例如私自添加或洗掉管理員賬號,
5、資料庫被惡意操作:資料庫服務器被攻擊,資料庫的系統管理員帳戶被篡改,
6、破壞硬碟資料,導致全系統癱瘓,
5.SQL注入基本知識
注:以下命令陳述句均基于 MySQL 資料庫
(1)增刪改查陳述句
增 Insert
基本語法 INSERT INTO 表名稱 VALUES (值1, 值2,....)
例子 insert into student(name,sex,age) values('張三',18,'男')
刪 delete
基本語法 DELETE FROM 表名稱 WHERE 列名稱 = 值
例子 delete from student where id=1
改 update
基本語法 UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值
列子 update student set name = '張三' where id=1
查 select
基本語法 SELECT 列名稱 FROM 表名稱
例子 select * from student
(2)系統函式
- version()——MySQL 版本
- user()——資料庫用戶名
- database()——資料庫名
- @@datadir——資料庫路徑
- @@version_compile_os——作業系統版本
(3)字串連接函式
concat(str1,str2,...)沒有分隔符地連接字串
concat_ws(separator,str1,str2,...)含有分隔符地連接字串
group_concat(str1,str2,...)連接一個組的所有字串,并以逗號分隔每一條資料
(4)一般流程
Mysql 有一個系統資料庫 information_schema,存盤著所有的資料庫的相關資訊,一般的, 我們利用該表可以進行一次完整的注入,以下為一般的流程,
猜資料庫
select schema_name from information_schema.schemata
猜某庫的資料表
select table_name from information_schema.tables where table_schema=’xxxxx’
猜某表的所有列
Select column_name from information_schema.columns where table_name=’xxxxx’
獲取某列的內容
Select *** from ****
二、分類
根據輸入引數分為:
- 數字型注入
- 字符型注入
根據注入技巧分為:
- 聯合注入
- 盲注
- 堆疊注入
- 報錯注入
- 二次注入
- 寬位元組注入
根據提交型別分為:
- GET 注入
- POST 注入
- COOKIE 注入
- HTTP 頭部注入
1.根據輸入引數分類的 SQL 注入
(1)數字型注入
我們經常可以看到這樣的 url http://xxx.com/users.php?id=1 基于此種形式的注入,一般被叫做數字型注入,這是因為其注入點 id 型別為數字,這一類的 SQL 陳述句原型一般為 select * from 表名 where id=1,
(2)字符型注入
我們有時又會看到這樣的 url http://xxx.com/users.php?name=admin 基于此種形式的注入,一般被叫做字符型注入,這是因為其注入點 name 型別為字串,這一類的 SQL 陳述句原型一般為 select * from 表名 where name='admin'
2.根據注入技巧分類的 SQL 注入
(1)聯合注入
什么是聯合注入?
聯合注入顧名思義,就是使用聯合查詢進行注入的一種方式,是一種高效的注入的方式,適用于有回顯同時資料庫軟體版本是5.0以上的 MYSQL 資料庫,
union 運算子介紹
UNION 運算子用于合并兩個或多個 SELECT 陳述句的結果集,請注意,UNION 內部的 SELECT 陳述句必須擁有相同數量的列,列也必須擁有相似的資料型別,同時,每條 SELECT 陳述句中的列的順序必須相同,
聯合注入演示
使用 sqli-labs less1 進行聯合注入的流程演示
爆資料庫
http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata--+

爆 security 資料庫的資料表
http://127.0.0.1/sqli-labs-master/Less-1/?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

爆 users 表的列
http://127.0.0.1/sqli-labs-master/Less-1/?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+

爆資料
http://127.0.0.1/sqli-labs-master/Less-1/?id=-1'union select 1,group_concat(username),3 from users--+

(2)盲注
什么是盲注?
盲注就是在注入程序中,獲取的資料不能回顯至前端頁面,此時我們需要利用一些方法進行判斷或嘗試,這個程序稱為盲注
盲注的分類
a.布爾盲注
什么是布爾盲注?
布爾盲注是指利用頁面回傳的對錯資訊來間接推測資料庫中的資訊的一種手段,(構造邏輯判斷)
適用條件:布爾盲注一般適用于頁面沒有回顯欄位(不支持聯合查詢),且 web 頁面回傳 True 或者 false 時,
常用函式
截取函式:left() right() substr() mid()
轉換函式:ascii() hex()
比較函式:if()
b.時間盲注
什么是時間盲注?
時間盲注又稱延時注入,指通過頁面執行的時間來判斷資料內容的注入方式,
什么時候使用?
當注入時,無論我們傳入什么值,網頁正常或報錯都顯示一種頁面時,那么網頁的是否正常顯示將不是我們用來判斷是否注入成功的依據,就要用基于時間的盲注,
方法:通過if判斷陳述句與 sleep 函式結合,通過網站訪問的回應時間來判斷sql陳述句的正確性
示例:if(left(database(),1)='s',0,sleep(3))
這段 payload 的含義是如果資料庫的第一位為's'時,網頁正常執行,否則延時3秒
c.報錯盲注
什么是報錯盲注?
是指通過構造特定的SQL陳述句,讓攻擊者想要查詢的資訊通過頁面的錯誤提示回顯出來的注入方式
什么時候使用:當正常的回顯注入無法顯示結果,網頁可以顯示報錯資訊時,就可以使用報錯注入
常見的報錯函式
1)floor 報錯注入
在進行報錯注入時,floor()函式一般需要與rand()、count()、group by聯用,
示例:
Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) a from information_schema.columns group by a
原理:
rand() 隨機產生0~1的數值,floor() 向下取整,所以 floor(rand()*2結果是0或1,
group by 用于分組,當同時執行count和group by函式時,MYSQL會創建一個虛擬表,虛擬表進行計數和分組,在執行group by陳述句的時候,group by陳述句后面的欄位會被運算兩次,
floor會報錯的原因就是group by在向臨時表插入資料時,插入重復主鍵導致的報錯,又因為報錯之前concat()里的陳述句已經執行過了,所以會直接爆出concat函式里執行后的結果
2)exp 報錯注入
示例:
select exp(~(select * FROM(SELECT USER())a))
原理:
exp()即為以e為底的對數函式,exp中的函式成功執行后回傳0,對0按位取反會回傳一個無符號的BIGINT值,所以會造成Double型資料溢位錯誤從而報錯,借此得到資料,
3)extractvalue 和 updatexml 報錯注入
示例:
extractvalue(1,concat(0x7e,(select @@version),0x7e))
updatexml(1,concat(0x7e,(select @@version),0x7e),1)
原理:
當使用 extractvalue(xml_frag, xpath_expr) 函式時,若 xpath_expr 引數不符合 xpath 格式,就會報錯,而 ~ 符號(ascii 編碼值:0x7e)是不存在 xpath 格式中的, 所以一旦在 xpath_expr 引數中使用 ~ 符號,就會產生 xpath syntax error (xpath語法錯誤),通過使用這個方法就可以達到報錯注入的目的,
updatexml同理
(3)堆疊注入
什么是堆疊注入?
顧名思義,堆疊注入就是將一堆 sql 陳述句疊加在一起執行,使用分號結束上一個陳述句再疊加其他陳述句一起執行,
堆疊注入產生的原因?
服務器在訪問資料端時使用了可同時執行多條 sql 陳述句的方法,比如 php 中的mysqli_multi_query()函式
聯合注入與堆疊注入的區別
union injection(聯合注入)也是將兩條陳述句合并在一起,兩者之間有什么區別么?區別就在于 union 或者 union all 執行的陳述句型別是有限的,可以用來執行查詢陳述句,而堆疊注入可以執行的是任意的陳述句,
堆疊注入演示
使用 sqli-labs 進行演示
可以直接構造如下的 payload:
http://127.0.0.1/sqli-labs-master/Less-38/index.php?id=1%27;insert%20into%20users(id,username,password)%20values%20(%2738%27,%27less38%27,%27hello%27)--+

打開 phpMyAdmin 可以看到 sql 陳述句被成功執行,用戶成功添加

(4)二次注入
什么是二次注入?
二次注入是指已存盤(資料庫、檔案)的用戶輸入被讀取后,再次進入到SQL查詢陳述句中導致的注入,
二次注入流程
第一步:插入惡意資料
第二步:參考惡意資料
二次注入演示
使用 sqli-labs less24 進行演示

查看當前用戶,可以看到 admin 的初始密碼為123

注冊用戶名為 admin’# 的賬號


登錄 admin’#,并修改密碼為 666666

如圖 admin 的密碼被修改

(5)寬位元組注入
什么是寬位元組?
當某字符的大小為一個位元組時,稱其字符為窄位元組.當某字符的大小為兩個位元組時,稱其字符為寬位元組.所有英文默認占一個位元組,漢字占兩個位元組
轉義函式介紹
為了過濾用戶輸入的一些資料,對特殊的字符加上反斜杠“\”進行轉義;Mysql中轉義的函式包括 addslashes,mysql_real_escape_string,mysql_escape_string 等,還有一種是配置magic_quote_gpc(魔術引號),不過 PHP 高版本已經移除此功能,
寬位元組注入原理
我們在注入程序中,輸入陳述句中的特殊字符會被 addslashes()這類轉義函式進行轉義,但 MySQL 采用了 gbk 編碼,會將兩個位元組看作一個漢字,例如,\ 的 URL 編碼是%5c 當用戶加上 %df 形成 %df%5c 資料庫會自動將 %df%5c 識別成漢字,從而將 \ 閉合,起到了繞過轉義的效果,這樣即可實作注入攻擊,
3.根據提交型別分類的 SQL 注入
(1)GET 注入
什么是 GET 注入?
GET 注入:通過 GE T傳參的方式,傳輸惡意陳述句,進行 SQL 注入
GE T注入介紹
提交資料的方式是 GET,注入點的位置在 GET 引數部分,比如有這樣的一個鏈接http://xxx.com/news.php?id=1,其中id是注入點,
(2)POST 注入
什么是 POST 注入?
POST注入:通過POST傳參的方式,傳輸惡意陳述句,進行SQL注入,本質和GET注入是一樣的
POST 注入介紹
使用 POST 方式提交資料,注入點位置在 POST 資料部分,常發生在表單中,
(3)COOKIE 注入
什么是 COOKIE 注入?
修改 cookie 的值進行注入的方式
COOKIE 注入介紹
HTTP請求的時候會帶上客戶端的Cookie,注入點存在Cookie當中的某個欄位中,
(4)HTTP 頭部注入
什么是 HTTP 頭部注入?
一般獲取頭部的資訊用于資料分析,通過請求頭部可以向資料庫發送查詢資訊,構造惡意陳述句可以對資料庫進行資訊查詢,
HTTP 頭部注入介紹
注入點在HTTP請求頭部的某個欄位中,比如存在User-Agent欄位中,嚴格講的話,Cookie其實應該也是算頭部注入的一種形式,因為在HTTP請求的時候Cookie是頭部的一個欄位,
三、繞過
關鍵字通用繞過思路
1. 雙寫繞過關鍵字過濾
2. 使用同義函式/陳述句代替
如if函式可用如下陳述句代替
case when condition then 1 else 0 end
3. 預處理,或其他手段造成字串拼接來繞過
1';set @a=concat("sel","ect * from users");prepare sql from @a;execute sql;
4. 大小寫變換
-1' UnIoN SeLeCt 1,2,database()--+
5. 編碼繞過
使用URL編碼對輸入陳述句進行加密,然后服務器端會對其進行解密,
6. 行內注釋繞過
行內注釋就是把一些特有的僅在MYSQL上的陳述句放在 /!.../ 中,這樣這些陳述句如果在其它資料庫中是不會被執行,但在MYSQL中會執行,
常見關鍵字繞過思路
1. and/or 被過濾/攔截
(1)雙寫anandd、oorr
(2)使用運算子代替&&、||
(3)直接拼接=號,如:?id=1=(condition)
(4)其他方法,如:?id=1^(condition)
2. 空格被過濾/攔截
(1)注釋繞過空格
示例:
select/**/user()/**/from/**/dual
(2)括號繞過空格
示例:select(group_concat(table_name))from(information_schema.taboles)where(tabel_schema=database());#
(3)Tab 代替空格
(4)使用兩個空格
(5)使?其他不可?字符代替空格
如 %09, %0a, %0b, %0c, %0d, %a0
3. 逗號被過濾/攔截
(1)改用盲注
(2)使用 join 陳述句代替
示例:
union select * from ((select 1)A join (select 2)B join (select 3)C);
(3)使用 substring 函式
substring(str FROM pos)
4. 單雙引號被過濾/攔截/轉義
(1)需要跳出單引號的情況:嘗試是否存在編碼問題而產生的SQL注入(寬位元組注入等)
(2)不需要跳出單引號的情況:字串可用十六進制表示、也可通過進制轉換函式表示成其他進制,
5. 比較符號(= < >)被過濾/攔截
(1)使用 in() 繞過
示例:
?id=' or substr((select database()),1,1) in('s')
(2)greatest,strcmp 等函式進行繞過
示例:
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
select strcmp(left(database(),1),0x32);#lpad('asd',2,0)
四、防御
SQL注入危害雖大,但是可以完全杜絕
1.嚴格的資料型別
在傳入引數的地方限制引數的型別,比如整型 Integer,隨后加入函式判斷,如is_numeric($_GET[‘id’]) 只有當 get 到的 id 為數字或者數字字符時才能執行下一步,但這種方法存在一定的限制,只能在特定的頁面才能使用,一般大部分都是要求我們傳入的字串,但可以很大程度限制整型注入的情況,
2.特殊字符轉義
數字型注入可以通過檢查資料型別防御,字符型則需要對特殊字符進行轉義,在 MySQL 中我們需要對" '進行轉義,這樣可以防止惡意攻擊者來閉合陳述句,我們通常使用 addslashes() 等安全函式來轉義特殊字符,
3.使用預編譯陳述句
當一條 SQL 陳述句執行前,需要先進行語法分析,如果沒有使用預編譯的方法來執行 SQL,那么每次在執行 SQL 時都需要先進行語法分析,然后再執行,此時進行 SQL 注入,惡意的代碼(payload)拼接上 SQL 陳述句之后才會進行語法分析,其中 payload 中包含的關鍵字等內容便會被識別,因此會被成功執行,
而預編譯則是先在待傳入引數的位置增加占位符(?),并對 SQL 陳述句進行語法分析和編譯,并將結果存入記憶體中等待呼叫,在呼叫時,傳入的引數會自動放入占位符的位置,并執行 SQL 陳述句,此時如果進行注入,由于并沒有重新進行語法分析,payload 中包含的關鍵字等不會被識別,而是作為字串的形式存在于陳述句中,因此 payload 不會成為 SQL 陳述句的一部分,
預編譯可以防止 sql 注入的原因:允許資料庫做引數化查詢,在使用引數化查詢的情況下,資料庫不會將引數的內容視為 SQL 執行的一部分,而是作為一個欄位的屬性值來處理,這樣就算引數中包含破環性陳述句(or ‘1=1’)也不會被執行,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/501175.html
標籤:其他
上一篇:Unity實作調色板
