悟空科技股份有限公司 未付款訂單存取控制不一致,導致台日兩站之使用者個資與付款流程資訊可經其它後台 API 查詢 - HITCON ZeroDay

Vulnerability Detail Report

Vulnerability Overview

  • ZDID: ZD-2026-00964
  •  發信 Vendor: 悟空科技股份有限公司
  • Title: 悟空科技股份有限公司 未付款訂單存取控制不一致,導致台日兩站之使用者個資與付款流程資訊可經其它後台 API 查詢
  • Introduction: 台灣站與日本站的未付款訂單雖已無法透過後台主要查詢功能檢索,但仍可經由其它後台 API 取得其訂單 ID,並進一步查詢交易紀錄、使用者個資與付款流程相關資訊,顯示各相關端點對未付款訂單的存取控制未一致套用。

處理狀態

目前狀態

公開
Last Update : 2026/09/27
  • 新提交
  • 已審核
  • 已通報
  • 未回報修補狀況
  • 未複測
  • 公開

處理歷程

  • 2026/07/28 10:26:46 : 新提交 (由 更新此狀態)
  • 2026/07/28 11:11:55 : 新提交 (由 更新此狀態)
  • 2026/07/28 12:02:12 : 新提交 (由 更新此狀態)
  • 2026/07/28 13:41:17 : 新提交 (由 更新此狀態)
  • 2026/08/03 12:59:17 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2026/08/05 19:02:14 : 通報未回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2026/08/05 19:02:14 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2026/08/05 19:02:15 : 通報未回應 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2026/09/27 03:00:23 : 公開 (由 HITCON ZeroDay 平台自動更新)

詳細資料

  • ZDID:ZD-2026-00964
  • 通報者:S_Cyrus ()
  • 風險:中
  • 類型:存取控制缺陷 (Broken Access Control)

參考資料

攻擊者可經由該漏洞取得、修改、刪除系統中的其他使用者的資料,或連線至高權限使用者的頁面。

OWASP Top 10 - 2017 A5 - Broken Access Control
https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control

CWE-284: Improper Access Control
https://cwe.mitre.org/data/definitions/284.html
(本欄位資訊由系統根據漏洞類別自動產生,做為漏洞參考資料。)

相關網址

https://helper.diyidphoto.com/api/gallery/list?site=tw
https://helper.diyidphoto.com/api/order/<OrderID>/payment
https://helper.diyidphoto.com/api/orders/search?diy_type=tw
https://helper.diyidphoto.com/api/orders/search?diy_type=ja
https://helper.diyidphoto.com/api/idphoto/orders?search=<OrderID>

敘述

0. 摘要(Summary)

https://helper.diyidphoto.com/ 是 https://diyidphoto.com/zh-tw/ 與 https://jp.diyidphoto.com/ 的後台管理頁面。

而在測試台灣站與日本站付款流程綁定不足時,進一步發現:

  1. 未付款訂單在後台主要的訂單查詢(/orders)功能與快洗證件照(/idphoto)功能的關鍵字搜尋,均無法查得。

  2. 但若取得未付款訂單的 OrderID,將其帶入支付細節(payment detail)端點 GET /api/order/<OrderID>/payment,即可查詢到其交易紀錄(trades),且其會回傳:

    • 使用者敏感個資,例如 Name(日本站)、Email、Phone(台灣站)等。
    • 參數 RequestJSON 的值經 base64 decode 後,可見其保存了付款流程的相關資訊,包含 email、phone、prime、token、webhook 等(但經測試,若將這些參數再次用以觸發付款流程,會顯示訂單不存在)。
  3. 而利用後台已上傳照片集(/gallery)功能,未付款訂單會被標註綠字的準備付款標籤,因此:

    • 透過端點 POST /api/gallery/list?site=tw(site=tw 與 site=ja 共用資料)取得 JSON response 後,搜尋 "PrePay":true 即可識別未付款訂單。
    • 而透過跨用途 token 可進入相同解析流程可知此端點訂單資料的格式如下,並得知訂單的 OrderID:
   {
     "error_code": 0,
     "error_text": "",
     "data": [
       {
         "Name": "origin_<OrderID>_<Numbers>",
         "Origin": "/api/gallery/img/<Origin_Token>",
         "Final": "/api/gallery/img/<Final_Token>",
         "PreviewOrigin": "/api/gallery/img/<PreviewOrigin_Token>",
         "PreviewFinal": "/api/gallery/img/<PreviewFinal_Token>",
         "Size": "<Size>",
         "PrePay": <PrePay>
       },
       ...
     ]
   }
  • 將取得的未付款訂單 OrderID 帶入端點 GET /api/order/<OrderID>/payment,即可查詢到主要端點無法搜尋到的未付款訂單,並得知其敏感個資與付款流程相關資訊。
  1. 另外,由於日本站 FAQ 提及無料サンプルは一定時間後に自動削除されます。支払いをしなければキャンセル扱いとなります。,因此串聯日本站資料保存情形可能與常見問題不一致也可能進一步衍生資料管理爭議。

