隨意聊

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

共 102 篇 第 5 / 6 頁 RSS 訂閱

連字造成網址偽裝

我知道有些工程師很愛用一種字體,會把 >= 直接顯示成一個字,像這種把多個字母合在一起顯示,有個專有名詞叫做「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 上傳檔案,正式發起攻擊。

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

影片:

ToDesktop建置機漏洞

只是想裝個 Cursor 來玩玩,卻意外發現個嚴重的漏洞?

一名資安研究員 xyzeva 在安裝 Cursor 的時候,發現了一個連線到 todesktop[dot]com 的請求,於是就好奇往下追,去看看這是什麼。發現 ToDesktop 是個能夠讓快速讓 web app 變成 desktop app 的服務(其實就是外面包一層 Electron 啦),也一併提供了 installer, auto update 等功能。

因此在安裝 Cursor 時,才會有連線到 ToDesktop 的請求。

經過了一番摸索之後,xyzeva 自己試用了一下 ToDesktop 的服務,做了個簡單的 app,並且在 package.json 的 postinstall 裡面放了一段 reverse shell 的程式碼。

因為 app 最後是在 ToDesktop 的 server build 的,所以 reverse shell 被觸發,xyzeva 成功進入了他們的 builder。結果找著找著就看到 config.prod.json.encrypted 跟 config.prod.json,一打開發現 HSM 的 secret 跟各種 credentials 都在裡面。

拿到這些 credentials 以後,可以自己簽一個合法的 package,然後自動幫有用 ToDesktop 這服務的軟體更新,如 Cursor、ClickUp 或是 Linear 等等。

最後 xyzeva 從 ToDesktop 那邊拿到了 5 千塊美金的賞金,而 Cursor 則另外加碼了 5 萬美金。

整件事情發生在去年 10 月,ToDesktop 被找到漏洞後也在 26 小時內快速修復,然後找資安公司來做 audit,一直到一月底完成,二月底複測結束,因此三月初公開漏洞。

,原文有更多細節,有興趣的可以看看。

話說這種 builder 拿 reverse shell 的操作滿常見的,你在 GitHub Actions 或是 Heroku 之類的也能做到(之前我有試過可以,現在不確定啦),畢竟這些 builder 就是要跑程式碼的,所以會執行任意指令也不意外。

但重點是權限的控管,不能讓這些 builder 有太多敏感資訊,不然就全部都曝光了。這些 builder 的 threat model 應該會是:「假設外人可以執行任意指令,該怎麼防禦?」,例如說弄個 sandbox 或是跑一個沒什麼權限的 container 之類的,而 ToDesktop 忽略了這點,就直接 gg 了。

Material Theme下架疑雲

到底是刻意製作惡意擴充套件、供應鏈攻擊,還是全部烏龍一場?

前幾天在推特上有看到 VSCode 的知名擴充套件 Material Theme 被強迫下架,而且會由 VSCode 主動移除,理由是裡面包含惡意程式碼,這幾天也看到一些新聞或是臉書上有人在分享這件事情。

剛剛花了點時間看了一下原始資料,發現事情並不單純。

目前看起來講述比較完整的新聞是 BleepingComputer 的這一篇:VSCode extensions with 9 million installs pulled over security risks [1],裡面提到了資安研究員 Amit Assaraf 與 Itay Kruk 向 VSCode 回報這個套件可能含有惡意程式碼,在他們自已發表的文章 A Wolf in Dark Mode: The Malicious VS Code Theme That Fooled Millions [2] 中是這麼說的:

A deep analysis concluded that hiding inside it’s codebase are multiple red flags indicating malicious intent. The malicious code seems to be inside a dependency of the theme, which was compromised.
經過深入分析後發現,其程式碼中隱藏著多個顯示惡意意圖的警訊。惡意程式碼似乎存在於該主題的一個依賴項內,而該依賴項已遭到入侵。

但是文章中並沒有提到具體細節,雖然有說更多資訊公開後會更新文章,但目前還沒更新。

