15/10/2026 · VietTechies · Biên tập

Năm 2006, Debian xóa hai dòng code trong bản OpenSSL của mình để một công cụ gỡ lỗi thôi cảnh báo. Suốt 20 tháng sau đó, các hệ thống Debian, và về sau là cả các hệ thống Ubuntu, đã tạo ra những khóa mã hóa có thể bị đoán trước. Người bảo trì (maintainer) thực hiện thay đổi này đã hỏi ý kiến các lập trình viên OpenSSL từ trước.
Ngày 1 tháng 5 năm 2006, Kurt Roeckx, người bảo trì gói OpenSSL của Debian, gửi thư lên openssl-dev, một danh sách thư (mailing list) công khai của OpenSSL. Valgrind — công cụ báo cho biết khi nào một chương trình ra quyết định dựa trên vùng nhớ chưa từng được khởi tạo — đang đưa ra nhiều cảnh báo khi kiểm tra các chương trình dùng OpenSSL. Roeckx đã lần ra nguồn gốc của các cảnh báo ấy: hai dòng trong file md_rand.c, nơi bộ sinh số ngẫu nhiên của thư viện OpenSSL đang nạp một vùng đệm (buffer) chưa được khởi tạo vào bể ngẫu nhiên của mình.
“Mọi người nghĩ sao về việc bỏ 2 dòng code đó?”, Roeckx hỏi. Ông thừa nhận rằng mình thậm chí không chắc dữ liệu chưa được khởi tạo chứa bao nhiêu độ ngẫu nhiên.
Ngay trong ngày, Ulf Möller đáp lại chính băn khoăn đó, từ một địa chỉ thuộc tên miền openssl.org: “Không nhiều. Nếu điều đó giúp ích cho việc gỡ lỗi, tôi ủng hộ bỏ chúng đi.” Hôm sau, Geoff Thorpe chỉ ra rằng code vốn đã có sẵn một tùy chọn dành cho các công cụ kiểm tra bộ nhớ: “biên dịch với -DPURIFY.”
Hai dòng này là cùng một lời gọi hàm, MD_Update(&m,buf,j). Roeckx xóa cả hai. Chỉ một trong hai dòng có thể xóa an toàn.
Vì sao hai dòng giống hệt nhau lại làm hai việc khác nhau
OpenSSL giữ độ ngẫu nhiên trong một bể (pool) — thực chất là trạng thái cộng dồn của một hàm băm. Một trong hai lời gọi nằm trong hàm trả về các byte ngẫu nhiên. Trước khi ghi kết quả vào vùng đệm do bên gọi truyền vào, lời gọi này trộn vào bể bất cứ thứ gì đang nằm sẵn trong vùng đệm ấy — có thể là vùng nhớ chưa ai gán giá trị. OpenSSL vốn đã bọc lời gọi này trong #ifndef PURIFY, nên có thể bỏ nó ra khi biên dịch cho Purify, một công cụ kiểm tra bộ nhớ khác. Xóa dòng này không gây hại gì.
Lời gọi còn lại nằm trong hàm nạp dữ liệu mới vào bể. Dữ liệu hạt giống (seed) — đầu vào khó đoán mà cả bộ sinh số dựa vào — thực sự đi vào bể qua chính dòng này. Khi dòng đó bị xóa, OpenSSL vẫn nâng mức ước tính về lượng ngẫu nhiên trong bể, nhưng bản thân seed thì bị vứt bỏ. Như vậy chỉ còn lại một đầu vào mà Russ Cox, người về sau mổ xẻ đoạn code này, gọi là “hơi khó đoán”: mã tiến trình (process ID), con số mà hệ điều hành gán cho mỗi chương trình đang chạy. Bộ sinh số trộn con số này vào mỗi lần được gọi.
Vì thế, như Cox viết, một hệ thống bị ảnh hưởng “chỉ có thể tạo ra 32.767 khóa SSH khác nhau ứng với một loại và một kích thước khóa nhất định” — mỗi mã tiến trình cho ra một khóa. Khóa SSH (Secure Shell) cho phép quản trị viên và lập trình viên đăng nhập vào các máy tính ở xa. Wiki của Debian cho biết thêm rằng đầu ra của bộ sinh số còn khác nhau tùy kiến trúc bộ xử lý — little-endian 32 bit, little-endian 64 bit hay big-endian 32 bit — nên tổng cộng có 98.301 chuỗi số “ngẫu nhiên” khả dĩ.
Hai mươi tháng sinh ra những khóa có thể đoán trước
Hai dòng code ấy bị xóa kể từ phiên bản 0.9.8c-1 của gói openssl, được tải lên nhánh phát triển của Debian ngày 17 tháng 9 năm 2006. Từ đó, thay đổi này lan tới etch, bản phát hành ổn định kế tiếp của Debian, và tới Ubuntu, bản phân phối dựa trên Debian. Thông báo bảo mật của Ubuntu nêu các phiên bản bị ảnh hưởng là 7.04, 7.10 và 8.04.
Ngày 13 tháng 5 năm 2008, một thông báo bảo mật của Debian cho biết “Luciano Bello đã phát hiện ra rằng bộ sinh số ngẫu nhiên trong gói openssl của Debian có thể bị đoán trước”, và đây là hậu quả của “một thay đổi sai, chỉ có ở Debian”. Các khóa bị ảnh hưởng bao gồm khóa SSH, OpenVPN và DNSSEC (cơ chế ký số cho hệ thống tên miền), dữ liệu khóa của chứng chỉ X.509 — loại chứng chỉ mà các trang web dùng cho HTTPS — và khóa phiên của các kết nối được mã hóa bằng SSL/TLS. Khóa tạo bằng GnuPG hoặc GnuTLS không bị ảnh hưởng. Cùng ngày, Ubuntu cũng công bố thông báo của riêng mình.
Có những khóa bị lộ dù được tạo ra ở nơi khác. Thông báo bảo mật của Debian cảnh báo rằng mọi khóa DSA (Digital Signature Algorithm, thuật toán chữ ký số) “từng được dùng trên các hệ thống Debian bị ảnh hưởng để ký hoặc xác thực” đều cần được coi là đã bị lộ. Mỗi lần ký, DSA cần một giá trị ngẫu nhiên bí mật, và trên máy bị ảnh hưởng, giá trị đó đến từ bộ sinh số đã hỏng.
Trong vòng hai ngày, nhiều khóa yếu đã bị công khai. Ngày 15 tháng 5, trung tâm cảnh báo an ninh mạng SANS Internet Storm Center cho biết nhà nghiên cứu bảo mật H D Moore đã đăng một trang web chứa toàn bộ khóa RSA 1024, 2048 và 4096 bit dùng cho SSH mà ông đã dò ra bằng cách vét cạn. Debian phát hành các danh sách đen gồm những khóa yếu, cùng một công cụ kiểm tra là ssh-vulnkey.
Thay khóa thì mất nhiều thời gian hơn hẳn. Trong một nghiên cứu năm 2009, Scott Yilek và bốn đồng tác giả đã quét hằng ngày hơn 50.000 máy chủ web có bật SSL/TLS và tìm thấy 751 máy chủ dùng chứng chỉ có lỗ hổng. Trong số những máy chủ còn dính lỗ hổng khi cuộc khảo sát bắt đầu, tức bốn ngày sau khi lỗi được công bố, khoảng 30% vẫn chưa được khắc phục gần sáu tháng sau đó, và các tổ chức cấp chứng chỉ vẫn tiếp tục cấp chứng chỉ cho các khóa yếu.
Những phản ứng đầu tiên hiểu sai điều gì về chuyện hỏi ý kiến OpenSSL
Ngay trong ngày Debian ra thông báo bảo mật, Ben Laurie, thành viên nhóm nòng cốt của OpenSSL, viết trên một danh sách thư về mật mã học rằng hai năm trước đó, Debian đã “sửa” một vấn đề mà Valgrind báo ra “bằng cách loại bỏ mọi khả năng bổ sung bất kỳ entropy nào” — tức đầu vào khó đoán — vào bể của OpenSSL. Ông viết rằng các nhà phân phối “nên đóng góp các bản patch của mình ngược về dự án gốc, cho những người bảo trì gói”. “Nếu lần này Debian làm vậy, chúng tôi (nhóm OpenSSL) hẳn đã cười lăn cười bò.” Châm ngôn của ông: “đừng bao giờ sửa một lỗi mà bạn không hiểu.”
Kho lưu trữ thư của openssl-dev kể một câu chuyện rối rắm hơn. Roeckx đã hỏi trên danh sách này, nơi mà chính trang hỗ trợ của OpenSSL mô tả là dành cho “thảo luận về việc phát triển thư viện OpenSSL”. Về sau, theo tường thuật của trang tin LWN, Laurie lập luận rằng openssl-dev không phải là nơi để bàn chuyện phát triển OpenSSL. Thế nhưng câu trả lời của Möller lại được gửi từ một địa chỉ openssl.org.
Thứ không được gửi ngược về dự án gốc là chính bản patch. Cox lưu ý rằng thư của Roeckx không nêu tên các hàm chứa từng lời gọi — chi tiết giúp phân biệt dòng vô hại với dòng thiết yếu — và rằng các lập trình viên OpenSSL “đã trả lời sai, có lẽ là chưa thực sự xem code”.
Bài học từ hai dòng code giống hệt nhau
Cảnh báo chỉ ra triệu chứng, chứ không chỉ ra mục đích. Các cảnh báo của Valgrind là chính xác: vùng nhớ chưa khởi tạo đúng là đang lọt vào bể. Valgrind không thể cho ai biết rằng một trong hai dòng ấy còn là đường đưa seed vào bể.
Code trông giống nhau vẫn có thể làm những việc khác nhau. Như Cox viết: “Việc một lời gọi không thiết yếu đã khiến lời gọi kia trông như cũng không thiết yếu.” Bài học đầu tiên của ông là: “Cố đừng viết code mẹo mực. Hãy cố viết code ngăn nắp.”
Một câu trả lời trên danh sách thư không phải là review code (đọc duyệt mã). Cox ngạc nhiên vì khi bản patch đã được viết xong, không ai quay lại trao đổi tiếp với OpenSSL. Theo lời ông: “Thảo luận trên danh sách thư không thay thế được việc review code thực sự.”
Hai dòng ấy viết y hệt nhau: MD_Update(&m,buf,j). Một dòng khuấy phần bộ nhớ còn sót lại vào bể; dòng kia mở cửa cho seed đi vào.
Roeckx đã hỏi liệu có thể bỏ hai dòng ấy hay không. Câu hỏi thật sự quan trọng là mỗi dòng làm gì.
Bài liên quan
Đọc bằng ngôn ngữ khác: English
Nguồn
- Thông báo bảo mật của Debian DSA-1571-1, “New openssl packages fix predictable random number generator”, ngày 13 tháng 5 năm 2008
- Kurt Roeckx, “Random number generator, uninitialised data and valgrind”, danh sách thư openssl-dev, ngày 1 tháng 5 năm 2006
- Ulf Möller, thư trả lời trên openssl-dev, ngày 1 tháng 5 năm 2006
- Geoff Thorpe, thư trả lời trên openssl-dev, ngày 2 tháng 5 năm 2006
- Báo cáo lỗi Debian #363516, “valgrind-clean the RNG”, mở ngày 19 tháng 4 năm 2006
- Gói openssl 0.9.8c-1 của Debian: bản diff mã nguồn (md_rand.c) và nhật ký thay đổi (changelog) có chữ ký của Kurt Roeckx, ngày 17 tháng 9 năm 2006 (snapshot.debian.org)
- Russ Cox, “Lessons from the Debian/OpenSSL Fiasco”, research!rsc, ngày 21 tháng 5 năm 2008
- Debian Wiki, “SSLkeys”
- Thông báo bảo mật của Ubuntu USN-612-1, “OpenSSL vulnerability”, ngày 13 tháng 5 năm 2008
- Ben Laurie, “The perils of security tools”, danh sách thư Cryptography, ngày 13 tháng 5 năm 2008
- Jake Edge, “Debian, OpenSSL, and a lack of cooperation”, LWN.net, ngày 14 tháng 5 năm 2008
- Bojan Zdrnja, “Debian and Ubuntu users: fix your keys/certificates NOW”, SANS Internet Storm Center, ngày 15 tháng 5 năm 2008
- Scott Yilek, Eric Rescorla, Hovav Shacham, Brandon Enright và Stefan Savage, “When Private Keys are Public: Results from the 2008 Debian OpenSSL Vulnerability”, hội nghị IMC 2009
- Ảnh đại diện: một chiếc chìa khóa bằng đồng thau (ảnh minh họa, không liên quan đến các sự kiện trong bài), tác giả Gausanchennai, qua Wikimedia Commons, CC BY-SA 4.0
