Vietnam's contact tracing app broadcasting a fixed ID
Prologue
Bluezone (Android, iOS) is a Bluetooth-based contact tracing app sponsored by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Government of Vietnam and developed by a coalition of local tech companies and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Ministry of Information and Communications.
The developers claim that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app is designed to alert people who may have come in contact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virus while keeping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir identity anonymous. The Android and iOS apps were released a few days ago, and according to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 official tally cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have attracted more than 150,000 users (last update April 30th 2020). The media quoted a top official touting that Bluezone is a breakthrough because it allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 government not to collect people's information and is able to solve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 basic errors in similar apps from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r countries.
Needless to say, Bluezone piqued my curiosity. I want to know it works. The developers pledge to open source cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y actually haven't released neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r code nor documentation. I break software professionally, and decided to send cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m a note offering my service pro bono, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y could give me early access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 design or something. I also suggested that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y should consider open solutions such as DP3T. They said thanks, but didn't send me nothing.
When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app was released Thursday, I downloaded and reverse engineered it. I found terrible vulnerabilities. I wrote a report and shared with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 developers, urging cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to use DP3T. I also published a summary without too many details on my blog to alert my community. The developers published a rebuttal basically calling me mistaken. They didn't send me a copy.
Below is my report which includes a rebuttal to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir rebuttal.
--
The report
1/ First of all, Bluezone assigns each installation a fixed 6-character ID, and broadcasts it over and over again. I've spent a majority of my waking moments in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past two weeks studying secure and private contact tracing technologies and to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best of my knowledge, Bluezone is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only app doing this. Needless to say, this puts users at grave risks, as it leaks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir location, movement, or social graph, etc. to whoever's watching.
In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir rebuttal, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 developers said cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't think changing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID can improve user privacy because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bluetooth MAC address is constant anyway. This is not true.
Bluetooth has two sub standards: Bluetooth Classic and Bluetooth Low Energy. A Bluetooth Classic device can be eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r discoverable or non-discoverable. When it is discoverable, it broadcasts its MAC address, device name and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r information. But when it is non-discoverable, it doesn't broadcast anything. For privacy, neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r Android nor iOS is discoverable by default. Phones are discoverable if and only if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bluetooth System Setting app is running in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 foreground, i.e., only when users want to pair with ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r devices.
Both Android and iOS also randomize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC address when broadcasting BLE advertisements. On Android, experiments by various groups show that restarting BLE advertising causes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS to choose a new random MAC address. On iOS, experiments by a friend of mine and in this paper show that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS automatically chooses a new random MAC address every hour or so.
I don't blame cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m for this confusion. I was confused myself when I thought Android and iOS expose APIs allowing apps to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC address however cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y see fit.
2/ To add insult to injury, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fixed 6-character IDs are predictable.
This is how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are generated:
var generateUserId = function() {
var t = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
n = t.length,
o = '';
Math.seedrandom(new Date().getTime());
for (var s = 0; s < 6; s++) o += t.charAt(Math.floor(Math.random() * n));
return o;
}
It uses this seedrandom library which always generates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same output when seeding with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same value. In this case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 seed is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current timestamp. The app fell victim to one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 classic blunders in practical crypto software security. Pro tips: if you are to design a PRNG and let your users choose cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own seed you may as well just return 4.
Anyways, this means all past and future IDs are predictable. The developers rebut that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 timestamp is unpredictable because it has a millisecond precision. This is missing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 forest for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 trees. While it may be a bit difficult to guess cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID assigned to a particular person, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are many ways to exploit this weakness at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system level. A few examples from top of my head:
- An attacker can generate all possible IDs and broadcast cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m everywhere. He can also target a group of users, who he knows installed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app in some particular time frame.
- After generating an ID, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app attempts to register it with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server. It generates a FCM token and associates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token. I bet that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server uses this to send infected IDs and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r notifications to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registration fails because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID already exists, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app doesn't generate anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r ID and try again. Because I can predict all future IDs, I can preregister all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. This is a denial of service attack, denying all future users to participate in this system.
3/ Acute readers probably have noticed that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IDs are too short! There are only 36^6 ~ 2^31 IDs. Because of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 birthday paradox, if 65K people use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app, two of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m will be assigned cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same ID with high probability. When so, if a person is declared infected, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r is also too! At cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current growth rate, I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first collision will happen within 2 weeks.
The developers rebut that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y've ensured that no collision is going to happen, regardless of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 probability.
Because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app tries to register cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server, it's possible to handle collisions, by checking whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID already exists on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server database. I don't think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android app is doing that (I haven't looked at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iOS app).
The developers also claimed that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir system can solve a problem that many ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r teams around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 world can't. That is, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can prevent abusers from replaying IDs collected at a hospital. How? Users can optionally upload cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir observed IDs to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server. Wait, what? This is contradict to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "no data collection" claim. You don't want to upload observed IDs to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server.
4/ The app backups to Android's public storage (a.k.a external storage) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 database of all observed IDs and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MAC address and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device name of observed Bluetooth classic devices (yes, it also scans for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m -- this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 source of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confusion in #1?). This means, information correlated to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user's location, movement and social graph is accessible to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r apps installed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 phone that can read external storage. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 backup database is used by health authority to determine who to quarantine users can easily falsify exposure records.
In my initial report, I didn't know that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y did this but I still flagged cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 external storage permission request because I don't think a contact tracing app needs access to photos, media and files to do its job. This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 principle of least privilege.
They rebut saying that requiring external storage access is not a security issue, and expressing surprise why a Google engineer doesn't know external storage is where Android stores photos, media and files. Well I flagged cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 permission request exactly because I *knew* external storage has sensitive information.
The app also requires access to fine-grained location information. Now, this is something I didn't know. I flagged this permission request, but it turns out that for privacy Android requires cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ACCESS_FINE_LOCATION permission if an app wants to use Bluetooth.
--
Epilogue
The boss of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 developers emailed asking me to help secure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app. I said I'd love to, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y move development to GitHub. This is what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y've pledged since day one. The boss said cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're going to upload today, but I haven't seen it yet. Stay tuned for more fun!
Update: fix some typos and remove unnecessary languages.
Update: fix more languages. The app now has 150K users. The good news is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 growth rate has slowed down. My friends and I have filed several bugs on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app's GitHub page, but got zero response so far.
(Discussions on Hacker News)
Comments
You're doing great work, keep going.
You said "If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registration fails because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ID already exists, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app doesn't generate anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r ID and try again". If so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re cannot be 2 users with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same ID registered in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 2nd one would have been unable to start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app at all?
Minh
Về vấn đề chống replay/relay attach ở mục 3, mình hình dung cách làm của BlueZone là tăng cường điều kiện xác định F1, cụ thể là chỉ khẳng định đúng F1 nếu thoả mãn cả 2 điều kiện sau:
1) Trên máy F1 có chứa một số token phát ra từ F0, và
2) Trên máy của F0 có chứa một số token phát ra từ F1
Như thế, nếu là relay/replay attach thì chỉ thoả mãn điều kiện 1 mà không thoả mãn điều kiện 2.
Mình có nhầm lẫn gì không nhỉ? :)
Ngoài ra, vì Android yêu cầu quyền truy cập vị trí khi dùng bluetooth, nên các nhà thiết kế Android cho là đã cho dùng bluetooth thì mặc nhiên người dùng lộ dữ liệu vị trí? Và nếu thế thì nên chăng BlueZone dùng luôn dữ liệu vị trí của người dùng?
Hà,
When registration fails, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app just silently cruises along. It can still scan and broadcast IDs, but because it can't talk to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server it won't be able to do any matching to detect exposure.
>Cụ thể giải pháp của nhóm cho phép khi 1 Bluezoner giả định có phát hiện tiếp xúc F0 (nhận được thông tin qua broadcast), Bluezoner này có tùy chọn xác minh F0 mình đã tiếp xúc có đúng là F0 thật hay không, bằng cách gửi lịch sử tiếp xúc F0 của mình lên hệ thống để so sánh với lịch sử tiếp xúc của F0 đã được cơ quan Y tế cập nhật. Nếu không có sự tương đồng, Bluezoner không phải là F1.
Vả lại có đúng là họ làm như vậy thì đây là cách làm rất nguy hiểm, vì nó bắt buộc người dùng chia sẻ dữ liệu với máy chủ, đi ngược lại với cam kết "không thu thập dữ liệu".
Có thể sửa vài lỗi ngữ pháp tiếng Anh, bỏ đi mấy phần ăn thua và đưa lên các diễn đàn, mạng xã hội để có nhiều thảo luận có ích hơn. Mới đọc đc cái này thấy không khí nó khác ở đây quá: https://twitter.com/matcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365wrdev/status/1254336105203200000
> "Vả lại có đúng là họ làm như vậy thì đây là cách làm rất nguy hiểm, vì nó bắt buộc người dùng chia sẻ dữ liệu với máy chủ, đi ngược lại với cam kết "không thu thập dữ liệu"."
> "Bluezoner này có tùy chọn xác minh F0 mình đã tiếp xúc có đúng là F0 thật hay không, bằng cách gửi lịch sử tiếp xúc F0 của mình lên hệ thống để so sánh với lịch sử tiếp xúc của F0 đã được cơ quan Y tế cập nhật."
Theo mô tả ở trên là BlueZone có tuỳ chọn là có muốn xác minh với cơ quan Y tế hay ko mà anh, đâu phải bắt buộc?
I reread all my posts and comments. I never attacked people, I only attacked cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir work. The difference is subtle, but not difficult to notice if one paid attention. When I said cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y made basic mistakes, I presented hard, verifiable evidences. Nothing personal, purely business. I hate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir work because it'll put ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r people at risk, but I don't hate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. If I met cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 team, I'd be happy to have a beer with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m (but I doubt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y'd want to ;-)
Trang này bị chặn miết, đóng mở thất thường
Adua acong
Thì PR (pull request) trên github đi nào
Cheers
seedrandom function is being commented out from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest source code (maybe after this report)
https://github.com/BluezoneGlobal/bluezone-app/blob/master/app/Configuration.js#L50
Here is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new function for it: https://github.com/BluezoneGlobal/bluezone-app/blob/15305e20da6619a069b1e023dc305dcc8ab984bd/ios/Scanner/BluezonerIdGenerator.swift#L15
(The equivalent native-lib for android has not been published yet I think) ~ Hopefully you can have a look to give our community a comment/assessment..
Technically speaking, please keep your great finding
BluezonerIdGenerator.swift looks fine, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 version on Android is broken: https://github.com/BluezoneGlobal/react-native-bluetooth-scan/issues/2.
> Nhóm phát triển cho biết họ dùng hàm sinh ngẫu nhiên cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365o millisecond. Cần đoán chính xác đến millisecond của 1 người thì chúng ta tự biết là có thể làm điều đó hay không.
Safe and Secure PRNG: am i a joke to you?
> It uses this seedrandom library which always generates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same output when seeding with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same value
I think it's ok to use seedrandom, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y use is wrong. According to seedrandom document https://github.com/davidbau/seedrandom#script-tag-usage
> // Calling seedrandom with no arguments creates an ARC4-based PRNG
// that is autoseeded using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current time, dom state, and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r
// accumulated local entropy.
var prng = new Math.seedrandom();
console.log(prng()); // Reasonably unpredictable.
and:
> // Warning: if you call Math.seedrandom without `new`, it replaces
// Math.random with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 predictable new Math.seedrandom(...), as follows:
Math.seedrandom('hello.');
console.log(Math.random()); // Always 0.9282578795792454
console.log(Math.random()); // Always 0.3752569768646784
so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem is not about seedrandom, but about how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y use it.
Javascript code in React Native can't generate secure random numbers, but must rely on native code in Android or iOS. https://github.com/rh389/react-native-securerandom sounds pretty good, but I haven't reviewed it carefully.