隨意聊

有別於其他的長文,這裡都是比較隨意寫的短文。原本是發在臉書粉專,但都藏在臉書裡面有點可惜,索性搬一份到部落格來,對不用臉書的人也更友善。

共 110 篇 第 5 / 6 頁 RSS 訂閱

信用卡金流合規風險

這是一段信用卡資安、PCI DSS 與金流服務提供商的故事

網路上偶爾會看到一些信用卡被盜刷的討論文章,有些人會說自己在某網站刷卡過後不久就被盜刷了,懷疑是那網站的問題。我看到這種討論後通常都不太在意,覺得可能性偏小。

為什麼偏小呢,因為大多數網站在刷卡時,要嘛直接跳轉到第三方金流,要嘛用 iframe 來嵌入付款頁面,自己的網站根本不知道卡號是多少。既然不知道的話,這網站又怎麼能流出你的卡號呢?

但幾週前我在某網站結帳時,心血來潮開了 DevTools 來看,才發現:「不對,為什麼你是直接收我卡號啊」,說好的 iframe 呢?直接收卡號就代表信用卡資料確實有進到這網站的系統中,開頭講的狀況還真的有可能發生。

接著我開始了一系列的研究,找了一堆資料,才發現這其實不是個案,而是有一堆網站都這樣。

大多數網站接的金流都是綠界、藍新這類的金流服務提供商,這些金流再去跟銀行接入。而藍新對外公開的 API,就只有跳轉這個選項,用起來滿安全的,商家也不需要碰到卡號。

但是,如果你想提升使用者體驗,省去跳轉這步,可以去申請「幕後授權」,就會開給你另一個 API,可以接收卡號、過期日跟 CVV 等資訊。接著你就可以在網站上放自己的 input,將這些資料收進自己系統,再轉傳給藍新。

若是不知資安為何物,可能會順便把卡號明文存到系統,或是寫到 log 裡,哪天被駭客打下來,就全部都外流出去了,卡就被盜刷了。

聽起來風險很高對吧?我也覺得很高啊!

於是,我參考了其他金流,發現 Stripe、adyen 以及綠界,網站上都寫說必須先提供 PCI DSS 相關文件(SAQ D)才會開 API 給你。

那藍新呢?不需要,你沒有做過任何資安合規也開給你,另一間 PAYUNi 統一金流看起來也是。在網路上搜了一下,發現這件事情似乎也沒人公開講過,難道只有我覺得這樣不太對勁?

收單行會要求合作的金流商必須合規,而金流商理應也必須要求商家,尤其是收卡號這種接觸到持卡人資料的行為,更應該特別小心。但藍新在方便性與安全性之間選擇了前者,而且若是要提升使用者體驗,藍新做個 iframe 是最好的,這樣商家也沒必要自己收卡號了。比起做個 iframe,他們選擇了開幕後授權給沒有合規的商家收卡號,身為消費者的我,覺得自己的信用卡資料實在不是很安全。

因此我寫了這篇貼文想讓大家知道有這件事,前面那篇 PCI DSS 與信用卡資安 裡面有更多細節,也有到底什麼是 PCI DSS 的講解,看完會更清楚整個脈絡。

總之我自己調查完一輪的結論是:「藍新應該好好把關,不該開給沒有合規的商家幕後授權」

最後聲明一下,金流跟 PCI DSS 合規這塊我非專業人士,若是整件事情我有哪邊理解錯的,也請不吝留言指正。

Google帳號洩電話

之前分享過洩漏 YouTube 頻道 email 拿到 2 萬美金的故事,同個作者 brutecat 這次又揭露新的漏洞:只要知道你的 Google 帳號,就能拿到你的電話號碼。

在看 writeup 的時候由於都是順著作者的脈絡,關關難過關關過,感受不到困難之處,因此這次我們換個角度,從「我可能會在哪裡就卡住」來聊聊整個故事。

前情提要是 Google 在 2018 年時發了個公告,説他們在登入頁會用 JavaScript 做一些安全檢查,提前阻止可疑的行為,因此瀏覽器一定要能執行 JavaScript,否則就不給用。

但 brutecat 找到一個就算關了 JavaScript 還是可以用的 username 復原服務,假設你忘記你的 Google 帳號,輸入電話跟姓名,就能找出你當初註冊的帳號。

例如說我電話是 0900-000-000,姓名是 Peter Lin,輸入這兩個之後就會跑出來 peter1234 這個 Google 帳號。

但是找回帳號對駭客來說有什麼用呢?我又不知道電話也不知道姓名,就算都知道了,能找到帳號又有什麼問題呢?這時 brutecat 其實是把它倒過來想的,假設我已經知道某個人帳號是 peter1234,姓名是 Peter Lin,那是不是就能反過來利用這功能,暴力破解出他的電話是多少!

舉個例子,輸入 0900-000-111 加上姓名,找不到帳號,代表這是錯的,但如果輸入 0900-000-000 跟姓名,找回成功,就代表找到了這個人的電話。

因此這整個攻擊的核心就在於,知道了某個 Google 帳號外加姓名,就能暴力破解出電話號碼。甚至更往前了一步,只要知道 Google 帳號就好。因為 brutecat 利用了其他 Google 產品中的一個功能,洩漏出 Google 帳號對應的 display name,藉此來知道對應的姓名。這一步如果沒什麼毅力的話直接就卡住了,只能一直隨機去戳各個產品然後試各種功能,直到找到一個能洩露姓名的功能為止。