上述結果顯示:

  1. 未付款訂單雖已被後台主要查詢端點排除或隱藏,但仍可透過其它後台端點取得其 OrderID,並進一步查詢相關交易紀錄。

  2. /api/order/<OrderID>/payment 未依訂單狀態套用一致的資料回傳限制。即使訂單處於未付款、已取消,或已被主要查詢功能排除的狀態,該端點仍會回傳使用者個資與付款流程相關敏感參數。

  3. 若業務邏輯上未付款訂單應被隱藏、取消或定期刪除,相關交易紀錄、個資與付款流程資料仍可透過後台 API 查詢,可能造成資料管理與隱私風險。詳情可見日本站資料保存情形可能與常見問題不一致。


1. 受影響功能(Affected Feature)

  • 主要受影響端點:
  GET /api/order/<OrderID>/payment
  POST /api/gallery/list?site=tw
  • 輔助驗證端點:
  POST /api/orders/search?diy_type=tw
  POST /api/orders/search?diy_type=ja
  GET /api/idphoto/orders?search=<OrderID>

2. 漏洞驗證之前置條件(Preconditions for Verification)


3. 重現步驟(Steps to Reproduce)與概念驗證(Proof of Concept)

以下重現步驟皆使用 Burp Suite 作為工具。

以下 PoC 僅整理我在實際測試中看到的重點證據。因為 HITCON 提交附件最多只能上傳 10 張圖,所以我只附足以證明主問題成立的必要代表性截圖。其餘我都有保留,若需要可再補充。


步驟 1:建立一筆或多筆未付款的台灣站與日本站訂單,並記住其 OrderID

  1. 在 Burp Suite 的瀏覽器連上台灣站 diyidphoto.com 和日本站 jp.diyidphoto.com 上傳測試圖片,一路進行到跳轉付款頁面,但不要付款。

  2. 查看 Burp Suite 的 Proxy 頁籤中的 HTTP history,找到付款流程端點 POST /api/pay 或 POST /api/pay-ja;

記住請求中參數 order_id 的值,此值為剛剛測試圖片的 OrderID;並且記住上傳測試圖片當天的日期,一至兩天後再繼續以下步驟。

圖片

本報告提供以下測試圖片的 OrderID:

(1) 台灣站 diyidphoto.com/zh-tw/

6976071 # 日期 2026-07-10
5572826 # 日期 2026-07-09
1493170 # 日期 2026-07-08
7473495 # 日期 2026-07-07
4242317 # 日期 2026-07-06
1486156 # 日期 2026-07-05
9035623 # 日期 2026-07-04
8217399 # 日期 2026-07-02
0931777 # 日期 2026-07-01
6197892 # 日期 2026-06-30

(2) 日本站 jp.diyidphoto.com

5042499 # 日期 2026-07-10
9331009 # 日期 2026-07-09
8354748 # 日期 2026-07-08
8708786 # 日期 2026-07-07
8348427 # 日期 2026-07-06
8253988 # 日期 2026-07-05
4091637 # 日期 2026-07-04
0907587 # 日期 2026-07-02
6639421 # 日期 2026-07-01
6463882 # 日期 2026-06-30

