2 điểm bởi GN⁺ 2023-07-25 | 1 bình luận | Chia sẻ qua WhatsApp
  • Zenbleed là một lỗ hổng trên dòng AMD Zen 2, khai thác quá trình khôi phục vzeroupper bị dự đoán sai để có thể đọc dữ liệu còn sót lại trong tệp thanh ghi vector của cùng một lõi vật lý
  • Được đăng ký là CVE-2023-20593, phạm vi ảnh hưởng bao gồm các sản phẩm Zen 2 như Ryzen 3000/4000/5000 with Radeon Graphics/7020 with Radeon Graphics, Ryzen PRO, Threadripper 3000, EPYC “Rome”
  • Cuộc tấn công xảy ra khi XMM Register Merge Optimization, đổi tên thanh ghi và vzeroupper bị dự đoán sai nối tiếp nhau trong một cửa sổ thời gian hẹp; ngay cả các phép toán cơ bản như strlen, memcpy, strcmp cũng có thể trở thành đối tượng bị quan sát
  • Biến thể đã tối ưu hóa có thể rò rỉ khoảng 30KB mỗi giây trên mỗi lõi, và việc cùng chia sẻ tệp thanh ghi của một lõi vật lý khiến ranh giới VM, sandbox, container và tiến trình đều trở thành vấn đề
  • Khuyến nghị áp dụng bản cập nhật microcode của AMD; tạm thời có thể đặt chicken bit DE_CFG[9], nhưng có thể phải trả giá về hiệu năng và chỉ vô hiệu hóa SMT thôi là không đủ

Đơn vị thực thi mà Zenbleed nhắm tới

  • CPU x86-64 có các thanh ghi vector XMM 128-bit, và CPU hiện đại mở rộng chúng lên YMM 256-bit và ZMM 512-bit
  • Thanh ghi vector không chỉ dùng cho tính toán số mà còn được dùng trong các hàm thư viện C chuẩn của glibc như strcmp, memcpy, strlen
  • strlen tối ưu bằng AVX2 trong glibc kết hợp nhiều lệnh vector để tìm vị trí byte nul đầu tiên trong chuỗi
    • vpxor xmm0,xmm0,xmm0 đặt phần thấp của ymm0 về 0
    • vpcmpeqb ymm1,ymm0,[rdi] so sánh các byte của chuỗi với byte 0
    • vpmovmskb eax,ymm1 chuyển kết quả so sánh sang thanh ghi thông thường
    • tzcnt eax,eax tính vị trí của byte nul đầu tiên

vzeroupper và tệp thanh ghi

  • vzeroupper là lệnh đặt các bit cao của thanh ghi vector về 0
  • Khi trộn cách dùng thanh ghi XMMYMM, thanh ghi XMM sẽ được nâng lên toàn bộ độ rộng, và trong quá trình này có thể phát sinh phụ thuộc vào các bit cao
  • glibc dùng vzeroupper để tránh các stall không cần thiết, nhờ đó các kết quả về sau không còn phụ thuộc vào các bit cao
  • CPU không đặt mỗi thanh ghi ở một vị trí vật lý cố định mà quản lý việc cấp phát thanh ghi vật lý bằng Register FileRegister Allocation Table
  • Khi đưa thanh ghi XMM về 0, CPU có thể không lưu các bit thực tế mà chỉ đặt cờ z-bit trong RAT
    • Cờ này có thể được áp dụng độc lập cho phần cao và phần thấp của thanh ghi YMM
    • vzeroupper có thể đặt z-bit rồi giải phóng tài nguyên tương ứng trong tệp thanh ghi

Lỗ hổng phát sinh trong quá trình khôi phục thực thi suy đoán

  • CPU hiện đại dùng thực thi suy đoán, nên các phép toán được thực hiện trên nhánh dự đoán sai phải được hoàn tác
  • Vấn đề là khi vzeroupper bị dự đoán sai đã được thực thi rồi được khôi phục, việc chỉ hoàn nguyên z-bit là không đủ để khôi phục chính xác trạng thái tài nguyên tệp thanh ghi đã bị giải phóng
  • Với lịch trình đủ chính xác, có thể khiến một số bộ xử lý khôi phục không chính xác từ vzeroupper bị dự đoán sai
  • Kỹ thuật này là CVE-2023-20593 và ảnh hưởng đến toàn bộ dòng Zen 2
    • AMD Ryzen 3000 Series Processors
    • AMD Ryzen PRO 3000 Series Processors
    • AMD Ryzen Threadripper 3000 Series Processors
    • AMD Ryzen 4000 Series Processors with Radeon Graphics
    • AMD Ryzen PRO 4000 Series Processors
    • AMD Ryzen 5000 Series Processors with Radeon Graphics
    • AMD Ryzen 7020 Series Processors with Radeon Graphics
    • AMD EPYC “Rome” Processors