所以現在的攻擊流程是:

  1. 決定要被攻擊的帳號,如 peter1234
  2. 洩漏出 peter1234 對應的名稱 Peter Lin
  3. 利用暴力破解,猜出電話號碼

而這第三步就是精華中的精華了。

當你利用帳號復原功能嘗試了幾次後,會發現跳出 captcha 把你擋住。由於這種機制通常針對的都是 IP,因此下一步我也會試試看能不能多換幾個 IP 繞過。

以前聽過有個方法是去各大雲上面開 serverless function,如 AWS Lambda 當 proxy,你開一個就是一個 IP,照使用量算錢很便宜,到處開一開要拿到 1000 個 IP 應該不是問題?不過還是有點少就是了。

而 brutecat 用的方法是我第一次聽到的:IPv6。一些 VPS 服務在開啟 IPv6 時,直接給你一整個網段,如 Vultr 給你 /64,因此你有一堆可以用的 IP。我實際去 Vultr 開了機器並且拿作者的 PoC 去跑,確實是這樣沒錯,可以在發請求時一直換 IP,如果 rate limiting 認的是 IPv6 地址,那就等於毫無作用。

但是呢,這招對 Google 來說不管用,因為 brutecat 後來發現就算換了 IP 還是會出現 captcha(雖然不管用但我偷偷學起來了,感覺未來用得到)。

到這邊應該許多人就放棄了,都換 IP 還是繞不過,心已死。

但 brutecat 繼續深挖,發現有開啟 JavaScript 的帳號復原功能裡面有個 token,把它搬來這邊用以後就能繞過 captcha,解決了這個問題 😂

到這邊其實暴力破解基本上就完成了,只是時間問題而已。不過目前要破解至少 10 位數的數字,要發幾億個請求,有可能被認為是「理論上可行」,但實務上困難,降低整體攻擊的 impact。

這時又可以凸顯出差異了,有些人到這邊可能就回報漏洞了,至少理論上可行(我懶惰,很可能會這樣幹)。而 brutecat 選擇進一步改善作法,要證明實務上也是可行的。

透過忘記密碼的功能,輸入 email 後選擇用電話號碼還原,Google 會顯示部分的電話號碼,如 •••• ••• •00,除了給了你兩碼以外,這個 • 的排列其實也暗示了地區,如美國會是 (•••) •••-••••,透過這兩個線索,能大幅降低要破解的數量,只嘗試符合的號碼。

最後嘗試出來的結果就是,像新加坡這種只有 8 碼的,又給了你 2 碼,只剩下 6 碼也就是最多 100 萬種組合,每秒可以嘗試 4 萬次(這個也很值得學習,這嘗試次數好多),扣掉不合法的號碼後,只需要 5 秒就能破解成功。

外行看熱鬧,內行看門道,乍看之下就是個暴力破解而已,但實際看會發現眉角很多,少了任何一步都沒辦法讓整個攻擊這麼成功,包括:

  1. 從 email 洩漏出 display name
  2. 利用忘記密碼拿到電話號碼 pattern 跟最後 2 碼
  3. 繞過 captcha
  4. 利用 IPv6 更換大量 IP(我其實不確定這步是不是必須的就是了)

這些細節其實才是關鍵所在。

Self-XSS變身術

Self-XSS,之前在我的書中有提過,通常有兩個定義,一個定義是「讓使用者主動攻擊自己」,例如說你在臉書打開 DevTools console,就會看到上面有個警告,寫著大大的紅字:「住手!」,就是怕有人自己在這邊貼一串 JavaScript 執行,自己攻擊自己。

而另一種定義則是「只能攻擊自己的 XSS」,假設 profile 頁面只有自己能看到,而姓名允許 HTML 所以能拿到 XSS。但因為只有自己能看到,所以沒辦法傳給其他人,只能攻擊自己。

因此在許多 bug bounty program 中,self-XSS 是不算數的,找到也沒用。

而 Slonser 近期發表了一篇 Make Self-XSS Great Again 的文章,談到幾種把 Self-XSS 變成 XSS 的做法。

Self-XSS 之所以難以造成 impact,是因為「只能攻擊自己」與「我要攻擊別人」是兩件矛盾的事情,就算被害者用你的帳號登入,執行了 XSS,你也沒辦法拿到被害者的資料。而 iframe 的一個屬性 credentialless 解決了這個問題。

加上 credentialless 之後,你可以讓同一個網頁用另外一套 storage,跟原本的隔絕開來。因此,我們可以用兩個 iframe,一個是被害者本來的頁面,另一個是加了 credentialless 的頁面,接著在後面這個執行攻擊的 payload,利用這兩個 iframe 是 same-origin 的特性,偷到被害者的資料。

講白話一點就是原本同一個網站同時間只能登入一個帳號,現在可以登入兩個而且互不干擾了,就帳號多開那樣啦!

而另一個我書中有談過的方法是 CSRF,例如說用 CSRF 把受害者的姓名改成 XSS payload,這樣就成功把 self-XSS 變成 XSS 了,是滿經典的做法。

最後還提到一個我覺得最有趣的新 API:fetchLater,這個 API 可以指定某個請求要在一段時間後發送,所以當你用 self-XSS 之後,可以安排某個請求在 1 天後發送,而 1 天過後受害者已經登入回自己的帳號,當請求發送時就是用自己的身份!

這 API 滿有趣的,值得多花點時間研究,畢竟原本是為了解決 sendBeacon 這種 tracking 的需求而出現的,沒想過還可以拿來做攻擊。