事情的發生是在 2/26,這些套件被強制下架後在 Hacker News [3] 上引起了相關討論,在微軟官方的 Visual Studio Marketplace GitHub repo [4] 中也有這件事情的討論串,在 HN 上 VSCode 團隊的成員 Isidor 有出來說明狀況:

A member of the community did a deep security analysis of the extension and found multiple red flags that indicate malicious intent and reported this to us. Our security researchers at Microsoft confirmed this claims and found additional suspicious code.
社群中的一名成員對該擴充功能進行了深入的安全分析,發現多個顯示惡意意圖的警訊,並向我們報告。微軟的安全研究人員隨後確認了這些發現,並進一步發現了額外的可疑程式碼。

而 GitHub 的討論串則是有 VS Code Marketplace 的 PM Sean 出來回覆:

We take the decision to remove seriously and thoroughly verify any reports. To protect developers, we also prioritize speedy removal of positives. We’ve posted the reason for removal in RemovedPackages, where we plan to add any future removals as well.
我們對移除決策持謹慎態度,並會徹底驗證所有舉報。為了保護開發者,我們也優先迅速移除確定存在問題的項目。我們已在 RemovedPackages 中發布了移除原因,並計劃未來將所有移除記錄統一發布在該處。

而在 RemovedPackages 中紀錄的原因是:

A theming extension with heavily obfuscated code and unreasonable dependencies including a utility for running child processes
一個主題擴充功能,其程式碼經過高度混淆,並包含不合理的依賴項,例如用於執行 child process 的 utility。

好,看到這邊,我相信大家應該很好奇這個惡意擴充套件到底幹了什麼。至少身為對資安有興趣的人,我很好奇他到底偷了什麼,那些惡意程式碼又是什麼。

而資安人的報導《資安風險!微軟禁下載量達900萬次的VSCode Material Theme擴充套件》[5] 中,有一段是:

技術專家進一步檢查發現,擴充套件中的「release-notes.js」文件包含高度混淆的JavaScript代碼,這在通常追求透明和可讀性的開源項目中是非常罕見且危險的信號。混淆的程式碼中頻繁出現與使用者名稱和密碼相關的引用,這進一步增加了安全疑慮。

這段的來源應該是開頭提過的 BleepingComputer 的報導中所寫的:

A partial deobfuscation of the code showed numerous references to usernames and passwords
對該程式碼進行部分反混淆後,發現其中包含大量與使用者名稱和密碼相關的引用。

所以目前已知的證據是:

  1. 擴充套件的某些程式碼經過混淆
  2. 用到了不合理的依賴,會去呼叫 child_process
  3. 反混淆後發現有提到許多使用者名稱跟密碼

看起來似乎…確實有點可疑?

但仔細想想會發現,可疑的不止上面這些,而是原始程式碼都有了,為什麼給不出一個罪證確鑿的證據說:「你看這段程式碼,就是偷偷讀取你的 SSH key 然後傳到這個 domain 去」。一開始回報的資安人員只說有很多 red flags,而微軟那邊也確認發現了可疑的程式碼,那第一個重點就出現了,到底那一段混淆過的程式碼,是單純的可疑,還是真的有問題?

那如果有問題,背後到底做了哪些惡意的事情?雖然混淆過了比較難解析,但微軟一定是有能力去反混淆的。

但很遺憾的是,目前無論是微軟還是當初的資安研究員,都還沒提出確切的證據。甚至在 GitHub Issues 中有些人把程式碼反混淆之後,說看不出來可疑的地方,而那些「提到許多使用者名稱跟密碼」的部分可能跟 URL parser 的一個 library 有關(URL 上面可以帶帳號密碼,因此 URL parser 需要處理)。

總而言之呢,截止目前為止,沒有一個人拿出證據說:「對,就是這段惡意程式碼有問題,它會偷你東西」。