Điều kiện tấn công và phạm vi rò rỉ

  • Để kích hoạt lỗi, XMM Register Merge Optimization, đổi tên thanh ghi và vzeroupper bị dự đoán sai phải diễn ra liên tiếp trong một cửa sổ thời gian chính xác
  • Chuỗi lệnh ví dụ dùng cấu trúc sau
    • vcvtsi2s{s,d} để kích hoạt merge optimization
    • vmovdqa để kích hoạt đổi tên thanh ghi
    • Nếu nhánh điều kiện thực tế là taken nhưng CPU dự đoán theo đường not-taken, vzeroupper sẽ bị thực thi do dự đoán sai và lỗi sẽ xuất hiện
  • Vì các phép toán cơ bản như strlen, memcpy, strcmp cũng dùng thanh ghi vector, nên chúng có thể trở thành đối tượng bị quan sát ở bất kỳ đâu trong hệ thống
  • Do tệp thanh ghi được chia sẻ trên cùng một lõi vật lý, các VM, sandbox, container và tiến trình khác cũng nằm trong phạm vi ảnh hưởng
  • Hai hyperthread chia sẻ cùng một tệp thanh ghi vật lý
  • Biến thể tấn công đã tối ưu có thể rò rỉ khoảng 30KB mỗi giây trên mỗi lõi, đủ nhanh để theo dõi khóa mã hóa và mật khẩu của người dùng đang đăng nhập
  • Tư vấn kỹ thuật và mã liên quan đã được công bố trong security research repository của Google
  • Mã thử nghiệm được cung cấp cho Linux, nhưng lỗi này không phụ thuộc vào hệ điều hành cụ thể nên mọi hệ điều hành đều bị ảnh hưởng

Cách phát hiện: fuzzing CPU và Oracle Serialization

  • Lỗ hổng được phát hiện bằng fuzzing
  • Ngành CPU cũng thực hiện kiểm chứng sau silicon (Post-Silicon Validation) để tìm lỗi phần cứng sau khi sản xuất chip
  • Khác với fuzzing dựa trên coverage thông thường, CPU không có chỉ số nào tương ứng trực tiếp với code coverage
  • Thay vào đó, người ta dùng performance counters để cung cấp phản hồi về các sự kiện kiến trúc đáng chú ý cho fuzzer
    • Cách này cho phép khám phá những chuỗi lệnh khó có thể tìm ra bằng ngẫu nhiên
    • Các tính năng như merge optimization cũng có thể được phát hiện tự động
  • Fuzzing phần mềm thường tìm crash, nhưng với các chương trình CPU được sinh ngẫu nhiên, bản thân crash đôi khi lại là hành vi đúng
  • Một cách tiếp cận trước đây là reversi, tạo phép toán ngược cho từng lệnh ngẫu nhiên rồi kiểm tra xem trạng thái cuối có khác trạng thái ban đầu hay không
    • Trên các kiến trúc CISC như x86, việc sinh test case trở nên phức tạp hơn
  • Một cách khác là dùng oracle để so sánh kết quả của CPU đang kiểm thử với CPU khác hoặc trình mô phỏng
  • Oracle Serialization kết hợp hai ý tưởng này
    • Tạo chương trình ngẫu nhiên rồi tự động chuyển đổi sang dạng được tuần tự hóa
    • Thêm các thành phần tuần tự hóa như store/load barrier, speculation fence, cache line flush
    • Chương trình gốc và chương trình đã tuần tự hóa phải tạo ra cùng đầu ra dù đặc tính hiệu năng có khác nhau
  • Nếu trạng thái cuối không khớp, đó có thể là lỗi thực thi vi kiến trúc, và chính sự sai khác này đã dẫn tới việc phát hiện Zenbleed

