Kaspersky Password Manager 的漏洞

Hacker News Daily 上看到「Kaspersky Password Manager: All your passwords are belong to us」這篇,講 Kaspersky Password Manager (KPM) 嚴重的安全漏洞,另外在 Hacker News 上的討論「Kaspersky Password Manager: All your passwords are belong to us (ledger.com)」也有提到一些有趣的東西。

標題的 All your passwords are belong to us 是出自「All your base are belong to us」這個梗的變形。

這包安全問題主要的原因是因為 KPM 沒有使用 CSPRNG,而且也沒有正確 seed,所以極為容易被猜出密碼本身。

KPM 的 Web 版使用了 Math.random(),在各家瀏覽器主要是用 xorshift128+ 實做 Math.random(),作者沒有針對這塊再花時間研究,但很明顯的 Math.random() 不是個 CSPRNG:

The underlying PRNG used by Chrome, Firefox and Safari for Math.random() is xorshift128+. It is very fast, but not suitable to generate cryptographic material. The security consequences in KPM has not been studied, but we advised Kaspersky to replace it with window.crypto.getRandomValues(), as recommended by the Mozilla documentation page previously mentioned.

Note: Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.crypto.getRandomValues() method.

而桌機版則是用了 MT19937,理論上取得 624 bytes 的輸出後就可以重建整個 PRNG 的內部狀態 (於是就可以預測後續的 output),但這代表你要知道其他網站的密碼,這點其實有點困難。

但作者發現 KPM 在產生 MT19937 的 seed 只跟時間有關,超級容易被預測:

So the seed used to generate every password is the current system time, in seconds. It means every instance of Kaspersky Password Manager in the world will generate the exact same password at a given second.

於是可以直接暴力解出所有的可能性:

The consequences are obviously bad: every password could be bruteforced. For example, there are 315619200 seconds between 2010 and 2021, so KPM could generate at most 315619200 passwords for a given charset. Bruteforcing them takes a few minutes.

Hacker News 上有不少陰謀論的討論,像是:

Getting some DUAL_EC prng vibes.

Insert Kaspersky owned by Russia intelligence conspiracy here...

另外 Kaspersky 跟俄羅斯軍方的關係也是很知名,這些東西大概要到十來年後才會知道...

Dan Kaminsky 過世

Hacker News 首頁上看到震驚的消息,Dan Kaminsky 過世:「Dan Kaminsky has died (twitter.com/marcwrogers)」,目前還沒看到過世的原因...

Dan Kaminsky 最有名的「成果」應該是在 2008 年發現當時大多數的 DNS resolver 軟體實做有問題,可以被 DNS cache poisoning 攻擊,當年我有寫下來提到,但寫的很短:「DNS 伺服器安全性更新」。

攻擊手法是先發一個 DNS query 到 DNS resolver,然後馬上再送出一個偽造的 DNS response packet 給 DNS resolver 收,運氣好的話這個偽造的結果就會被 cache 起來。

記得當年的 168.95.1.1168.95.192.1 沒有太直接受到影響 (相較於其他的 DNS resolver),是因為這兩個 DNS resolver 後面有 server cluster 會打散流量,所以未必能猜對去查詢時用的 DNS server 所使用的 IP address,有點類似下面提到的緩解方案 (只是沒那麼有效)。

而記得後來的緩解方式是透過亂數化 source port (讓 DNS resolver 查詢時不要從 port 53 出去問),這個方式讓攻擊機率大幅下降 (大約降到 1/2^{16} 的機率)。

後來 DNS 加上 nonce 機制再繼續壓低攻擊成功的機率 (再降一次 1/2^{16},變成大約 1/2^{32}),最後則是 DNSSEC 的支援度逐漸普及,才解決掉這個問題。

資安領域的重大損失,尤其在 DNS 這塊...

用 SSD 的 I/O 暴力解

這篇「Achieving 11M IOPS & 66 GB/s IO on a Single ThreadRipper Workstation」用了 AMD 平台上的 PCI-e 4.0 硬幹出 4K 隨機讀取 11M IOPS 的速度,另外在大區塊讀取可以到 66GB/sec,後面這個速度應該是可以把 DDR4 記憶體頻寬吃滿...

硬體的部份,作者用了 8*1TB + 2*500GB 的 M.2 SSD 來建這組系統,然後接到卡上:

不過他好像沒提到這組機器的價錢 (雖然每個單品都查的到),大概算了一下 storage 的部份其實不怎麼貴,Samsung 980 Pro PCIe 4.0 M.2 SSD 的部份,1TB 每一條要 USD$160,500GB 要 USD$120,旁邊那些 CPU 與記憶體反而貴不少... 不過整台機器應該有機會在 USD$10000 搞定?

感覺拿來給剪片的人用很爽?至少在處理讀寫的時候應該是很順...

AT&T 網路的問題

Hacker News Daily 上看到個有趣的 troubleshooting 過程,AT&T 的線路會造成 random bit flipping 的問題,另外在 Hacker News 上的討論野蠻熱鬧的:「AT&T Fiber in the SF Bay Area is flipping bits (twitter.com/catfish_man)」。

有人生了一個 script 出來測試,這隻 script 會抓 www.example.com 的 HTTP 與 HTTPS 結果比較,從下面大家的留言回報,可以看出來有 random bit flipping 的問題:「bmastenbrook/example-test.sh」。

然後總算是解決了:

可惜看不到 AT&T 的回應,大家只能猜測是 memory 相關的問題,也許壞的部份有多個地方,造成 ECC 機制在某些情況下不夠用...

莎士比亞風格的 UUID

UUID 是個長 128 bits 的數字,轉成 16 進位也有 32 個字要記,對於人類記憶來說不太友善。

前幾天在 Hacker News 上看到的東西,把這 128 bits 的資訊轉成類莎士比亞的句子,相比前面 32 個 16 進位的數字來說好記不少:「uuid-readable」。

Generate Easy to Remember, Readable UUIDs, that are Shakespearean and Grammatically Correct Sentences

給的輸出範例包括了:

Loren Chariot Addy the Titbit of Cholame questioned Cele Garth Alda and 16 windy frogs

Drucill Hubert Lewse the Comer of Avera rejoices Fiann Craggy Florie and 5 hard trouts

Jacquette Brandt John the Pectus of Barnsdall doubted Glenn Gay Gregg and 12 noisy stoats

我不覺得有變簡單啊 XDDD 也許對於英文母語的人來說會簡單一些... 吧?

sysbench 的 RNG

Percona 的 blog 上看到了 sysbench 的 RNG (Random Number Generator) 跟想像中的不太一樣:「What You May Not Know About Random Number Generation in Sysbench」。

預設是 Special:

而不是直覺的 Uniform (也有提供):

另外還提供三種:

翻了翻可以翻到其他四個的理論基礎,但就是不知道 Special 的設計理論在哪裡...

利用 Sensor 校正資訊產生 Device Fingerprint 的隱私攻擊

看到「Fingerprinting iPhones」這篇提出的攻擊,標題雖然是提到 iPhone,但實際上攻擊包括了 Android 的手機:

You are affected by this fingerprinting attack if you are using any iOS devices with the iOS version below 12.2, including the latest iPhone XS, iPhone XS Max, and iPhone XR. You are also likely to be affected if you are using a Pixel 2/3 device, although we hypothesise the generated fingerprint has less entropy and is unlikely to be globally unique. A SensorID can be generated by both apps and mobile websites and requires no user interaction.

目前 iPhone 升級到 12.2 之後可以緩解這個問題,Android 看起來還不清楚...

攻擊的方式是透過手機在出場前會使用外部的校正工具,找出手機內 sensor 所偵測到的值與實際值的差異,然後把這些資訊燒到韌體裡,當呼叫 API 時就可以修正給出比較正確的值。

而因為這些校正資訊幾乎每一隻手機都不一樣,而且不會因為重裝而變更 (即使 factory reset),加上還可以跨 app 與 web 追蹤,就成為這次攻擊的目標:

In the context of mobile devices, the main benefit of per-device calibration is that it allows more accurate attitude estimation.

資訊量其實相當大,透過 app 分析可以得到 67 bits entropy,透過網頁也有 42 bits entropy,而且不怎麼會變:

In general, it is difficult to create a unique fingerprint for iOS devices due to strict sandboxing and device homogeneity. However, we demonstrated that our approach can produce globally unique fingerprints for iOS devices from an installed app -- around 67 bits of entropy for the iPhone 6S. Calibration fingerprints generated by a website are less unique (~42 bits of entropy for the iPhone 6S), but they are orthogonal to existing fingerprinting techniques and together they are likely to form a globally unique fingerprint for iOS devices.

We have not observed any change in the SensorID of our test devices in the past half year. Our dataset includes devices running iOS 9/10/11/12. We have tested compass calibration, factory reset, and updating iOS (up until iOS 12.1); the SensorID always stays the same. We have also tried measuring the sensor data at different locations and under different temperatures; we confirm that these factors do not change the SensorID either.