步驟 2:用已上傳照片集功能查詢未付款訂單

  1. 在 Burp Suite 的瀏覽器開啟 https://helper.diyidphoto.com/login ,並使用已建立的帳號及密碼登入。可參考未授權使用者可匿名建立後台帳號並任意指定 role與低權限後台帳號可繞過 RBAC建立。

  2. 進入後台左側管理控制面板的已上傳照片集功能,調整日期為步驟 1 中上傳測試圖片當天的日期。

圖片

  1. 到 Burp Suite 的 Proxy 頁籤中的 HTTP history,應可見此請求:
POST /api/gallery/list?site=tw HTTP/2
Host: helper.diyidphoto.com
Cookie: access_token=<access_token>; uid=<uid>; role=%5B%22admin%22%5D
Content-Type: application/json

{"Date":"<Date>"}

其 Response 可見以下資料

{
  "error_code": 0,
  "error_text": "",
  "data": [
    {
      "Name": "origin_<OrderID>_<Numbers>",
      "Origin": "/api/gallery/img/<Origin_Token>",
      "Final": "/api/gallery/img/<Final_Token>",
      "PreviewOrigin": "/api/gallery/img/<PreviewOrigin_Token>",
      "PreviewFinal": "/api/gallery/img/<PreviewFinal_Token>",
      "Size": "<Size>",
      "PrePay": <PrePay>
    },
    ...
  ]
}

在 Response 的資料中,搜尋測試圖片的 OrderID,即可見該測試圖片為 "PrePay": true,這代表這筆訂單為未付款狀態(或稱準備付款狀態)。

而直接請求 Origin 或 Final 之路徑,可進一步驗證與查看此未付款訂單的照片,請求如以下:

GET /api/gallery/img/<Final_Token> HTTP/2
Host: helper.diyidphoto.com
Cookie: access_token=<access_token>; uid=<uid>; role=%5B%22admin%22%5D

圖片

圖片


步驟 3:用訂單查詢功能查詢 OrderID

  1. 依訂單所屬的站別-點擊左上角 DIY 旁類似雙彎曲箭頭的按鈕-切換台灣站 / 日本站後台,接著點擊訂單查詢功能,在關鍵字欄位輸入測試圖片的 OrderID 並點擊關鍵字搜尋按鈕以查詢該訂單,會發現沒有查詢結果。

  2. 而從 Burp Suite 的 HTTP history 可見此請求:

台灣站 POST /api/orders/search?diy_type=tw
日本站 POST /api/orders/search?diy_type=ja

其 Response 顯示 {"error_code":0,"error_text":"","data":[]},這代表沒有該訂單資料。

因此,可確認未付款訂單的相關資料,已無法透過主要的訂單查詢端點而取得。

圖片


