iT邦幫忙

2026 iThome 鐵人賽

DAY 14
1
Security

《朝 HTB CPTS 前進:資安新手的 30 天實作筆記》系列 第 14 篇

Day 14 — 兩週回顧 & SQL Injection 補強:搞懂 INFORMATION_SCHEMA,自己把資料撈出來

  • 分享至 

  • xImage
  •  

Day 14 了!!不知不覺過了兩週!!!

說實話,沒想到自己可以走那麼遠 xddd

每天幾乎都會遇到卡關,但為了順利交出鐵人賽,必須要努力解決><從中真的是大進步!!!

Web 漏洞部分,因為時間比較緊湊,目前只有實作到 SQL Injection 跟 Command Injection QQ。但對於滲透測試的流程、思路、Linux 提權等等,過了兩週,功力真的大進步!!!

其他常見的 Web 漏洞像 IDOR、XSS、LFI、RFI、SSRF、CSRF、File Upload等雖然很重要,但 CPTS 考試還有 AD、Windows 靶機這些更複雜的區塊也是重點,所以其他 Web 漏洞,我們就等之後有時間再一起練習!


但 Day 12 有一件事情,我還是有點心虛 😂

Day 12 的方法二,我們是利用資料庫的欄位資訊,把未上架的產品列出,來成功闖關。

當時雖然成功解題了

但:information_schema 真的懂了嗎?

……老實說,沒有 xddd

比較像是當下有一些想法,再搭配 AI 一起摸索,最後是有把題目解出來沒錯,但其實自己沒有真的搞懂 xddd

如果現在問我:

「資料庫裡到底有哪些 Table?我要怎麼知道?」

我可能還是會先:恩......讓我想想

所以今天就趁這個機會,把 information_schema 好好搞懂。

不只是知道「這樣下 SQL 可以解題」,而是要能靠自己做到:

資料庫裡有哪些資料表? → 查 INFORMATION_SCHEMA.TABLES
這張資料表有哪些欄位? → 查 INFORMATION_SCHEMA.COLUMNS
知道資料表名跟欄位名 → SELECT 撈出資料

這樣下次再遇到類似的 SQL Injection,才不會又變成:

AI:你可以這樣下
我:喔喔好 🤣

而需要達到這樣的功力,不能靠背的,必須要真的理解!


SQL Injection 補強:從 information_schema 到撈出資料

在開始練習,強化實作能力之前,先把幾個基礎觀念強化一下!

先搞懂:資料庫長什麼樣子

要搞懂 SQL Injection,以及要怎麼利用 information_schema 找到想要的資料,得先知道資料庫裡面的東西是怎麼放的~

一起想像一下:資料庫就像是 Excel。

用一個假設的學校系統來看整個資料庫長什麼樣子:

┌──────────────────────────────────────────────────┐
│           📁 學校資料庫                            │
│                                                  │
│  ┌───────────────┐  ┌───────────────┐            │
│  │ 📋 通訊錄      │  │ 📋 成績單      │            │
│  │ 存學生的聯絡方式│  │ 存每個人的考試成績│           │
│  ├───────────────┤  ├───────────────┤            │
│  │ id            │  │ id            │            │
│  │ 姓名          │  │ 學生名        │            │
│  │ 電話          │  │ 科目          │            │
│  │ Email         │  │ 分數          │            │
│  └───────────────┘  └───────────────┘            │
│                                                  │
│  ┌───────────────┐  ┌───────────────┐            │
│  │ 📋 教師名單    │  │ 📋 帳號密碼    │ ⬅ 是寶藏!!!     │
│  │ 存老師跟教哪科  │  │ 存登入用的帳密  │            │
│  ├───────────────┤  ├───────────────┤            │
│  │ id            │  │ id            │            │
│  │ 老師名        │  │ username      │            │
│  │ 科目          │  │ password      │            │
│  └───────────────┘  └───────────────┘            │
└──────────────────────────────────────────────────┘

一個資料庫裡面可以有好幾張資料表(Table),每張資料表裡面又可以有好多欄位(Column)。
SQL Injection 的目標就是:
先找到資料庫裡有哪些資料表 → 找到目標資料表 → 找出裡面的欄位 → 再把想看的資料撈出來。

把其中一張資料表打開來看,就像 Excel 工作表:

通訊錄 這張「工作表」:
 