瀏覽器防護本機請求

昨天聊到了 Windsurf Editor 的漏洞,一句話解釋就是 Windsurf 在你 local 起的 server 有問題,收到請求就能打出 RCE(Remote Code Execution,遠端程式碼執行)。

其實仔細想想,要打到 local server 不是件容易的事情,大多數人會覺得你要先跟被害者在同個內網才能攻擊,否則是沒辦法直接連到他的機器的。

但我上一篇也提到了,透過瀏覽器可以讓這件事變得非常容易,因為瀏覽器就是把網頁在你電腦打開,所以當我在網頁上去 fetch localhost 的時候,這個 localhost 是指你的電腦,也就是誰打開網頁,就是誰的電腦。

透過瀏覽器,讓我們對 local 發送請求變得非常容易,而瀏覽器當然也注意到了這點。

早在 2014 年就有人提出瀏覽器應該要阻擋從 public 到 private 的請求,例如說我一個 huli .tw 的網頁,不應該讓我發請求到 localhost,這就是阻擋 public 到 private。

因此後來 Google 就提了個 Private Network Access 的 spec,規定如果從 public 要發請求到 private network,那必須要有一個新的 CORS header:Access-Control-Request-Private-Network: true

若是 private network 沒有這個 header,瀏覽器就不讓它存取。

我大概三四年前注意到這東西的,但今天再回去看了一下,發現好像不推了,改推另一種更簡單的形式「當網頁需要發請求給 local network 時,跳出請求授權按鈕要你同意」,把是否開放的權力交還給使用者。

然後在設計時也有考慮到昨天講的 DNS rebinding,每次只要新建 connection 就要重新檢查,就不能像昨天那樣繞過了。

所以,在不久的將來,當瀏覽器跳出視窗問你要不要授權某個網站訪問 localhost 的時候,或許你會想起這篇文章,然後按下 No。

補充文章:

Windsurf本機RCE漏洞

你用 AI IDE 幫忙寫 code 很開心,駭客用你的 AI IDE 駭進去也很開心。

資安研究員 s1r1us 發現了一個 Windsurf IDE 的漏洞,拿到了一萬美金的賞金,並且剪了一支 YouTube 影片詳細講述這個過程。

大意就是 Windsurf 的核心邏輯其實是放在一個額外的程式並且做為 server 跑起來(這個 server 是跑在 localhost 的),跟 IDE 透過 HTTP 來溝通。例如說你在 Windsurf Chat 中寫的 prompt,會被送到本地的這個 server,server 處理完畢之後回傳結果。

而問題就出在這個 server 完全沒有任何 auth 或是 CSRF 的保護,所以身為攻擊者,我可以寫個網頁,直接 POST 一個「幫我執行 XXX 指令」的 prompt 到本地的 Windsurf server ,它就會開心地幫你執行。接著我把這個網頁傳給其他人,其他人只要點了就會中招。

雖然 Windsurf server 的 port 是隨機的,但只要簡單做個 port scanning 就可以找到,這沒什麼問題。

有問題的是另一個地方,那就是這個 server 只接受 content-type 為 application/proto 的請求,而瀏覽器預設是不支援這個 content type 的(非簡單請求),需要開 CORS。也就是說,如果這 server 沒有支援 CORS,瀏覽器是不會幫你發出這個請求的。

好巧不巧地,Windsurf server 原本就不是給瀏覽器前端去呼叫的,所以當然沒有支援 CORS,因此瀏覽器就送不出請求,看起來無解了。

這時候 s1r1us 想起了他以前打 CTF 的經驗,腦中蹦出了一個名詞(這我自己幫他加戲的):DNS rebinding!

舉例來說,假設 huli 是我的 domain,我就設置 huli 的 DNS 紀錄,A record 設兩條,一個是真的 server IP,另一個是 127.0.0.1。

接著在瀏覽器執行 fetch(“huli/sendMessage”) 並且帶上 payload 跟 header,接著瀏覽器就會發送一個 CORS 請求到我的 server,此時我回應 OK,允許瀏覽器發送真的 POST 請求。

這時,我把 server 關掉,讓這個 IP 沒辦法訪問,瀏覽器就會很聰明地 fallback 到另一個 A record,也就是 127.0.0.1,並且發出 POST 請求。這就是 DNS rebinding 的應用,一個 domain 對應到兩個 IP,讓瀏覽器先用 A 再用 B,藉此繞過原本 local server 不支援 CORS 的限制。

透過這個方式,就能夠讓瀏覽器發送 CORS 請求並且包含這個自訂的 header,順利攻陷 Windsurf。

Git歷史裡的祕密

一定有很多人都曾經不小心把 secret commit 進去 git 裡面過,而發現之後可能就立刻把 secret 刪掉,再 commit 一次。

但是 git 畢竟是個版本管理的程式,你沒有刻意把紀錄刪除的話,紀錄是永遠都會在的。因此表面上看起來沒 secret,實際上去找的話,就能從記錄中還原出來。

而有個資安研究員 Sharon Brizinov 就寫了個工具大規模去掃,先從 bug bounty 平台上獲得公司清單,然後問 AI 這些公司的 org 叫什麼名稱,有哪些 repo,再去掃這些 repo,最後找到一堆 GCP/AWS/Slack/GitHub token,回報後總共獲得 64k 美金,折合台幣約 190 萬元。

話說作者在掃描的時候大量運用一個叫 TruffleHog 的開源工具,可以確認 git repo 裡有沒有洩漏的 secret,找到後還可以確認是否有效,非常方便。