而套件的作者 equinusocio 也在 2/28 的時候發了一個 Issue [6],描述了他的視角,說在他看來可疑的地方只有使用了一個太舊的 package 而已,明明就沒有經過證實,怎麼就把我的套件都下架,甚至連帳號都 ban 了。

也在裡面公開了一直被說有問題的檔案 release-notes.ts 混淆前以及混淆後的原始碼,並且指控 VSCode 團隊散播未經證實的假消息:

As for the VS Code team — and by extension, @microsoftopensource — the entire team, and particularly @isidorn, publicly accused me of criminal activity by spreading false and unverified information.
至於 VS Code 團隊,特別是 @isidorn,公開散播不實且未經證實的資訊,指控我涉及犯罪行為。

當然啦,整個故事還有其他案外案,包括了套件作者以前的其他事蹟(修改 commit 紀錄以及修改開源的 license,準備賣付費版的套件,有一說認為混淆程式碼是因為之後要賣付費版),以及有個技術網紅 t3dotgg fork 了一個號稱乾淨版的 Material Theme 重新上架等等,這些就都先不談了。

在我自己目前看來,儘管程式碼經過混淆確實可疑,但混淆過並不代表一定就是惡意程式碼。要說它是惡意程式碼,你必須要有明確的證據,這種事不能亂指控的,畢竟現在全天下都直接認定 Material Theme 就是惡意軟體了。

總之呢,我認為整件事情還沒蓋棺定論,還需要再讓子彈飛一會兒,目前還不能確認 Material Theme 含有惡意程式碼(因為沒有確切證據)。

故事大概會有兩種發展,看是微軟會先拿出證據一槍斃命,證實它就是個惡意軟體;還是拿不出證據反而變成 🤡,只要有疑慮,在沒有驗證過以前就可以把套件下架,讓無辜的套件背上惡意軟體的污名。

補充文章:https://www.informationsecurity.com.tw/article/article_detail.aspx?aid=11684

Bybit冷錢包竊案

終於可以來寫加密貨幣交易所 Bybit 被偷走 15 億美金的案例啦!

事情發生在 2 月 22 號,Bybit 的冷錢包被駭客直接偷走大約 15 億美金,換算成台幣快 500 億了,是史上最大宗的加密貨幣竊案。

事件一出來的時候,我就認為這會是個歷史性的事件,因為:

  1. 損失 15 億美金,史上最嚴重
  2. 是冷錢包出事,不是熱錢包
  3. 已經有證據證明是北韓的駭客集團 Lazarus Group 幹的

在講犯罪手法之前,我們先來看一下 Bybit 的冷錢包平常是怎麼簽署交易的。

他們在 Ethereum 上的冷錢包走的是智慧合約多簽錢包,多簽的數量沒有查到細節,有查到 3/5 跟 3/6 兩種說法,但總之需要有 3 個人簽署才會生效。

而整個錢包系統用的是一個叫 Safe{Wallet} 的東西,提供了一個介面讓簽署者看交易內容,實際要簽署的時候,需要使用 Ledger 提供的冷錢包。

當三個人簽署這個交易後,交易就直接送去鏈上了。

而這次的攻擊其實與冷錢包本身無關,是 Safe{Wallet} 這段被駭了。駭客入侵了 Safe{Wallet} 的 S3 bucket,修改了前端的檔案,讓那些 signer 看到要簽署的交易內容是 A,結果真正簽的是 B。因此就簽署了錯誤的交易,就是這麼簡單。

這邊有個細節是,一般會想到的「竄改交易」是例如說我想轉 100 塊到熱錢包,此時竄改成轉 100 萬給駭客的地址,但是在這個案例中並不是這樣。實際上駭客簽署的內容是去執行智慧合約的某個方法,讓自己有權限,就可以繞過後續的簽名,直接把錢轉走。

那為什麼不直接篡改交易就好,要額外多一步呢?我猜有可能是因為 :
(1) 這個地址有多個幣種,竄改交易只能轉一個幣種
(2) 轉更大額有風控機制會擋下來