欄位 →  id | 姓名    | 電話          | Email
資料 →  1  | Kitty   | 0912-345-678  | kitty@example.com
資料 →  2  | Kuromi  | 0922-111-222  | kuromi@example.com
  • 資料表(Table) 就像 Excel 的一個工作表(Sheet)
  • 欄位(Column) 就是直行的標題——id、姓名、電話、Email
  • 資料(Row) 就是橫列的每一筆——Kitty 那一列、Kuromi 那一列
    這樣就能理解,SQL Injection 最後一步在做的事:我們知道了資料表名叫 通訊錄、欄位有 姓名 跟 Email,就能寫 SELECT 姓名, Email FROM 通訊錄 把資料撈出來。

但問題是——我們一開始連「有一張資料表叫通訊錄」都不知道。所以要從更外面的層級開始問起。

資料庫(Database)——裝很多張資料表的容器

就像上面那張圖,一個資料庫裡面會有好幾張資料表——通訊錄、成績單、教師名單、帳號密碼⋯⋯我們要做的就是找出有哪些資料表,然後鎖定最香的那張(像帳號密碼)。

伺服器(Server)——跑資料庫的那台機器

一台伺服器上可以跑好幾個資料庫。除了應用程式自己的資料庫,系統也會有自己用的。就像一台電腦上有好多個 Excel 檔案——有的是你自己的,有的是系統預裝的。

SQL Injection 的時候,我們要先確認 「我現在在哪個資料庫裡」 ,才知道該從哪裡開始查資料表。

Schema——可以先把它想成資料庫裡的「資料夾」

Schema 可以先把它想成資料庫內部的「資料夾」,用來分類、管理不同的資料表。

MSSQL 的預設 schema 叫 dbo——很多使用者自己建的資料表幾乎都放在這裡。等一下查資料表的時候,我們會加 WHERE TABLE_SCHEMA='dbo' 來過濾,先把範圍縮小到 dbo 裡的資料表,避免系統相關的雜訊太多。

(對照 Day 12:PostgreSQL 的預設 schema 叫 public,所以當時查資料表時會用 WHERE table_schema='public')

整個結構從大到小:

伺服器     → 「我在哪台機器上?」
 └── 資料庫  → 「這台機器上有哪些資料庫?我在哪個裡面?」
      └── Schema → 「這個資料庫裡有哪些資料夾?應用程式的資料表在 dbo 裡」
           └── 資料表    → 「dbo 裡有哪些資料表?admin_users!(完全是寶藏呀!有帳密的話就更好了!!!)」
                └── 欄位  → 「admin_users 有哪些欄位?有 username 跟 password_hash」
                     └── 資料 → 「SELECT username, password_hash → 帳密到手」

所以 SQL Injection 就是照這個順序,一層一層往下挖:

我在哪個資料庫? → 有哪些資料表? → 資料表裡有哪些欄位? → 撈出資料

先搞懂:information_schema——資料庫的「目錄」

「一層一層往下問」,但問誰?我們連資料庫裡有什麼資料表都不知道,總不能用猜的吧~

其實資料庫自己就有一份「目錄」,記錄了裡面所有的結構——有哪些資料表、每張資料表有哪些欄位。這個目錄叫 INFORMATION_SCHEMA。

想像一下:你走進一個完全陌生的圖書館,不知道有什麼書、放在哪裡。你可以一個書架一個書架翻——但更聰明的做法是先去看目錄。目錄會告訴你:這間圖書館有哪些區、每區有哪些書。

INFORMATION_SCHEMA 就是資料庫的目錄。裡面有很多可以查資料庫結構資訊的內容,我們這次最常查的是這三個:

我想知道什麼 查哪張目錄 撈哪個欄位
有哪些 Schema(資料夾)? INFORMATION_SCHEMA.SCHEMATA SCHEMA_NAME
資料庫裡有哪些「資料表」? INFORMATION_SCHEMA.TABLES TABLE_NAME
某張資料表裡有哪些「欄位」? INFORMATION_SCHEMA.COLUMNS COLUMN_NAME

開始實作囉~~~

基礎觀念搞清楚了,來實際操作。

今天的實作素材,是跟Claude討論一起製作出的 SQL Injection 練習靶機 - BaijiaShop敗家線上商城

這個靶機的後端是 MSSQL,跟 Day 12 的 PostgreSQL 不一樣——但information_schema兩種資料庫都支援