而文章有提到 TruffleHog 其實原本就能找歷史紀錄,那為什麼作者要重新弄一套呢?這是因為有些檔案太大導致 TruffleHog 會出問題,自己把檔案從紀錄中還原之後,成功率會大大提高。

每次都很佩服這種專門找某個洞然後寫工具大規模去掃的,把程式放在背景跑,找到了就發個訊息通知自己,怎麼想都覺得滿帥的

休學前先想簽證

三不五時滑個社群就會看到有人在討論大學休學這個議題,我對「要不要念大學」或是「學歷有沒有用」這些議題其實沒什麼興趣,但身為一個過來人,我覺得有個角度滿值得分享給大家的,那就是:「出國工作」。

這是我拿著高中學歷這麼久以來,目前唯一感到不方便的地方。

辦理某些國家的工作簽證時,學歷是會被列入考量的。

以我自己待過的新加坡跟日本來講,都是會看的。新加坡的工作簽證基本上有兩種,EP 跟 SP,EP 會更方便一點,以前我身邊朋友們幾乎都拿 EP,就我拿 SP。

前陣子查了一下,新加坡最新的規定已經有把學歷明文列上去了(EP),雖然說大學沒畢業還是有機會拿 EP 或是改拿 SP,但學歷會列入評分標準是肯定的。

日本的話也是,規定就寫著相關科系大學畢業或是 10 年以上實務經驗,沒有的話只能另尋管道,像我一樣考個日本的 IT 證照來符合資格。之後想用高度人才身份申請永住的話,沒有學歷直接少 10 分,這 10 分可能讓你從等一年變成等三年。

總之呢,如果你正在念大學想休學或是輟學,可以先想想自己未來兩三年有沒有想出國工作的打算,如果有的話,建議先去查一下該國家的簽證規定,確保自己是符合資格的。我之前也寫過一篇比較完整的文章,有興趣的話可以一起看。

YouTube頻道Email外洩

今天來分享個洩漏 YouTube 頻道 email 得到 2 萬美金賞金的故事,有些細節滿有趣的

YouTube 後台有個 API: /youtubei/v1/creator/get_creator_channels 可以拿到一些頻道營收相關的資訊,其中有個叫做 channelIds 的參數,如果填入了別人的,一樣可以拿到結果,但問題是拿到的都是一些公開資訊,沒什麼用。

一般來講差不多到這邊就是死路了,但作者 brutecat 之前在研究 Google API 時,發現了一條新的路。當你傳送的 request body 的值有錯誤的時候,server 會回傳錯誤資訊,舉例來說,你傳 browserId: 1,server 會跟你說:「browse_id 應該是字串」。

而 Google API 除了支援一般 JSON 以外,也支援 JSON + protobuf 的形式,在這個前提之下 request body 會進行序列化,然後直接用 array 傳進去,如:[1,2,3,4,5,6] 這樣,不會有欄位名稱。

因此只要傳入這樣一個陣列,就會得到一段錯誤訊息跟你說每個欄位叫什麼名稱,型態又是什麼,間接還原出來這整個 API 能夠接收的參數。

因為這個發現,作者找到了一個 includeSuspended 的隱藏參數,加上去之後 response 會多一個 externalContentOwnerId,拿這個 ID 去打別的 API,就能拿到這個 owner 背後所關聯的 email。

故事大概是這樣啦,原文有更多細節,例如說會解釋什麼是 content ID 等等,但核心大概就是「找到原本沒公開的參數」這一點,從這邊突破進去,這點滿有趣的。

,這位 brutecat 之前也找了另一個也是洩漏 email 的拿到一萬美金,太神啦。

連字造成網址偽裝

我知道有些工程師很愛用一種字體,會把 >= 直接顯示成一個字,像這種把多個字母合在一起顯示,有個專有名詞叫做「Ligature」,中文通常翻作連字。簡單來說,就是字體可以規定某幾個特定字母連在一起時該顯示成什麼樣子。

而近期有一位叫做 yuki yamaoto 的人回報給 Chromium 一個 bug,就是因為這個連字功能所造成的。當你在 Android Chrome 上造訪 http://googlelogoligature[.]net 這個網址的時候,就會出現我附圖這樣的狀況

這是因為 Google 自己用的字體會把 googlelogoligature 這一串字已連字的方式顯示成 Google 的 logo,所以就變成一種 URL spoofing,讓人以為是 Google 官方網站,但其實不是。

以前類似漏洞都是利用 Unicode 的一些奇怪特性,這是我第一次看到還可以用連字來攻擊,真的很有趣,這個 bug 最後也拿到了 15000 美金的賞金。

參考資料:https://issues.chromium.org/issues/391788835

AI假漏洞報告氾濫

今天看到一篇文章《AI Slop Is Polluting Bug Bounty Platforms with Fake Vulnerability Reports》在描述 AI 產的假報告如何污染 bug bounty。

故事要從 curl 公開的一份 bug bounty report 說起,這份報告看似有道理,還附上程式碼來讓你 reproduce,但細看之後會發現整份報告都不合理,強烈懷疑是用 AI 產生的假報告。

而且還真的有些公司會因為人力不足,直接花錢應付了事,為一個根本就不存在的漏洞付錢 😅

這種現象一直出現的話就是劣幣驅逐良幣,你用 AI 隨便產個假的東西就可以拿到錢,結果我認真找了兩天的漏洞你說我 Duplicate/Not Applicable