步驟 4:用快洗證件照功能的關鍵字搜尋功能查詢 OrderID

  1. 進入後台左側管理控制面板的快洗證件照功能(若在日本站後台,請先切換到台灣站後台才會看到此功能;或直接在瀏覽器的網址列輸入 https://helper.diyidphoto.com/idphoto),在關鍵字搜尋欄位輸入測試圖片的 OrderID 並點擊搜尋按鈕以查詢該訂單,也會發現沒有查詢結果。

  2. 從 Burp Suite 的 HTTP history 可見此請求 GET /api/idphoto/orders?search=<OrderID> ,其 Response 顯示 {"error_code":0,"error_text":"","data":[]},這代表沒有該訂單資料。

因此,可確認未付款訂單的相關資料在此也不可見。

圖片


步驟 5:將 OrderID 填入支付細節端點

  1. 從低權限後台帳號可繞過 RBAC可知,後台快洗證件照提供支付細節查詢功能-其端點為 GET /api/order/<OrderID>/payment-可查看特定訂單的支付細節。

  2. 在 Burp Suite 的 HTTP history 中,將任一登入後台後的 Host: helper.diyidphoto.com 請求發送至 Repeater,並將其請求修改如以下:

GET /api/order/<OrderID>/payment HTTP/2
Host: helper.diyidphoto.com
Cookie: access_token=<access_token>; uid=<uid>; role=%5B%22admin%22%5D

送出請求後,在 Response 可見:

(1) 台灣站訂單之 Response

{
  "error_code": 0,
  "error_text": "",
  "data": {
    "invoice": null,
    "trades": [
      {
        "ID": <Trade_ID>,
        "OrderID": "<OrderID>",
        "IdempotentKey": "",
        "PayMethod": "<PayMethod>",
        "TradeID": "<Method_TradeID>",
        "Amount": 120,
        "Status": <Status>,
        "Name": "",
        "Email": "<Email>",
        "Phone": "<Phone>",
        "RedirectURL": "<RedirectURL>",
        "RequestJSON": "<RequestJSON>",
        "CreatedAt": "<CreatedAt_Date_Time>",
        "UpdatedAt": "<UpdatedAt_Date_Time>"
      }
    ]
  }
}

而將參數 RequestJSON 的值(RequestJSON)經 base64 decode 後,可發現其保存了付款流程的相關資訊,其參數與值皆如下:

{
  "mail": "",
  "name": "",
  "email": "<Email>",
  "phone": "<Phone>",
  "prime": "<Method_Prime>",
  "token": "<UUID>",
  "method": "<Method>",
  "address": "",
  "invoice": "email",
  "webhook": "/zh-tw/takePhoto",
  "order_id": "<OrderID>",
  "tax_name": "",
  "tax_number": "",
  "donate_code": "",
  "use_for_what": <Use_For_What>,
  "carrier_phone": "",
  "use_for_other": "",
  "carrier_natural": ""
}

圖片

(2) 日本站訂單之 Response

{
  "error_code": 0,
  "error_text": "",
  "data": {
    "invoice": null,
    "trades": [
      {
        "ID": <Trade_ID>,
        "OrderID": "<OrderID>",
        "IdempotentKey": "<IdempotentKey>",
        "PayMethod": "<PayMethod>",
        "TradeID": "",
        "Amount": 500,
        "Status": <Status>,
        "Name": "<Name>",
        "Email": "<Email>",
        "Phone": "",
        "RedirectURL": "<RedirectURL>",
        "RequestJSON": "<RequestJSON>",
        "CreatedAt": "<CreatedAt_Date_Time>",
        "UpdatedAt": "<UpdatedAt_Date_Time>"
      }
    ]
  }
}

而將參數 RequestJSON 的值(RequestJSON)經 base64 decode 後,可發現其保存了付款流程的相關資訊,其參數與值皆如下:

{
  "email": "<Email>",
  "phone": "",
  "prime": "<Method_Prime>",
  "token": "<UUID>",
  "method": "<Method>",
  "webhook": "https://jp.diyidphoto.com/takePhoto",
  "order_id": "<OrderID>",
  "photo_kind": <Photo_Kind>,
  "photo_name": "<Photo_Name>",
  "user_agent": "<User_Agent>",
  "passport_name": "<Name>",
  "three_domain_secure": false
}

圖片

  1. 從上述 Response 中,可發現參數 CreatedAt 的值為上傳測試圖片當天的日期;這代表該筆未付款訂單的交易紀錄已持續保留一段時間,且可透過此端點查詢到其個資與付款流程敏感參數。

4. 預期行為(Expected Behavior)

  1. 未付款、取消或已被主要查詢功能排除的訂單,應在後台各相關 API 中套用一致的可見性與存取限制。

  2. 若後台有查詢未付款訂單之交易紀錄的業務需求,API 回應亦應遵守資料最小化原則,僅回傳必要資訊,並遮罩或移除 Name、Email、Phone、token 等敏感欄位。


5. 實際行為(Actual Behavior)

  1. 未付款訂單已無法透過 /orders 與 /idphoto 查詢,但仍可透過 /gallery 相關 API 由 PrePay 狀態及命名格式間接識別,並取得其 OrderID。

  2. 使用取得的 OrderID 帶入 /api/order/<OrderID>/payment 時,API 仍會回傳該未付款訂單的交易紀錄,且依站別不同,回應中可包含 Name、Email、Phone、RequestJSON、token 等個資或付款流程相關資料。


6. 影響(Impact)

此問題可能導致以下風險:

  1. 未付款訂單可被側向發現

    即使 /orders 與 /idphoto 已無法搜尋未付款訂單,仍可透過 /gallery API 的 "PrePay": true 與 Name 欄位反推出 OrderID。

  2. 未付款訂單仍可查詢交易紀錄與敏感資訊

    GET /api/order/<OrderID>/payment 未與主要查詢功能套用一致的訂單狀態限制,導致未付款訂單仍可查詢交易紀錄,並回傳使用者個資及付款流程相關資訊,增加敏感資料暴露風險。

  3. 可能產生資料管理或隱私爭議

    日本站 FAQ 提及「無料サンプルは一定時間後に自動削除されます。支払いをしなければキャンセル扱いとなります。」,但後台實際上仍可檢索未付款訂單資料、照片資料或付款流程資料,可能與使用者對資料刪除或取消處理的合理期待產生落差。


7. 可能的根本原因(Likely Root Cause)

問題可能出在後台不同 API 對未付款訂單,未套用一致的可見性控管與狀態限制,導致已被主要查詢功能排除的訂單仍可透過其它端點查詢;

同時 /api/order/<OrderID>/payment 端點對未付款、或應視為取消的訂單,仍回傳使用者個資與付款流程相關敏感資訊,未依資料最小化原則調整回應內容。


8. 嚴重性評估(Severity Assessment)

中高風險(Medium-High)

但串聯既有後台權限問題,風險可提升至 High。

理由:

  • 台日兩站之未付款訂單已無法透過後台主要訂單查詢功能取得,顯示系統可能已對該類訂單採取排除或限制查詢措施;然而,透過其他後台端點仍可側向取得 OrderID,並進一步查詢其交易紀錄與付款細節。

  • 透過 /api/order/<OrderID>/payment 回傳內容包含使用者個資與付款流程相關敏感資訊。即使目前測試未能利用相關參數重新觸發付款流程,這些資料仍不應在未付款或應視為取消的訂單狀態下完整回傳。

  • 單獨利用此問題需先取得未付款訂單的 OrderID,因此利用條件受限;但若串聯既有後台權限漏洞(例如未授權使用者可匿名建立後台帳號並任意指定 role、低權限後台帳號可繞過 RBAC與後台身份驗證可被繞過),攻擊者可能透過 /gallery 取得未付款訂單 OrderID,再查詢其個資與付款流程資料,進一步增加釣魚、社交工程或資料濫用風險。

  • 日本站 FAQ 文字所述與實際後台可查詢資料之間可能存在落差,可能影響使用者對資料刪除或未付款訂單取消處理的合理期待,進而衍生資料管理與隱私風險(詳見日本站資料保存情形可能與常見問題不一致)。

由於目前為維持最低限度測試,尚未針對實際完成付款的訂單進行驗證,因此若後續確認以下任一情況成立,實際嚴重性可能進一步提升:

  • 已付款訂單的 /api/order/<OrderID>/payment 回應中,RequestJSON 內的付款流程參數可被再次用於觸發付款流程、新增交易紀錄或再次付款。
  • 若可再次進入付款流程,是否會反映在交易紀錄中,導致交易紀錄被污染;或增加網站管理人員被導向惡意網站的風險(詳見日本站特定付款方式可被注入外部網域與台灣站與日本站付款流程綁定不足)。
  • 若可再次付款,以相同方式用在其他使用者的訂單上,是否會造成訂單資料、照片資料或付款流程狀態被覆寫、混淆或不當存取。

9. 補充說明(Researcher Note)

  1. 本報告之測試僅限確認漏洞存在,未進行批次化、大量化或自動化操作,也未進行破壞性操作。

  2. 由於此系統與技術牽涉到三家公司-台灣公司為誠和國際股份有限公司(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. 後台各相關 API 應統一套用未付款、取消或不可查詢訂單的狀態限制,避免主要查詢功能已排除的訂單仍可透過其它端點被間接查詢。

2. 端點 `/api/order/<OrderID>/payment` 應依資料最小化原則調整回應內容,遮罩或移除非必要敏感欄位。

3. 端點 `POST /api/gallery/list?site=tw` 應避免回傳可反推出 `OrderID` 的命名格式,改用不可逆、用途限定且具時效性的識別值。

擷圖

留言討論

聯絡組織

 發送私人訊息
您也可以透過私人訊息的方式與組織聯繫,討論有關於這個漏洞的相關資訊。
;