總而言之呢,看似是轉給熱錢包的交易,其實是「授權給駭客的智慧合約」,三個簽署者都簽完,交易上鏈之後,就直接 gg 了。

我上一份工作做的是冷錢包相關的風險評估,看過不少交易所的文件跟架構,稍微有些理解,看到這事件我就想說不合理啊,這個流程有問題啊。

第一個大問題是,為什麼冷錢包轉帳的地址沒有白名單?這算是滿基本的操作,因為是冷錢包,所以通常轉帳的地址就那幾個,所以會設定一個白名單,設定白名單要先簽過一次交易,之後才能轉到這個地址。我查了一下,好像 Safe{Wallet} 本身沒有這個功能 😂

第二個問題是,為什麼沒有人確認自己簽的交易跟看到的是不是一樣?

我去找了 Bybit CEO 親上火線解釋的片段,其實流程裡是有的,但沒人照做,以下是英文逐字稿原文以及中文翻譯:

I use a a ledger as a hardware device for the last signing part. so after I signed and also check the The Ledger screen one of the issues with, at least from my experience, with the ethereum related cold wallet transfer is that it doesn’t exactly shows the destination.
我使用 Ledger 作為硬體設備來進行最後的簽署步驟。所以我簽署時也檢查了 Ledger 的螢幕。不過根據我的經驗,與以太坊相關的冷錢包轉帳存在的一個問題是,它並不會準確地顯示目標地址。

it shows a lot of code so it is not so I checked the code but I didn’t check fully. normally also the address the destination address is not inside of that multi-sig signing, so I signed.
它顯示了大量的 code,因此並不那麼直觀。我檢查了 code,但沒有完全檢查。通常來說,目標地址並不會出現在多重簽名的簽署內容中,所以我還是簽署了交易。

簡單來講就是,因為看不懂所以就不檢查了,有看跟沒看一樣。三個人可能都看過,但是都沒看仔細,就當作例行流程直接簽了。就算內容看不懂,只要能檢查到 to 的位置,應該就能發現 to 是一個陌生的地址。說不定其實也是個 UI + UX 問題,因為 Ledger 每次顯示的內容都不重要,所以每次都被略過不看。

所以呢,雖然是因為 Safe{Wallet} 前端被駭所導致的事件,但我覺得 Bybit 也要負滿大的責任,畢竟前端被駭在 Web3 世界早就不是什麼新鮮事,這個風險是絕對可以預測到的,明明知道風險卻沒有做任何對策,或是做得不夠徹底。

我以前看過的冷錢包流程中,有那種很安全的是 100% 離線的,例如說拿來簽署的 UI 是放在自己內網,而且簽署完之後還沒完成,不會直接上鏈,而是把簽署好的交易複製到某個硬體裝置,接著把這個裝置 帶去一個完全隔離的房間,用那裡面的電腦搭配上最後一個 key 去簽署(到這一步多簽才完整),此時在 UI 上可以看到正確的交易內容,確保交易內容無誤。

簽完之後,一樣把簽好的東西放到硬體裝置中儲存,再帶到外面的電腦,接上公網,把交易上鏈。

由於最後一步的電腦在一個離線的環境中,因此 UI 很難被篡改(除非有內鬼,那是另外一回事),能很大程度保證看到的就是最後簽的。要攻破整個流程,需要的成本會多很多。

總之呢,整件事情差不多就是這樣,沒有強制的白名單、三個簽署者也都沒有檢查簽的內容,只要竄改 UI 就能騙過這些人,然後偷走了 15 億美金。看起來人果然是資安最脆弱的一環,明明知道要檢查,但因為看不懂 + 以前也都是這樣的,一個失誤就釀成大禍。

補充文章:

GitLab重設密碼漏洞

今天看到 HackerOne 公開了一個 2023 年底的 GitLab 漏洞報告,最嚴重的那種,賞金 35000 美金。