上面是文章中的說法,不過我去看了一下原始資料,curl 的那個 report 看起來確實是亂掰的沒錯,報告中提的 commit 不存在。但是「有其他公司會付錢」這件事就不一定了。

文章的依據應該是同一個 bug hunter 在一個月前有其他 valid report 的紀錄,不過因為都是非公開的,無法得知報告內容,說不定以前人家也是乖乖找漏洞,最近才開始用 AI 寫報告(?)

開源授權小問答

滿好奇大家對於開源授權的了解程度到哪裡,直接來個開場小問答。

第一題:當你看到有個 GitHub 的公開專案沒有任何 license 相關資訊,而你想要使用這個專案,此時該怎麼做最適當:

(A) 因為放 GitHub 就是開源,直接 clone 下來用就好
(B) clone 下來用,並在自己的專案中附出處,表明有用到這個 repo
(C) 沒有任何 license,所以只能看而已不能用
(D) 雖然沒有 license,但除了看還可以 fork,不過還是不能用

第二題:有個採用 MIT 授權的 GitHub 公開專案,在附上原本 LICENSE 檔案的前提下,有哪些事情是允許的(複選):

(A) clone 下來用
(B) clone 下來用,但不特別標注來源 repo 是哪裡
(C) clone 並把 commit 紀錄全部刪掉之後重新傳到 GitHub 新的 repo
(D) 把這個專案包成 SaaS 拿去賣
(E) 在閉源專案裡使用它
(F) 把程式碼包成壓縮檔,拿去網路上販賣

回答前先聲明一下,因為非專業人士,這兩題的答案我沒有 100% 把握,但我能講出背後的理由。如果有解讀錯誤的地方,麻煩在留言區不吝打臉並附上證據,我會修改原文。

第一題的答案是 D,你可以看可以 fork,但不能用。

GitHub 為了幫助大家了解各種開源授權,弄了一個 choosealicense 的網頁,其中有一個 No License 的頁面,說明了在沒有附上任何授權條款的前提下,就代表你保留所有權利,所以連複製都不行。

但是,因為你上傳到 GitHub 了,所以要遵守平台的 ToS,而 GitHub 的 ToS 就是允許其他使用者觀看以及 fork 你的 repo,因此 fork 是可以的,但 fork 後你也不能改它,因為你還是沒有 modify 或 copy 的權利。

第二題的答案是「全部都可以」。

MIT License 裡面寫著只要你附上了原本的 LICENSE 檔案,你可以「use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software」,基本上想做什麼就做什麼,拿去賣或任意修改都是可以的。換句話說,只要附上原本 LICENSE 檔案(跟裡面的 copyright),沒有什麼不能做的。

看到這裡,不曉得大家會不會覺得 MIT 授權能做的事比自己想得還寬鬆許多?居然還可以直接拿去賣。至少我第一次知道的時候是這麼想的沒錯,以前都是看別人用我就用,沒讀過授權條款本身,讀了才發現原來這麼寬鬆。

最近圈子裡出現了兩起授權爭議相關事件,第一件跟工研院有關,但這件已經很多專業的人跳出來講了,就先不聊了。我自己對第二件比較有興趣,先強調一下這件雖然也與授權有關,但跟工研院的事件完全不同,所以不能混為一談,可以視為兩個獨立事件。

事件發生在 4/25,@stanma9107 跳出來指控 @clarencetw 的 expo-tappay-ios 這個專案是抄襲自他的 expo-tappay-apple-pay,而指控的內文格式直接參考了剛講的工研院事件的 issue,導致許多人覺得這又是一起類似的事件。不過就像我剛講的一樣,在仔細了解過後,會發現兩起事件完全不同。

指控內容主要有兩點:

  1. 我就有開源你為什麼 Fork 完還要另開專案複製 Source Code
  2. 完全移除原始專案的 LICENSE 與作者資訊

先不管開源授權的話,站在一般的角度來看,這兩點其實是有道理的,「用我的專案就該給我完整的 credit」跟「你可以 fork 幹嘛直接開新的,是不是想當作自己寫的」之類的,我都能理解。

但如同開頭講的,在 MIT 授權的前提下,只要原本的 LICENSE 有保留,不必特別寫出處,也沒有一定得 fork,甚至其他人直接拿去賣錢也可以。

而這個專案值得討論的點在於,只在 package.json 裡面有一行 license:MIT,並沒有其他 LICENSE 檔案,就會構成兩個路線:

  1. MIT 授權不成立?
  2. 也算 MIT,但沒有 LICENSE 所以沒東西複製

如果是第二種路線,代表也沒什麼抄襲的問題,在 MIT 授權的前提下直接 copy 全部改掉都可以,而原本的條件「必須附上 LICENSE」也沒東西可以附。但我自己覺得「宣稱自己是 MIT 授權但沒有完整的 LICENSE」這件事,說不定會更偏向第一種。

總之呢,在我看來這確實有討論空間,也是與工研院事件差很多的地方。工研院的案例原本的專案就有 LICENSE,很明顯是違反授權,但這次的專案並沒有 LICENSE 檔案,只有 package.json 中標明是 MIT,所以「移除原始專案的 LICENSE」這件事是不存在的。

這個事件也已經在雙方有共識的狀況下落幕,兩方我都不認識,雖然還有其他角度跟觀點可以討論,我先不多做評論。