那我們就來走一遍完整流程,把上面說的觀念都串起來~

情境: 我們在測試敗家線上商城,發現搜尋功能有 SQL Injection。
目標: 取得敗家線上商城的管理者帳密!!!(超美好)

注入點在商品搜尋框,後端把我們的輸入直接拼進這句 SQL:

SELECT id, name, price, description FROM products WHERE name LIKE '%[我們的輸入]%'

以這個靶機(MSSQL)為例,資料庫結構長這樣(先不准偷看資料庫結構!!!)

BaijiaShop(資料庫)
 ├── dbo(即Postgresql的public)
 │    ├── products(商品)── 6 筆商品
 │    ├── categories(分類)
 │    ├── customers(會員帳密)
 │    ├── orders(訂單)
 │    ├── order_items(訂單明細)
 │    ├── coupons(折價券)
 │    ├── admin_users(管理員帳密)⬅ 寶藏在這!!!
 │    └── app_config(系統設定)⬅ 藏了一堆金鑰,喜歡!
 └──另一個 schema,放系統相關資料表

Step 1:找欄位數

UNION 兩邊欄位數必須一樣,所以第一步要先確定原本查詢有幾欄。

怎麼找?用 ORDER BY n。ORDER BY 1 就是「按第 1 欄排序」,ORDER BY 2 就是「按第 2 欄排序」⋯⋯如果你 ORDER BY 的數字超過實際欄位數,資料庫就會報錯。所以慢慢加上去,加到報錯的前一個數字就是答案。

嘗試 ORDER BY 1-- -:

https://ithelp.ithome.com.tw/upload/images/20260928/20184189oWeDbANTAt.png

嘗試ORDER BY 5-- -
https://ithelp.ithome.com.tw/upload/images/20260928/20184189QuVnsYQSpc.png

嘗試ORDER BY 4-- -

https://ithelp.ithome.com.tw/upload/images/20260928/20184189rHuiFvJUK5.png

ORDER BY 5 報錯,ORDER BY 4 可以正常執行——所以 products 這張資料表是 4 個欄位


Step 2:找哪個欄位能顯示文字——之後要撈出資料表名、資料欄位名稱都要靠這欄!

UNION SELECT 前後對應位置的欄位,資料型態要能對得上。所以從第 1 欄開始,一欄一欄把字串輪流塞進去測試,其他欄位全部用 NULL 佔位。

測試第一個欄位是否為文字型態:

' union select 'hi',null,null,null -- -

https://ithelp.ithome.com.tw/upload/images/20260928/20184189C0cB8O5oe2.png

會出現錯誤:

Conversion failed when converting the varchar value 'hi' to data type int.
(第 1 欄是 int,不能放非數字字串——這就是為什麼要用 NULL 佔位、只把字串放進「字串型別」的欄位)

這代表 UNION SELECT 前面原本查詢(products)的第一欄位的資料型態不是字串,我們想知道的所有字串型資訊(資料表名、欄位名、帳密⋯⋯)不能放在union select後的第一欄位。

測試第二個欄位是否為文字型態:

' union select null,'hi',null,null -- -

https://ithelp.ithome.com.tw/upload/images/20260928/20184189JH75zhLHZB.png

不會出錯!而且頁面上出現了 hi。

這代表目前這個位置可以接受字串型態的值——型態對得上,所以不會報錯。

等等我們想知道的所有字串型資訊(資料表名、欄位名、帳密⋯⋯)都可以放在第二個欄位。 其他欄位我們用 NULL 佔位就好。


Step 3:先摸清楚環境——我在哪?這是什麼資料庫?

拿到注入點之後,不急著撈資料——先搞清楚自己在什麼環境裡。MSSQL 有幾個內建函式可以直接問:

我在哪個資料庫?

' union select null,DB_NAME(),null,null -- - 

https://ithelp.ithome.com.tw/upload/images/20260928/20184189T0u7O7Wekj.png

DB_NAME() 回傳目前連線所在的資料庫——BaijiaShop,這就是應用程式自己的資料庫,帳密幾乎都在這。

這台跑的是什麼資料庫、什麼版本?

' union select null,@@version,null,null -- -

https://ithelp.ithome.com.tw/upload/images/20260928/20184189NViSMxIZHI.png