目前提出來的解法是加入隨機值的噪音 (iOS 的作法),不過作者有建議預設應該要關閉 js 存取 sensor 的權限:

To mitigate this calibration fingerprint attack, vendors can add uniformly distributed random noise to ADC outputs before calibration is applied. Alternatively, vendors could round the sensor outputs to the nearest multiple of the nominal gain. Please refer to our paper for more details. In addition, we recommend privacy-focused mobile browsers add an option to disable the access to motion sensors via JavaScript. This could help protect Android devices and iOS devices that no longer receive updates from Apple.

不過當初這群人怎麼會注意到的...

AWS 提供模擬 Amazon Aurora 異常的測試功能...

Twitter 上看到 Jeff Barr 提到了在 Amazon Aurora 上的模擬 (這邊應該是講 MySQL):

指到的頁面是文件「Managing Amazon Aurora MySQL - Amazon Relational Database Service」,翻了一下 Wayback Machine,看起來之前就有了,只是現在拿出來再宣傳一下:「Managing Amazon Aurora MySQL - Amazon Relational Database Service」。

透過主動觸發 Amazon Aurora 異常,可以測試整個系統的後續反應:

  • A crash of the master instance or an Aurora Replica
  • A failure of an Aurora Replica
  • A disk failure
  • Disk congestion

前面三種都屬於 Aurora 本身的故障測試,第四種除了有可能是 Aurora 本身的問題外,也可以測壓力過大時的情境 (i.e. 前面透過 auto scaling 撐住了,但後面的資料庫可能沒有足夠的能力支撐)。

Googlebot 的 Math.random()

Hacker News Daily 上看到「Googlebot’s Javascript random() function is deterministic」這則有趣的發現。作者發現 Googlebot 的 Math.random() 並不隨機,甚至是固定的:

The first time Googlebot calls Math.random() the result will always be 0.14881141134537756, the second call will always be 0.19426893815398216. The script I linked to above simply uses this fact but obfuscates it a little and ‘seed’ it with something that doesn’t look too arbitrary.

需要無法預測的 random number (有安全性需求的) 應該用 RandomSource.getRandomValues() 這類函數,而不是用 Math.random(),所以這點倒是還好...

Ethereum Smart Contracts 裡的 PRNG

現代密碼學的安全性有很大一塊是基於亂數產生器 (RNG) 非常難被預測。如果這個前提不成立的話,利用亂數產生器產生出來的各種資訊都會被預測出來 (尤其是 Private Key)。

但真正的 RNG 需要靠硬體支援,而且產生速度很慢,一般都會使用 PRNG (Pseudorandom number generator) 產生。也就是「看起來」很亂的亂數產生器。

PRNG 通常是指在統計學上通過許多測試,像是在多種測試都是 Discrete uniform distribution,不需要防止有惡意人,可以從產生出的 PRNG 的值而推導出後續結果的用途。

在「Predicting Random Numbers in Ethereum Smart Contracts」這篇裡面,作者列出了一堆實做 Ethereum Smart Contracts 卻誤用 PRNG 的行為。

文章裡提到的問題都是因為 PRNG 拿著可被預測的資訊當作 entropy source (e.g. seed),而且提出來的範例都是拿 block 本身或衍生的資訊 (像是 block 的 hash) 來用:

  • PRNGs using block variables as a source of entropy
  • PRNGs based on a blockhash of some past block
  • PRNGs based on a blockhash of a past block combined with a seed deemed private
  • PRNGs prone to front-running

然後列了大量的程式碼當例子,建議有需要接觸的人看過一次,或是有時間的人都值得看這些負面範例... XDDD

不過作者在文章裡面也給了一堆有問題的方法,像是從外部網站取得亂數之類的 XDDD

正確的方法是使用 CSPRNG (Cryptographically secure pseudorandom number generator),這是專門設計給密碼學用的 PRNG。

CSPRNG 有幾種方法可以取得:

  • 在大多數的程式語言內都有對應的 library 可以用,另外在比較近代的瀏覽器內 (如果問 IE 的話,是 11+),可以透過 RandomSource.getRandomValues() 得到。
  • 如果打算自己搞底層而需要直接取得 CSPRNG 的產出,在 Unix-like 的環境下可以透過 /dev/urandom 取得,在 Microsoft Windows 下則可以透過 CryptGenRandom 取得。

別學作者那邊奇怪方法啊 XDDD