Ứng phó và giới hạn phát hiện

  • Lỗ hổng đã được báo cho AMD vào ngày 15/5/2023
  • AMD đã phát hành bản cập nhật microcode cho các bộ xử lý bị ảnh hưởng
  • Nhà cung cấp BIOS hoặc hệ điều hành có thể đã phát hành bản vá kèm theo bản cập nhật này
  • Biện pháp được khuyến nghị là áp dụng bản cập nhật microcode
  • Khi không thể áp dụng bản cập nhật, có thể dùng biện pháp giảm thiểu ở mức phần mềm bằng cách đặt chicken bit DE_CFG[9]
    • Có thể gây tổn thất hiệu năng
    • Trên Linux có thể đặt cho mọi lõi bằng msr-tools
    • Trên FreeBSD dùng cpucontrol(8)
    • Nếu không biết cách thiết lập MSR trên hệ điều hành khác, cần nhờ hỗ trợ từ nhà cung cấp
  • Chỉ vô hiệu hóa SMT là không đủ
  • Chưa có kỹ thuật phát hiện tấn công đáng tin cậy nào được biết đến
    • Vì không cần system call đặc biệt hay quyền đặc biệt nào
    • Cũng không thể phát hiện tĩnh việc sử dụng vzeroupper không phù hợp