查了一下發現是 CVE-2023-7028,只要知道 email 就可以透過漏洞,把重設密碼的信件送到自己信箱,輕輕鬆鬆重設其他人的密碼然後登入(如果沒有 2FA 的話)。

而這個漏洞的細節也很簡單,原本重設密碼的請求裡是這樣寫的:
{
“email”: “victim@gmail. com”
}

你只要把它改成 array:
{
“email”: [“victim@gmail. com”, “huli@huli .tw”]
}

GitLab 就會順便送一封重設密碼的信到我信箱,就是這樣 😅

身為開發者,看到這種漏洞的第一反應就是:「後端到底幹了什麼奇耙的事,為什麼陣列也能過」,於是我去找了 patch 來看。

看起來好像是原本拿到 input 中的 email 之後就呼叫一個 find_by_any_email 的方法,去找出背後對應的 user 然後寄信,而這些方法既支援字串也支援陣列,但用的時候是以 input 是字串去考量的,沒想到會有陣列的可能性,因此就出包了。

之後的 patch 把找 email 那段改成了簡單的 Email.confirmed.find_by(email: attributes[:email].to_s),先轉成字串再去找對應的 user 準沒錯,就不會寄到其他人那裡了。

話說這種型態的混淆一直都是很好的攻擊面,尤其是針對 JavaScript 或 PHP 這種超級彈性的語言,這種原本預期是字串卻變成陣列的攻擊滿常碰到的,但 Ruby 我就不太熟了,至少這次的 GitLab 漏洞原理也類似。

講到這個,我最喜歡看到的其實是背後用 TypeScript 寫的後端,因為很多開發者誤以為用 TypeScript 宣告了某個東西是字串,它就一定是字串,不知道這只在靜態檢查生效,動態才不管你 😆

參考資料:https://github.com/Vozec/CVE-2023-7028

公共CDN腳本風險

今天看到黑暗執行緒大大寫了一篇 CDN 相關的貼文,講了一下引用第三方公共 CDN 檔案的優缺點,而貼文底下也有不少回應補充(我也去補充了一下XD),由於這個議題很有趣,因此這邊再簡單講一下我的想法。

先說明一下,這篇提的情境是在網頁上引用來自於 unpkg 或是 cdnjs 等等這種第三方公共 CDN 的 JavaScript ,你對內容沒有掌控權,只能使用不能修改,跟自己把東西放到 CDN 是完全不同的情境。

我的想法是,除非是壞掉也沒關係的小玩具,否則一律建議不要。

使用那些公開免費的 CDN,最大的優點就是方便,直接 script 無腦引入就好,而且通常速度比放自己那裡快(假設自己那裡沒有開 CDN 的話)。

缺點的話主要就兩個,一個是那些第三方網站掛掉你的網站就跟著掛了,第二個是資安風險,你引用的那些來源被入侵你的網站也跟著被入侵,就是俗稱的供應鏈攻擊。

這些問題其實實際上也發生過不少次。例如說 2023 年 12 月我就寫過冷錢包公司 Ledger 的 CDN 被入侵的事件;還有去年 6 月才發生的 polyfill 事件,都是直接使用其他人 host 的腳本而導致資安問題的經典案例。

就連 Cloudflare 自己經營的 cdnjs 也曾經被打進去過,說明了這些第三方 CDN 的安全性可能沒有你我想像中的高。就算前端用了 integrity 防禦,當攻擊發生時,仍然會面臨兩個問題,第一個是網站會掛掉(因為檢查不通過),第二個則是如果那些腳本原本就是動態再引用其他網址,那 integrity 是無效的,因為腳本中的文字沒有變,而是引用的來源內容變了。

再者,以往使用這些第三方 CDN 的好處是因為快取的關係,別的網站用了你也能受益,只要下載一次就好。但自從 Chrome 在 2020 年開啟了快取分區(cache partition)的功能後,這點也不再成立。