總結一下,我覺得我們這些局外人從中可以學習到的是對開源授權有正確的認識,當你明確表示你的開源專案是 MIT 授權的時候,代表其他人只要附上 LICENSE 檔案,想幹嘛就幹嘛。如果有其他要求,例如說禁止商用或是衍生專案也要開源等等,那應該要選擇其他的授權條款。

當你在 GitHub 上傳了一個專案,就只是公開程式碼而已,在沒有明確附上 LICENSE 的前提下,別人其實也不能拿去用。如果想讓別人使用,記得要指定好授權,而且要先了解各種不同授權的內容差在哪裡,才能選到適合自己的。

補充文章:https://ossf.denny.one/en/legal-column-list/513--mit.html

Unicode編碼入門

「編碼」一直是個有點小複雜的議題

很久以前就知道一篇文章:「每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(沒有藉口!)」,但拖延了很久才看

幾年前找了個時間研究一下 UTF-8、UTF-16、UTF-32 跟 Unicode 這些東西,靜下心來看發現好像也沒有這麼難,於是寫了一篇跟編碼有關的文章,試圖用白話文的方式從本質上去理解編碼這件事情到底在幹嘛

文章的定位是希望沒有程式基礎也能看懂,所以寫得滿淺的,任何人只要想理解什麼是 Unicode 或是 UTF-8 都適合觀看

visited歷史洩漏修補

前幾天看到 Chrome 在新版中把 :visited 的一個小問題修掉了,簡單講一下來龍去脈。

沒點的連結是藍色,點過的是紫色,應該很多人都有這個印象。但其實除了預設的顏色之外,你也可以透過 a:visited 這樣的方式去調整「已經點過的連結」的樣式,無論是改顏色或者是加其他東西都是可以的。

不過這個功能方便歸方便,背後的隱憂是如果我們能偵測出這個顏色變化,就能反過來推導出某個 link 是否被點擊過,就等於是洩漏了使用者的 history。

因此呢,最新的 Chrome 就把這個問題修了,把 :visited 的生效機制改掉,不再是 global 的,而是分區計算。這就像以前我提過的快取分區一樣,都是為了解決這些 XS-Leaks 的問題。

但話又說回來,實務上能利用這些攻擊的情境多不多呢?我是覺得沒有很多啦,因為這個手法比較像是「給一個連結 A,知道使用者是否造訪過 A」,而不是「直接洩漏出你造訪過 A」。

我看過最多的應用情境只有 CTF 而已,已經是個在 CTF 中出現過不少次的手法,但拿到現實生活中利用的話,成功率跟可行性應該都還是偏低的。Chrome 官方也有一篇介紹這次修補的文章

另一個ChatGPT漏洞

「ChatGPT」有漏洞,但不是那個 ChatGPT 😆

剛剛看到有人轉 TWCERT/CC 的一篇文章,標題為「ChatGPT 漏洞遭大規模濫用,美國為主要攻擊目標」,內容寫說:

資安業者Veriti的研究員發現一個正被積極利用的伺服器端請求偽造(SSRF)漏洞,編號為CVE-2024-27564(CVSS:6.5)。此漏洞允許攻擊者利用ChatGPT的pictureproxy.php元件(commit ID為f9f4bbc),通過「url」參數發起任意請求,繞過安全控制,控制ChatGPT請求指定資源,從而可能導致敏感資訊洩漏。

我想到之前在講 Material theme 的事件時,也有人回說 ChatGPT 被爆了一個漏洞,但人家根本沒用 PHP,看來就是這個了。

我去找了一下 CVE 紀錄裡面附的參考資料,發現這個漏洞指的是 dirk1983/chatgpt 這個 GitHub repo,只是簡單用 PHP 做的一個 ChatGPT wrapper,README 裡面寫說:

本项目完全开源,是PHP版调用OpenAI的API接口进行问答的Demo(中間省略)本项目定位是个人或朋友之间分享使用,轻量设计,不计划引入数据库等复杂功能。有需要的用户可以自行拿去修改,版权没有,改动不究。

所以呢,就是這個叫做 ChatGPT 的 PHP 專案有一個 SSRF 的漏洞,跟我們平時在用的 ChatGPT 基本上一點關係都沒有 😅

而且會架這種服務放在公網的,應該大多數也都是個人,我想不到有公司會這樣搞 😂

補充文章:https://www.twcert.org.tw/tw/cp-104-10060-5d64a-1.html

Ingress NGINX惡夢

今天又一個嚴重的漏洞被公開了,名為 IngressNightmare,顧名思義,就是 Ingress NGINX 的噩夢。

找到漏洞的是最近才剛被 Google 買下來的 Wiz,我看了看 writeup,大意就是在 Ingress NGINX 中有個 admission controllers,會接收一些參數之後,把參數組裝成 NGINX config 然後用 NGINX 去做驗證。

但是呢,組裝的過程有漏洞,可以跳脫原有流程插入其他的 config,而使用 NGINX 去驗證這個惡意的 conifg 時,就能觸發 RCE,而且這個 RCE 的點是 admission controllers,在集群內的權限是較高的,可以從這個點出發去打整個 k8s 的 cluster。

所以,只要 admission controllers 是對外公開的就有風險,難怪會取叫 IngressNightmare。

由於可以注入惡意 config 的地方很多,所以背後其實有三個漏洞:

  1. CVE-2025-24514 – auth-url Annotation Injection
  2. CVE-2025-1097 – auth-tls-match-cn Annotation Injection
  3. CVE-2025-1098 – mirror UID Injection

注入惡意 config 之後,這個 config 就會被 NGINX 執行,因此下一步是要找到要利用哪一個設置,才能執行程式碼。