1 bình luận

 
GN⁺ 2023-07-25
Ý kiến trên Hacker News
  • Vụ này thực sự rất đáng chú ý, và có thể trở thành ví dụ kinh điển cho việc chạy trong VM không có nghĩa là an toàn
    Việc thoát VM từ lâu đã được biết đến, nhưng lần này là một lỗ hổng quy mô lớn, dễ khai thác mà không cần thoát, trong khi phần thưởng lại rất lớn
    Việc lỗi này được sửa bằng microcode không có nghĩa là không tồn tại các lỗi tương tự khác. Nhiều 0-day thường đã được các nhóm black hat đánh thuê biết tới từ rất lâu trước khi bị công bố rộng rãi
    Các lỗ hổng CPU được phát hiện trong vài năm gần đây:
    https://en.wikipedia.org/wiki/Meltdown_(security_vulnerability)
    https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)
    https://aepicleak.com/
    https://en.wikipedia.org/wiki/Software_Guard_Extensions#SGAxe
    https://en.wikipedia.org/wiki/Software_Guard_Extensions#LVI
    https://en.wikipedia.org/wiki/Software_Guard_Extensions#Plundervolt
    https://en.wikipedia.org/wiki/Software_Guard_Extensions/…
    https://en.wikipedia.org/wiki/Software_Guard_Extensions#Enclave_attack
    https://en.wikipedia.org/wiki/Software_Guard_Extensions/…
    https://www.vusec.net/projects/crosstalk/
    https://en.wikipedia.org/wiki/Hertzbleed
    https://securityweek.com/amd-processors-expose-sensitive-data-new-squi…

    • Vấn đề là VM không còn thực sự là một máy ảo nữa
      Thay vì diễn giải lệnh bằng một câu switch lớn, nó chạy lệnh trên CPU thật và dựa vào một số cờ phần cứng để CPU đảm bảo dữ liệu hay lệnh không chồng lấn lên nhau. CPU có hứa như vậy, nhưng trong thực tế thì rất khó để giữ đúng lời hứa đó
    • So sánh với Meltdown/Spectre có thể hơi dễ gây hiểu lầm
      Bên đó là một kiểu tấn công hoàn toàn mới, khả thi nhờ timing-based, dù CPU đã làm chính xác điều nó phải làm; còn Zenbleed lần này gần với một lỗi truyền thống hơn, nơi dữ liệu không được phép tồn tại lại bị lưu trong thanh ghi
    • Dù chạy mã không đáng tin trong sandbox, container hay VM thì ít nhất từ sau Rowhammer cũng đã không còn an toàn nữa
      Tôi cho rằng nhiều lỗ hổng kiểu này xuất phát từ việc phía phần mềm và phía phần cứng không thực sự trao đổi đúng mức với nhau. Phía phần mềm mặc định giả định có đảm bảo cô lập, còn phía phần cứng thì không cảnh báo đủ mạnh khi các giả định như vậy xuất hiện
    • Cuối cùng có vẻ phần lớn những thứ này đều liên quan đến branch prediction
      Hoặc là branch prediction vốn phức tạp đến mức về bản chất sẽ luôn dễ dính các lỗ hổng kiểu này, hoặc nó khác quá xa với cách chúng ta trực quan hiểu về đường đi mã và việc thực thi lệnh, nên rất khó hình dung ra các điều kiện biên trước khi đã quá muộn
      Liệu có lúc nào độ phức tạp của kiến trúc CPU trở nên khó suy luận đến mức chúng ta chấp nhận đánh đổi hiệu năng để giữ nó đơn giản hơn không?
    • Tôi đã thấy một số công ty trộn chung VM lộ ra Internet/DMZ và VM nội bộ trên cùng một hypervisor
      Tôi đã chỉ ra điều này và khuyên rằng nên air-gap chúng bằng hypervisor riêng biệt, nhưng lúc nào cũng bị phớt lờ. Rốt cuộc thì có lẽ họ sẽ tự chịu thiệt thôi
  • README trong tệp tar của exploit có thêm chi tiết và lịch công khai
    2023-05-09 Một thành phần của pipeline kiểm chứng CPU tạo ra kết quả bất thường
    2023-05-12 Cô lập và tái hiện thành công vấn đề, tiếp tục điều tra
    2023-05-14 Xác định phạm vi và mức độ nghiêm trọng của vấn đề
    2023-05-15 Viết báo cáo trạng thái ngắn gọn và chia sẻ với AMD PSIRT
    2023-05-17 AMD xác nhận báo cáo và thừa nhận có thể tái hiện được
    2023-05-17 Hoàn tất phát triển PoC đáng tin cậy và chia sẻ với AMD
    2023-05-19 Bắt đầu thông báo cho các nhà cung cấp kernel và hypervisor lớn
    2023-05-23 Nhận bản cập nhật microcode beta cho Rome từ AMD
    2023-05-24 Xác nhận bản cập nhật đã khắc phục vấn đề và thông báo cho AMD
    2023-05-30 AMD thông báo đã gửi thông báo bảo mật cho các đối tác
    2023-06-12 Họp với AMD để thảo luận về trạng thái và chi tiết
    2023-07-20 AMD công khai bản vá sớm hơn ngày embargo đã thống nhất mà không báo trước
    2023-07-21 Vì bản sửa lỗi đã được công khai, đề xuất thông báo riêng cho các bản phân phối lớn chuẩn bị cập nhật gói firmware
    2023-07-24 Công bố disclosure

  • Cái này thực sự đáng sợ. Trên thiết bị Zen 2 của tôi là Ryzen 3600, tôi chạy exploit với tư cách người dùng không có đặc quyền, rồi sao chép và dán một chuỗi vào trình soạn thảo văn bản chạy nền (Kate), và chỉ trong vài giây các mảnh của chuỗi đó đã được ghi lại trong đầu ra zenbleed
    May mắn là exploit này có vẻ phụ thuộc rất nhiều vào một routine assembly cụ thể nên việc lạm dụng từ JS hay WASM trong trình duyệt có lẽ sẽ rất khó. Nếu không thì chỉ cần mở một tab độc hại ở nền trong vài giờ cũng đã có thể rò rỉ dữ liệu dễ dàng
    Đang chờ maintainer Fedora phát hành microcode mới để kernel có thể cập nhật trong quá trình khởi động

    • Ít nhất có một người ở đây nói rằng cũng có thể tái hiện bằng JavaScript: https://news.ycombinator.com/item?id=36849767
    • Tôi cũng đã thử trên thiết bị Zen 2 của mình, và cùng kiểu tấn công đó vẫn hoạt động cả khi chạy trong KVM
    • Một khi đã tìm ra cách trong JS thì có vẻ khả năng áp dụng sẽ khá rộng
      Đồng thời hy vọng các bản vá phần mềm trong V8 và SpiderMonkey sẽ đến sớm hơn và giảm nhẹ thêm
      Tuy nhiên exploit JS cũng sẽ cần một cách để đưa dữ liệu ra ngoài, mà việc che giấu hoàn toàn điều đó có lẽ khá khó
    • Tôi không biết cách build PoC. Trên Ubuntu nó báo "No such file or directory"error 127
  • Có cảm giác việc OpenBSD vừa bổ sung tải microcode AMD trong vòng 3 ngày gần đây không phải là ngẫu nhiên
    https://news.ycombinator.com/item?id=36838511

  • Có vẻ cách diễn đạt rằng AMD đã phát hành bản cập nhật microcode cho các bộ xử lý bị ảnh hưởng là chưa thật chính xác
    AMD đã phát hành bản cập nhật microcode[0] cho family 17h model 0x310xa0, và theo WikiChip[1] thì các mã này tương ứng với Rome, Castle Peak, Mendocino
    Cho đến nay có vẻ vẫn chưa có bản cập nhật microcode cho Renoir, Grey Hawk, Lucienne, Matisse, Van Gogh. May mắn là kernel mới có thể chỉ cần đặt chicken bit cho các dòng này, và thực tế cũng làm như vậy[2]
    [0] https://git.kernel.org/pub/scm/linux/kernel/git/firmware/lin...
    [1] https://en.wikichip.org/wiki/amd/cpuid#Family_23_.2817h.29
    [2] https://github.com/torvalds/linux/commit/522b1d69219d8f08317...

  • Xem phần liên quan thì kỹ thuật này là CVE-2023-20593, hoạt động trên mọi bộ xử lý cấp Zen 2, ít nhất bao gồm các sản phẩm sau
    AMD Ryzen 3000 Series Processors
    AMD Ryzen PRO 3000 Series Processors
    AMD Ryzen Threadripper 3000 Series Processors
    AMD Ryzen 4000 Series Processors with Radeon Graphics
    AMD Ryzen PRO 4000 Series Processors
    AMD Ryzen 5000 Series Processors with Radeon Graphics
    AMD Ryzen 7020 Series Processors with Radeon Graphics
    AMD EPYC “Rome” Processors

    • Tôi thắc mắc liệu điều này có nghĩa là “chỉ được xác nhận trên Zen 2”, hay là vấn đề thực sự chỉ giới hạn trong kiến trúc này
      Có thể cùng kỹ thuật đó hoặc kỹ thuật tương tự cũng hoạt động trên các lõi Zen/Zen+ cũ hơn hoặc Zen 3 mới hơn, chỉ là chưa chứng minh được hay không?
    • Con 2700X của tôi có vẻ đã thoát trong gang tấc. Nếu giả định rằng dòng 7020 bị ảnh hưởng còn dòng 7000 thì không, thì đúng là vậy
    • Không biết PlayStation 5 thì sao. Xbox và thiết bị kia của Valve chắc cũng tương tự
    • Ryzen 5000 không có Radeon thì không bị ảnh hưởng sao? Có vẻ các bộ xử lý đó là Zen 3
      AMD Ryzen 9 5950x Desktop Processor của tôi cũng có vẻ là Zen 3 nên chắc ổn
      Tôi không chạy tác vụ không đáng tin cậy, nhưng vẫn cứ nên cẩn thận thì hơn
    • Nhân tiện, Ryzen 3000 APU không phải Zen 2
  • Trang web đang sập vì quá tải lưu lượng: https://web.archive.org/web/20230724143835/https://lock.cmpx...

    • Chỉ là một trang HTML tĩnh đơn giản, nên tôi không hiểu nổi vì sao năm 2023 mà trang tĩnh vẫn có thể chết vì traffic
      Trong đa số trường hợp, traffic từ HN còn chẳng đạt nổi 100 pageview mỗi giây
    • Link nhanh hơn: https://archive.is/QAwvQ
    • Bản gốc cuối cùng rồi cũng tải được. Có thể tùy môi trường
  • https://www.amd.com/en/resources/product-security/bulletin/a...
    Theo thông báo bảo mật của AMD, bản cập nhật firmware cho CPU không phải EPYC sẽ không có cho tới cuối năm. Vậy đến lúc đó người dùng phải tắt chicken bit và chấp nhận tổn thất hiệu năng sao?

    • AMD có tỉnh táo không vậy? Đây không phải mức độ nghiêm trọng trung bình
  • Vừa ấn tượng vừa đáng sợ. Sau khi chạy mẫu 10MB trong 1 phút, tôi đã có thể “rò rỉ” được một phần mật khẩu Bitwarden của mình, mật khẩu đăng nhập ssh, các mảnh thông tin xác thực ngân hàng, và có thể dễ dàng ghép lại

  • Bài viết thực sự rất hay. Tôi đặc biệt thích phần bàn về cách có thể xác định liệu một chương trình được sinh ngẫu nhiên có chạy đúng hay không
    Cách tiếp cận hiển nhiên là chạy nó trên một oracle như bộ xử lý khác hoặc trình mô phỏng để xem nó có hoạt động theo cùng một cách hay không
    Nhưng để kiểm tra các hiệu ứng vi kiến trúc trong những cửa sổ thời gian hẹp, người ta cũng có thể viết cùng một chương trình với nhiều stall, fence, nop v.v. được chèn vào. Trong mã đơn luồng, điều đó không được ảnh hưởng đến đầu ra, nhưng bên trong CPU thì vi kiến trúc sẽ thực hiện những việc khá khác nhau. Nhờ vậy CPU có thể trở thành oracle của chính nó

    • Phần này thực sự rất thú vị, đặc biệt là sự khác biệt giữa fuzzing phần mềm và fuzzing phần cứng
      Tôi cũng thích cả chicken bit