總之呢,前端直接引用那些第三方 CDN 的 JavaScript,就是拿方便性來換取安全性跟穩定性。如同我開頭所說,如果是掛掉也沒差的小玩具我覺得倒是無妨,頂多一年掛個一次。

但若是公司的服務用了結果出事,那影響就比較大了,畢竟這個風險是完全可以避免的。

不過話說回來,其實整個議題與 CDN 這個技術沒什麼關係,本質上就是個「動態引入其他網站的腳本」的問題,當內容不可控而且是動態的時候,自然而然就會提高風險。

延伸可以參考我在《Beyond XSS》裡關於快取風險的章節,以及我之前寫過的 polyfill.io 事件。書籍版本也可以在天瓏找到

CSS高度動畫新招

如果你問我,HTML、JavaScript 跟 CSS 哪個最難,我大概會回答 CSS,並且送你一張 CSS 拉窗簾.gif。跟 JavaScript 比起來,CSS 進化的速度來得更快,每隔幾個月就出來一個新東西,解決了許多的經典難題。

不過就算沒有這些新東西,其實也能做出一個堪用的版本,或是乾脆直接用 JavaScript 來弄,大部分也都能搞定。但正是因為如此,導致許多人(包括我)的 CSS 知識可能一直都沒有進化,原地踏步,不知道有哪些新的東西。

舉個例子,一個點擊可以展開,再點一次可以收起來的摺疊元件(Collapse)大家應該都不陌生。那如果折疊的時候想加上一點動畫該怎麼弄?沒弄過的人會說這簡單,不就加個 transition: height 0.3s; 就行了嗎?

弄過的人會跟你說這樣沒用,因為 height 是 auto,這種狀況下不會有 transition。要解決的話不外乎就是三招,第一招是寫死固定高度,但通常沒辦法滿足需求;第二招是改成用固定的 max-height,既能動又不會真的讓高度寫死,而缺點是動畫時間會很奇怪;第三招則是請 JavaScript 出馬,在折疊前先把高度取出來再設置上去。

除了廣為人知的這三招以外,最近看到另外兩招新的也可以解決,第一個是 ChatGPT 推薦我用的 grid + grid-template-rows,利用 grid 會自己調整大小但又不是 auto 的特性來做,就能有 transition。

第二個其實才是今天想講的主題,只要在展開時把高度改成 height: calc-size(auto, size); 就搞定了,酷吧。

不過瀏覽器支援度很差,去年九月推出的 Chrome & Edge 129 才開始支援,其他瀏覽器直接死給你看。或許這也是為什麼許多新的 CSS 方法沒有受到這麼多關注吧?就算知道了,可能要先等個半年一年才能等到所有主流瀏覽器的支援,就算到了那時,整體支援率可能還只有 50% 不到,還要再等個三五年才能實際用在 production 上。

但總之呢,能用純 CSS 解決這個千古難題還是挺讚的對吧。

下次碰到需要幫 height: auto 加上 transition 時,如果可以保證使用者的瀏覽器都很新,不妨試試看。

CDN快取去匿名化

有一種攻擊手法叫做「deanonymization」,中文翻作:「去匿名化」,在網路世界中,每個人都保有一定的匿名性,但我們也都知道這層匿名性其實滿容易被打破的。

舉例來說,假設我發了我的 server 連結給 Discord 網友,當他點了之後,我的 server 就會直接收到他的設備傳來的網路請求,假設他沒開 VPN,那我就能拿到他的 IP 跟設備資訊等等,足夠辨識出他人大概是在哪個區域(例如說在台北或是東京之類的)。

但這畢竟也要我的網友主動點擊 URL 才行,而今天要介紹的手法不須要點擊也能做到同樣的事。有個 15 歲的高中生 daniel 前陣子就發表了一篇文章《Unique 0-click deanonymization attack targeting Signal, Discord and hundreds of platform》,分享了他是如何做到的。