而 Wiz 找到了一個叫做 ssl_engine 的設置可以載入檔案並執行,但這個檔案該從哪裡來呢?

這邊運用了一個在 CTF 滿常見的技巧:「請求暫存」,在 NGINX 中如果 request 超過一定大小,就會先被寫入一個暫存的檔案,雖然說這個檔案會立刻被移除掉,但是用 file descriptor 還是能存取到:/proc/31/fd/10 這樣子(PHP 的 session 功能也滿常這樣被利用的)。

因此,只要暴力去猜 PID 跟 FD,就能猜到檔案位置,利用發請求的方式以及 NGINX 的暫存功能,把檔案短暫留在 server 上。

全部湊起來的話,就能讓 NGINX 去載入你指定的 library,就達成 RCE 了。最後這個 Ingress NGINX 會用 nginx -t 去測試設定檔的漏洞為 CVE-2025-1974,跟前面提過的加起來總共四個漏洞。

看下來確實滿嚴重的,基本上只要 admission controller 有對外就 gg 了,而且從報告看起來,網路上似乎還滿多有對外的 😅

Next.js中介層繞過

Next.js 昨天剛爆出一個嚴重漏洞 CVE-2025-29927,可以繞過 middleware。雖然說 CVSS 給的是 9.1 分所以是 critical,但其實我覺得沒這麼嚴重,且聽我娓娓道來。

一言以蔽之呢,這個漏洞可以不讓 middleware 執行,因此如果你有在 middleware 做一些權限檢查,就可以繞過這部分。舉例來說,用 middleware 保護 /admin 頁面,當 token 驗證失敗時跳轉到 /,此時就可以用這漏洞繞過 middleware,直接訪問 /admin 頁面。

但我覺得之所以沒這麼嚴重,是因為通常就算 middleware 這關過了,後端 API 還是需要一個合法的 token 才能取得資料,在這狀況下會是空的,所以理論上你也只看得到前端頁面,看不到後端的資料。

除非你只用 middleware 保護一個後台,而且後台的操作也都是透過這個 middleware 統一驗證的,那確實就出大事了 😅

而漏洞的利用方法也很簡單,只要傳一個 request header 就行了:
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
或是
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware

原理是 Next.js 用這個 header 來驗證 middleware 有沒有被執行過,但沒有阻止外面傳進來,所以只要自己傳進來,Next.js 會以為有執行過,就跳過不執行了 😆

總之呢,如果你沒有用到 middleware 來做權限驗證的話,那相當安全。如果有用的話,可以檢查一下繞過 middleware 會不會出事。

發現漏洞的資安研究員的 writeup 以及官方公告。

參考資料:https://nextjs.org/blog/cve-2025-29927

Beyond XSS限時優惠

《Beyond XSS:探索網頁前端資安宇宙》是我之前寫的一本專門探索網頁前端資安的書籍,內容涵蓋了各種熱門與冷門的技巧與漏洞,如 XSS、Prototype Pollution、DOM clobbering、CSS injection 或是 XSLeaks 等等。

資安背景的人閱讀後可以學到更多專屬於前端的攻擊方式,前端背景的人也可以從另一個角度看看自己所熟悉的東西,無論是哪一種,都會學到不少新知識。

雖然說書籍原本的目的是想盡量寫的淺顯易懂,但老實說書中的內容對初學者來說還是有點硬,需要一點時間慢慢研究。但就算只是先大概翻過,對名詞有個印象,我相信還是很有幫助的。

今天有博客來的一日限時活動,這本書在搭售的名單裡面,與另一本機器學習的書籍一起買的話有 66 折的優惠,有興趣的朋友可以參考看看。

Material Theme誤判後續

就在四天前,微軟的 VS Code 團隊道歉了,說 Material Theme 被判定為惡意軟體是 false positive,誤會一場。

兩週前 3/2 我有寫了一篇貼文談 Material Theme,主要是在講雖然它可疑,但沒有證據證明它是惡意軟體,因此還需要再等一段時間才能有結論。

在寫那篇貼文時,我的立場其實是「微軟應該要有確切證據才能把套件下架」,文章底下也有許多網友的看法,看了看之後我思考了一下,改成了贊同微軟的做法:「有足夠的信心就能先下架」,但前提是在下架時需要十分謹慎。

當某個套件足夠可疑時先下架,或許就能搶先一步保護使用者,這是好的沒錯。但如果是 false positive 呢?那作者的名聲就會受到損害。就算事後做出澄清了,能看到消息的人又有多少呢?

因此,下架時要更小心,更強調「還在驗證中」這件事,在這點上,我覺得 VS Code 團隊還有進步的空間。他們發表的言論比較像是:「雖然還沒完全確定,但我滿有自信它是惡意軟體」,而不是更中性的「還沒確認,請等我們驗證完」。

由於兩週前在寫這件事的時候就覺得有滿多點可以聊的,因此原本就打算事情告一段落來寫篇文章,叫做:《VS Code Material Theme 不是惡意軟體——安全的線該畫在哪?》。

內文會稍微整理一下事情的經過以及結果,提出我自己的一些看法。其實原本還想要聊「Editor/IDE 本身該如何防禦惡意的擴充套件」這件事情,但寫著寫著有點累了,以後再說吧。

至於有關 Material Theme 開源授權的支線故事,這段我倒是沒有仔細研究,因為我認為與它是不是個惡意軟體關係不大,就沒特別聊了。

用Favicon玩遊戲