@@version 一次告訴我們三件事:是 MSSQL(不是 MySQL、不是 PostgreSQL)、版本是 2019、架構是 64 位元。版本資訊可以作為後續漏洞研究的線索(相關操作可以參考Day 5 — 從版本號到 Shell:第一次用 Metasploit 拿下目標)。

目前用什麼帳號連進來的?

' union select null,system_user,null,null -- -

https://ithelp.ithome.com.tw/upload/images/20260928/20184189FlV3Kk4ZV2.png

SYSTEM_USER 回傳目前的 SQL Server Login 名稱。如果這裡顯示的是 sa,那我們就可以執行很多事,所以遇到資料庫跟拿到shell一樣。要先偵查環境與拿到的帳號,這裡是 baijia_app,是一般的應用程式帳號。

小整理——MSSQL 環境偵察常用函式:

我想知道什麼 用什麼 結果
目前在哪個資料庫 DB_NAME() BaijiaShop
資料庫類型和版本 @@version Microsoft SQL Server 2019...
目前的 Login 帳號 SYSTEM_USER baijia_app

這些資訊看起來不像帳密那麼香,但在真正的滲透測試裡很重要——知道版本,可以作為後續漏洞研究的線索!知道帳號,則可以進一步判斷權限,information gathering非常重要!我們不能放過!!!


Step 4:查 BaijiaShop 裡有哪些資料表

WHERE TABLE_SCHEMA='dbo' 就是「只看 dbo 這個資料夾裡的資料表」,把其他資料夾裡的資料表過濾掉:

ss' union select null,TABLE_NAME,null,null from information_schema.tables where table_schema='dbo'-- -

故意用ss這種查不到任何商品的字,這樣頁面上就只會剩下我們要的table name(比較乾淨><

頁面出現:

https://ithelp.ithome.com.tw/upload/images/20260928/20184189tEqHTlzU4c.png

看到 admin_users——管理員帳密很可能在這裡,先查這張。

(對照 PostgreSQL:過濾條件是 WHERE table_schema='public',因為 PostgreSQL 預設 schema 叫 public,不叫 dbo。)


Step 5:查 admin_users 有哪些欄位

ss' union select null,COLUMN_NAME,null,null from information_schema.columns where table_name='admin_users'-- -

頁面出現:

https://ithelp.ithome.com.tw/upload/images/20260928/20184189higQZlPl2B.png

找到了—— username 跟 password_hash 就是我們要的。


Step 6:撈出管理員帳密

我們剛剛只有先找「一個」文字型態的欄位,但想同時撈 username 跟 password_hash 兩欄,用 : 把兩欄拼在 union select後的第二個欄位輸出:

ss' union select null,username+':'+password_hash,null,null from admin_users-- -

頁面出現:
https://ithelp.ithome.com.tw/upload/images/20260928/20184189XsZ9xsV2gr.png

帳密出來了——雖然密碼不是明文,但我們可以拿密碼的hash值,使用John the Ripper去破解看看


偷出管理員帳密的探險流程

確認union select前的資料表欄位數(ORDER BY)
→ 找可以顯示出文字型態資料的欄位(UNION SELECT 塞字串測試)
→ DB_NAME() 確認在哪個資料庫
→ INFORMATION_SCHEMA.TABLES 找有哪些資料表
→ INFORMATION_SCHEMA.COLUMNS 找有哪些欄位
→ SELECT 撈出目標資料

走完這一遍,對Day 12 的方法二不再心虛(變身為自己的information_schema AI><
終於不只是知道怎麼解,請AI協助,而是真的知道要取得什麼資訊,必須要怎麼做哩!


下集預告 ><

明天開始就要正式進入 CPTS 考試的 AD 部分準備哩!!!

完全陌生的領域,有點緊張 ><
但鐵人賽都已經進行到一半了,沒有不繼續走下去的道理吧 xddd

先來把靶機跟教材找好,趕快鑽研一下 ><
明天就直接開始我們的 AD 之路!!!

不知道會不會瘋狂卡關 xddd
但就一邊查、一邊學,繼續一起往 CPTS 前進囉!

我們明天見~~~


上一篇
Day 13 — Command Injection:一個查庫存的按鈕,竟然能讓伺服器執行指令 👀
下一篇
Day 15 — Active Directory:從零開始,這個陌生的世界長什麼樣?
系列文
《朝 HTB CPTS 前進:資安新手的 30 天實作筆記》 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言