Discord 在發送好友邀請的時候,會在手機上彈一個通知出來,這個通知會有加你好友的人的大頭貼照片,讓你方便辨識,十分合理。這時候你可能會想說,那我把 Discord 大頭貼設成自己的 URL 不就行了嗎?抱歉,這樣是行不通的,因為大頭貼只能上傳圖片,最後會被放到 Discord 的 server,前面掛 CDN,所有網址都是 Discord 在管的,這也是滿常見的做法。

然而,就是這個 CDN 開啟了去匿名化之路。

以 Cloudflare 為例,它有許多節點,例如說在東京連到的就是 NRT 節點,會從這邊下載資源,如果這個節點沒有,就會去 source 拉取並且存一份到節點中,別的東京使用者下次去 NRT 節點就拉得到資源了,速度會更快,這就是 CDN 運作的原理。

而 daniel 之前在網路上發現有人分享一個方法,可以透過 Cloudflare 自己的服務 Cloudflare Workers,強制把請求發送給某個特定 CDN 節點。

這是什麼意思呢?

對於某個特定資源 huli_avatar.png,我可以用這個方式,發請求給所有 Cloudflare 的 CDN 節點,並且透過 response header,來得知這個節點的快取狀況,我能知道是 HIT 還是 MISS,也能知道快取還多久會過期。

也就是說,當我發送 Discord 好友邀請給小明的時候,小明手機自動跳通知,去最近的 CDN 節點抓取圖片。接著,我利用剛剛講的方法,發送請求給所有節點,只要查看 response header,就能知道小明剛剛訪問的是哪個節點,進而推測出小明大概的位置。

簡單來說就是利用 CDN 快取機制來 leak 出使用者的大概位置,也算是一種 side-channel attack 了。

Signal 跟 Discord 都能用類似手法進行攻擊,不過這兩個聊天軟體都不認為這是個需要修的漏洞(我也不認為就是了),而 Cloudflare 最後修了那個可以透過 worker 發送請求到任意節點的問題。

我的想法是,這個手法有趣歸有趣,但是對那些聊天軟體來說,似乎確實超過了職責所在,畢竟就算不是透過這種方法,發 URL 點擊也還是能達到一樣的效果,而且更精準。況且這就是 CDN 的運作機制,要修的話也不知從何修起,成本滿高的。

分享這篇是因為故事很有趣,而且很完整,原文裡面有附各種圖片還有完整的 exploit 影片,推薦有興趣的人去看看原文。

影片:https://gist.github.com/hackermondev/45a3cdfa52246f1d1201c1e8cdef6117

DeepSeek資料庫裸奔

今天來分享一個過年時的舊聞,應該不少人看過了,就是 DeepSeek 的資料庫在網路上裸奔被發現的故事。

資安公司 Wiz 的研究團隊在 1/30 的時候發佈了一篇名為《Wiz Research Uncovers Exposed DeepSeek Database Leaking Sensitive Information, Including Chat History》的文章,揭露了整段故事的細節。

基本上要入侵的第一步叫做 reconnaissance,簡稱 recon,偵查的意思,從外部的角度去搜集各種資訊,最常見的就是去找出 subdomains 或是 Google Dorking 等等,先把公開的資源搜集一波,再決定下一步。

當找到 subdomain 以後,先掃一次 port,看一下有哪些有趣的發現,接著再繼續打。

而這次 DeepSeek 的漏洞是在掃 port 這邊就被找到了,簡單來說先掃到一個 subdomain: dev[dot]deepseek[dot].com,掃 port 發現上面開著 8123 port,結果一連進去就是一個公開的 ClickHouse,可以直接下 SQL query 並顯示結果。

整個過程就是這樣,一個裸奔的 ClickHouse 放在網路上,就算沒有被這間資安公司找到,可能過不久就被其他機器人掃到了。完全不需要驗證又直接開放在公網,暴露的又是資料庫,算是滿嚴重的。

補充文章:https://www.ithome.com.tw/news/155392