當你打開一個新的分頁時,頁籤的左邊通常會出現一個圖示,我們叫它 favicon,就算我們切到其他分頁,這個 favicon 也可以讓我們快速辨識出這是哪個網站。

這樣的一個小東西,利用到極致可以幹嘛呢?你可能要說可以增加網站辨識度什麼的,不是,答案是可以玩 flappy bird 跟 pong。

那要怎麼利用這個小小的 favicon 來玩遊戲呢?

網頁本身可以不斷更新 favicon,一秒大概可以切換 4 張,而 @trunarla 就利用了這個特性做了個 flappy bird 的遊戲,favicon 就是遊戲畫面,按下空白鍵就會讓鳥飛起來。我有試玩了一下,雖然畫面很小看久眼睛有點痛,不過還滿有趣的。

但這還不是最厲害的了,而是 @trunarla 的朋友 @itseieio 受到啟發後,決定用 240 個 tab 排成 8*30 的畫面,並且用這個畫面來渲染知名的遊戲 pong(就是有顆球會在左邊右邊彈來彈去的那個)。

@itseieio 自己寫的文章裡面記錄了很多有挑戰性的小地方,例如說分頁被放到背景之後就會限制 setInterval 的頻率,導致畫面切換很慢,那該怎麼辦呢?

解法是用一個 web worker,就能在背景也能快速更換 favicon。另一個挑戰是這麼多的 tab 要怎麼互相溝通?最直覺的想法是寫個 websocket 讓 server 搞定,但光是初始化就要一些時間,於是用了純前端的做法 broadcast channel,在前端讓一個主頁面處理,再把消息廣播到其他分頁。

文中有紀錄更多細節,包括整體 size 的計算以及實作「從頁面跑到 favicon 的效果」等等,都非常有趣,但文章中我最喜歡的是作者引用美國的魔術師雙人組合 Penn and Teller 中 Teller 的一段話:

Sometimes magic is just someone spending more time on something than anyone else might reasonably expect

所謂的魔法,有時就只是某個人在某件事上花了你難以想像的時間

既然都可以拿分頁來玩遊戲了,感覺可以再進化,例如說可以 render 低畫質的 YouTube 影片之類的。

影片:https://eieio.games/blog/running-pong-in-240-browser-tabs/

Bybit竊案來源查證

今天看到一篇動區的文章在寫老高的最新影片在講 Bybit 竊案,但是內容沒有講對。

動區的文章中指出,老高影片中提到硬體錢包上地址很難確認這件事情是錯的,「實際上問題是他們一開始簽進去的多簽介面就是假的,Ben Zhou在直播中有強調他們有經過確認,Ledger上面的數據也確認無誤(跟一開始發起的是一樣的),但還是被盜了,所以怎麼檢查也不會查到,即使有確認也沒用(因為數據什麼的都會跟第一個簽名的一樣)。」(括弧內直接引用原文)

我平常不看老高影片的,但因為這篇文章跑去看了。

老高確實有講錯的地方,他說被植入木馬的是 Bybit 的人,所以會看到假的介面。這個在一開始確實有人這麼猜,但已經證實是錯的了,被植入木馬的是 Safe{Wallet} 那邊的人。可能老高寫這篇稿的時候還太早,事情還沒塵埃落定就寫了。

而動區的這篇文章,我上面引用的那個段落,跟我所知道的不太符合 😅 我上次有寫過了,還直接引用了 Ben Zhou 直播的片段中所說的原話,他說他沒有完全檢查硬體錢包上顯示的那些 code。

所以我滿想知道資安專家所講的「Ben Zhou在直播中有強調他們有經過確認,Ledger上面的數據也確認無誤」這段是怎麼來的,來源是哪裡。

或許這就是附上來源的重要性吧,也是我一直持續在做的事情,要附上來源才能證明你所講的是真的,否則可信度就會大幅降低。當然,我並不是說他們寫的一定是錯的,說不定 Ben Zhou 在後續的直播中確實有提到,那錯的就是我了,是我沒有查到這類的資訊,我也很樂意修改文章,提供正確的情報。

話說上次不是提到了被駭的是 Safe{Wallet} 那邊的 S3 bucket 嗎?那到底是怎麼被駭的呢?這兩天 Safe{Wallet} 那邊的調查報告也出來了。

是其中一個開發者的筆電被駭了,駭客直接去拿電腦上的 AWS session token,直接用這個 token 就跟用 cookie 類似,因為已經是登入之後了,所以不用再過一次 MFA,就能直接上傳檔案。

那為什麼開發者的筆電會被駭呢?是因為開發者的筆電上跑了一個專案,而這個專案裡面有惡意程式碼,所以猜測是透過社交工程的方法,試著讓該名開發者去執行。

這個組織以前幹過類似的事情,只要開發者把那個專案跑起來,就中招了(其實也滿合理的,你都跑了其他人給你的程式碼了,要埋木馬應該不難)。

不只大的駭客組織會這麼幹,在幣圈這種事已經屢見不鮮了。例如說假裝 hire 工程師,給一個專案外加高薪讓你幫忙修改一些東西,殊不知只要跑起來,就直接掃你電腦裡面有沒有放密碼或是 private key,直接把你洗劫一空。

但這次的目標不是個人,而是他所任職的公司,因此潛伏在電腦裡面,伺機而動。時機一到,就利用電腦上的 AWS session key 上傳檔案,正式發起攻擊。

有許多公司對外的防護做得不錯,但從內部打進來看起來還是最容易的。

影片: