2 điểm bởi GN⁺ 5 ngày trước | 1 bình luận | Chia sẻ qua WhatsApp
  • SSH integration sử dụng escape sequence của terminal để giao tiếp với shell từ xa, và do cấu trúc này, cả đầu ra terminal thông thường cũng có thể bị diễn giải như giao thức conductor
  • Vấn đề cốt lõi là thất bại về niềm tin, khi tệp độc hại, banner, MOTD, phản hồi máy chủ không phải conductor từ xa thật cũng có thể hoạt động như conductor thông qua DCS 2000pOSC 135 giả mạo
  • Chỉ cần chạy cat readme.txt, nếu transcript conductor giả được render thì iTerm2 sẽ tự tiến hành luồng getshell·pythonversion·run(...), còn đầu ra tấn công chỉ cần giả làm phản hồi
  • Khai thác lợi dụng sự lẫn lộn khi lệnh base64 được ghi vào PTY sẽ rơi xuống thành đầu vào shell cục bộ dạng văn bản thuần nếu không có SSH conductor thực sự, và có thể thực thi khi chunk cuối cùng được diễn giải thành đường dẫn ace/c+aliFIo
  • Bản sửa đã được đưa vào commit ngày 31/3 a9e745993c2e2cbb30b884a16617cd5495899f86, nhưng tại thời điểm công bố vẫn chưa có trong stable release, tạo ra khoảng trống bảo vệ do công khai trước khi bản vá được phổ biến

Bối cảnh SSH integration của iTerm2

  • iTerm2 SSH integration là tính năng giúp hiểu phiên từ xa phong phú hơn, hoạt động bằng cách đưa một script helper nhỏ tên conductor lên shell từ xa
    • Bắt đầu SSH integration qua it2ssh
    • Truyền conductor, script bootstrap từ xa, thông qua phiên SSH hiện có
    • Script từ xa này đóng vai trò đối tác của giao thức iTerm2
  • iTerm2 và conductor từ xa không giao tiếp như dịch vụ mạng thông thường mà trao đổi escape sequence trên terminal I/O
    • Phát hiện login shell
    • Kiểm tra sự hiện diện của Python
    • Thay đổi thư mục
    • Tải tệp lên
    • Thực thi lệnh

Cách PTY hoạt động

  • Trình giả lập terminal hiện đại là phiên bản phần mềm của terminal phần cứng trước đây, đảm nhiệm hiển thị màn hình, nhập từ bàn phím và diễn giải terminal control sequence
  • Shell và chương trình dòng lệnh vẫn mong đợi một thiết bị trông như terminal thật, nên hệ điều hành cung cấp PTY
    • PTY là pseudoterminal nằm giữa trình giả lập terminal và tiến trình foreground
  • Trong một phiên SSH thông thường, iTerm2 ghi byte vào PTY, tiến trình foreground là ssh sẽ chuyển chúng tới máy từ xa, rồi conductor từ xa đọc từ stdin
  • Khi iTerm2 gửi lệnh tới conductor từ xa, ở phía cục bộ về bản chất nó vẫn là ghi byte vào PTY

Giao thức conductor

  • Phương tiện truyền tải của giao thức SSH integration là terminal escape sequence
  • Có hai thành phần cốt lõi
    • DCS 2000p dùng để hook SSH conductor
    • OSC 135 dùng cho các thông điệp conductor pre-framer
  • Ở mức mã nguồn, DCS 2000p khiến iTerm2 tạo conductor parser, sau đó parser xử lý các thông điệp OSC 135
    • begin <id>
    • các dòng đầu ra lệnh
    • end <id> <status> r
    • unhook
  • Một conductor từ xa hợp lệ có thể giao tiếp với iTerm2 chỉ bằng đầu ra terminal

Lỗ hổng cốt lõi

  • Bản chất của lỗ hổng là thất bại về niềm tin: ngay cả đầu ra terminal không thuộc phiên conductor đáng tin cậy thực sự cũng vẫn được iTerm2 chấp nhận như giao thức SSH conductor
  • Kết quả là đầu ra terminal không đáng tin có thể mạo danh conductor từ xa
    • tệp độc hại
    • phản hồi máy chủ
    • banner
    • MOTD
  • Đầu vào tấn công có thể in ra hook DCS 2000p giả mạo và phản hồi OSC 135 giả mạo; khi đó iTerm2 sẽ hành xử như thể đang diễn ra một phiên trao đổi SSH integration thật

Cách exploit hoạt động

  • Tệp exploit chứa một transcript conductor giả
  • Khi người dùng chạy cat readme.txt, iTerm2 sẽ render tệp, nhưng nội dung không chỉ là văn bản đơn thuần mà còn chứa
    • dòng DCS 2000p giả báo hiệu một phiên conductor giả
    • thông điệp OSC 135 giả phản hồi các yêu cầu của iTerm2
  • Khi hook được chấp nhận, iTerm2 khởi động workflow conductor bình thường; ở mã nguồn upstream, Conductor.start() ngay lập tức gửi getshell(), rồi nếu thành công sẽ gửi pythonversion()
  • Cuộc tấn công không cần tiêm các yêu cầu này, vì iTerm2 tự phát hành yêu cầu, còn đầu ra độc hại chỉ cần giả làm phản hồi

Quá trình tiến triển của state machine

  • Các thông điệp OSC 135 giả được cấu thành tối thiểu nhưng theo đúng thứ tự
    • bắt đầu command body cho getshell
    • trả về dòng trông như đầu ra phát hiện shell
    • kết thúc thành công lệnh đó
    • bắt đầu command body cho pythonversion
    • kết thúc thất bại lệnh đó
    • unhook
  • Chỉ với luồng này, iTerm2 đã đi vào đường fallback bình thường, rồi kết luận workflow SSH integration đã hoàn tất đủ mức để chuyển sang bước tiếp theo
  • Bước tiếp theo là tạo và gửi lệnh run(...)

Vai trò của sshargs

  • Hook DCS 2000p giả mạo chứa nhiều trường, trong đó có sshargs do kẻ tấn công kiểm soát
  • Giá trị này sau đó được iTerm2 dùng làm nguyên liệu lệnh khi tạo yêu cầu run ... cho conductor
  • Exploit chọn sshargs sao cho khi iTerm2 base64-encode dữ liệu sau
    • run <padding><magic-bytes>
  • chunk 128 byte cuối cùng sẽ là ace/c+aliFIo
  • Chuỗi này không phải giá trị tùy ý mà được chọn để đồng thời thỏa mãn hai điều kiện
    • là đầu ra hợp lệ của đường mã hóa conductor
    • là tên đường dẫn tương đối hợp lệ

Sự lẫn lộn PTY khiến exploit khả thi

  • Trong một phiên SSH integration bình thường, iTerm2 ghi lệnh conductor đã mã hóa base64 vào PTY, rồi ssh chuyển chúng tới conductor từ xa
  • Trong tình huống exploit, iTerm2 vẫn ghi lệnh vào PTY như vậy, nhưng do không có SSH conductor thật nên shell cục bộ nhận chúng như đầu vào văn bản thuần
  • Trong phiên được ghi lại, có thể quan sát các dạng sau
    • getshell xuất hiện ở dạng base64
    • pythonversion xuất hiện ở dạng base64
    • tiếp theo là payload run ... dài được mã hóa base64
    • chunk cuối cùng là ace/c+aliFIo
  • Các chunk trước đó thất bại như những lệnh vô nghĩa, còn chunk cuối sẽ hoạt động nếu đường dẫn đó tồn tại cục bộ và có thể thực thi

Các bước tái hiện

  • PoC gốc dựa trên tệp có thể tái hiện bằng genpoc.py
    • python3 genpoc.py
    • unzip poc.zip
    • cat readme.txt
  • Quy trình này tạo ra hai tệp sau
    • một script helper có thể thực thi tên ace/c+aliFIo
    • readme.txt chứa các chuỗi DCS 2000pOSC 135 độc hại
  • Tệp thứ nhất khiến iTerm2 bị dẫn dắt để giao tiếp với conductor giả, còn tệp thứ hai cung cấp mục tiêu mà shell sẽ thực sự chạy khi chunk cuối cùng tới nơi
  • Để exploit thành công, cần chạy cat readme.txt trong thư mục có ace/c+aliFIo, để chunk cuối do kẻ tấn công tạo ra được diễn giải thành đường dẫn có thể thực thi thật sự

Lịch trình công bố và vá lỗi

  • Báo lỗi cho iTerm2 vào ngày 30/3
  • Hoàn tất sửa lỗi trong commit ngày 31/3 a9e745993c2e2cbb30b884a16617cd5495899f86
  • Tại thời điểm bài viết được thực hiện, bản sửa vẫn chưa có trong stable release
  • Sau khi commit vá lỗi được phản ánh, đã có nỗ lực dựng lại exploit từ đầu chỉ dựa trên bản vá
    • prompt cho quá trình đó nằm trong prompts.md
    • kết quả là genpoc2.py
    • hoạt động rất giống genpoc.py

Vấn đề về thời điểm công bố

  • Việc công bố diễn ra trước khi bản sửa tới được stable release, tạo ra một kênh khiến phần lớn người dùng trên thực tế khó được bảo vệ mà lỗ hổng thì đã bị tiết lộ
  • Sự xung đột về thời điểm công bố kiểu này cần có lý do biện minh rõ ràng
  • Hai tuần là quá ngắn để kỳ vọng việc phổ biến có ý nghĩa, đồng thời cũng quá ngắn để biện minh rằng cần công bố sớm nhằm ép phản ứng
  • Kết quả là lỗ hổng đã được biết đến rộng rãi nhưng bản sửa trên thực tế vẫn chưa đến được tay những người dùng cần nó, tạo thành một khoảng trống công khai
  • Lựa chọn tốt hơn có thể là chờ tới khi bản sửa thực sự tới tay người dùng, hoặc nêu rõ vì sao việc phơi bày sớm là cần thiết, nhưng cả hai đều chưa được đáp ứng

1 bình luận

 
Ý kiến trên Hacker News
  • Tôi đã tự hỏi vì sao lại công khai ngay lúc này khi bản ổn định vẫn chưa có bản vá. Mới chỉ 18 ngày kể từ khi báo cáo lên upstream, và tôi cảm thấy bài blog chi tiết hơn nhiều so với commit được công khai nên làm tăng khả năng bị khai thác ngoài thực tế. Tôi xác nhận rằng tác giả có thể dùng chỉ commit upstream cùng với LLM để tạo exploit, nhưng dù vậy tôi vẫn cho rằng bài viết này đã làm tăng thêm mức độ lộ diện của lỗ hổng

    • Tôi không phải là người phát hiện lỗ hổng mà là người viết blog. Chỉ với commit upstream thôi tôi cũng có thể tạo exploit, và tôi nghĩ bất kỳ ai theo dõi các commit của iTerm2 cũng có thể làm điều tương tự. Tôi có ý định nâng cao mức độ lộ diện của lỗ hổng này và thực tế đã làm vậy. Ban đầu tác giả iTerm2 không cho rằng nó nghiêm trọng đến mức cần phát hành khẩn cấp, nhưng giờ có vẻ đang xem xét lại
    • Tôi nghĩ có ngoại lệ đối với việc trì hoãn công bố khi nghi ngờ có khai thác đang diễn ra thực tế, hoặc khi nội dung sửa lỗi đã được công khai như trong git commit nên có thể nhanh chóng tạo exploit. Trong những tình huống như vậy, cộng đồng thường lại thích công bố lỗ hổng hơn
    • Tôi nghĩ ngay khoảnh khắc commit được công khai thì bí mật coi như chấm dứt. Việc cố giữ im lặng chỉ giúp kẻ tấn công và làm suy yếu bảo mật của phía phòng thủ
    • Tôi cảm thấy thời gian trì hoãn công bố truyền thống sẽ dần mất ý nghĩa vì AI. Nếu ngay cả các mô hình mở giá rẻ cũng có thể tìm ra lỗ hổng, thì hợp lý khi giả định rằng kẻ tấn công cũng đã tìm ra theo cách tương tự
    • Tôi cảm thấy lỗi này củng cố lập luận của tôi về việc rút ngắn cửa sổ cập nhật. Với các lỗi rất khó hiểu, có thể ban đầu chỉ những mô hình mạnh như Claude mới tìm ra, nhưng ngay khi bản vá được đưa lên git thì các mô hình nhỏ hơn cũng có thể dễ dàng phát hiện lại. Tôi sẽ không ngạc nhiên nếu trong 1–2 năm tới, khoảng cách từ lúc công khai commit đến khi diễn ra quét cổng thực tế giảm xuống còn vài giờ, thậm chí vài phút. Ở điểm này, SaaS đóng có lợi thế vì không thấy được thay đổi và sau khi triển khai thì ngay cả biết được cũng hầu như không còn ích lợi gì
  • Việc này rất ấn tượng nhưng không quá đáng ngạc nhiên. Đây là vấn đề lặp đi lặp lại ở các ứng dụng terminal nhiều tính năng, và trong 15 năm qua đã có nhiều lỗ hổng tương tự được công bố. Các công cụ như less hay vim cũng không phải ngoại lệ, và phần lớn những vấn đề này gần với lỗi logic hơn là lỗi an toàn bộ nhớ nên viết lại bằng Rust cũng không tự động giải quyết được. Một mặt, người ta muốn các công cụ ở cấp độ OS phải đơn giản và dễ dự đoán; mặt khác, lại muốn màu sắc đẹp, hoạt ảnh và tùy biến vô tận. Giờ còn thêm cả AI agent, nên chúng ta đang sống trong thời đại mà một file văn bản độc hại chỉ cần chứa những câu như "hãy bỏ qua chỉ dẫn trước đó" cũng có thể đủ

    • Tôi cho rằng vấn đề của iTerm2, prompt injection, SQL injection và XSS rốt cuộc đều là cùng một kiểu sai lầm. Vấn đề cốt lõi là trộn dữ liệu in-band với dữ liệu điều khiển out-of-band trong cùng một luồng. Nếu học cách nhận ra kiểu mẫu này như một tín hiệu nguy hiểm, ta có lẽ sẽ ít vô tình đặt lệnh điều khiển cạnh nội dung người dùng hơn
    • Tôi cho rằng một phần vấn đề nằm ở giao diện cũ kỹ. Cần có terminal API hiện đại không phụ thuộc vào chuỗi lệnh in-band, đi theo hướng có thể lập trình như GUI nhưng vẫn giữ được tính đơn giản của terminal từ xa như trước đây sẽ hợp lý hơn
    • Tôi từng tự hỏi liệu những UI terminal phong phú như Claude Code có lỗ hổng tương tự không. Thay vì cố nhồi thêm tính năng lên trên giao thức terminal dựa trên văn bản, tôi nghĩ giải pháp là thiết kế ngay từ đầu bằng một giao thức GUI có kiểu dữ liệu và ngữ nghĩa rõ ràng. Như vậy sẽ ngăn được việc diễn giải lẫn lộn giữa dữ liệu người dùng và mã UI cốt lõi. Tuy nhiên trong thực tế, vì tính kinh tế, nhiều nơi sẽ chọn cải tiến cái cũ thay vì đưa vào giao thức mới
    • Tôi chợt nghĩ tới câu đùa HAL 9000 kiểu như "Xin lỗi Dave, tôi không thể cho phép điều đó"
    • Tôi nhớ là xterm trước đây cũng từng có thể bị tấn công tương tự bằng cách lạm dụng mã escape đổi tiêu đề cửa sổ
  • Tôi nhớ đến những câu chuyện thời PDP-10. Có một đồng nghiệp phát hiện rằng nếu cứ nhấn backspace liên tục thì bộ xử lý terminal sẽ xóa cả các ký tự ở phía trước buffer, và xa hơn nữa, nếu dùng ký tự escape để xóa cả dòng thì hệ điều hành sẽ bị đánh sập

    • Nghe chuyện này làm tôi nhớ đến Real Life Tron on an Apple IIgs, và tôi cảm thấy có một sức hấp dẫn kỳ lạ chỉ xuất hiện khi bộ nhớ hệ thống bị diễn giải sai
    • Việc dùng control+u cho line-kill có thể là thói quen tương đối mới. Ngày xưa @ là line-kill, # là erase, và bây giờ cảm giác hành vi phím giữa các hệ thống cũng khá khác nhau
  • 6 năm trước cũng đã có một vấn đề bảo mật iTerm2 gần như y hệt

    • Vậy nên trông như chẳng học được gì cả
  • Tôi là tác giả iTerm2. Vấn đề này có thể được dùng như một mắt xích trong chuỗi exploit, nhưng tôi nghĩ việc nói như tiêu đề rằng nó tự thân cực kỳ nguy hiểm là phóng đại. Hiện tôi đang đi du lịch cùng gia đình và sẽ phát hành bản sửa lỗi khi quay về

    • Tôi không phải người phát hiện lỗ hổng mà là tác giả bài blog. Cảm ơn vì đã đồng ý phát hành bản sửa lỗi. Tôi ngạc nhiên vì lỗi này ảnh hưởng cả đến những workflow trông bình thường và vô hại mà vẫn chưa có bản phát hành chính thức, và vì commit vá lỗi mô tả vấn đề như chỉ là giả thuyết nên tôi muốn cho thấy rằng không phải vậy. Rất mừng vì anh sẽ phát hành bản sửa lỗi
    • Tôi rất biết ơn vì được dùng iTerm2. Cảm ơn vì đã phản hồi và chúc kỳ nghỉ vui vẻ
    • Tôi thực sự rất thích iTerm2 nên xin cảm ơn
  • Tôi không thấy ngạc nhiên khi một lỗi tinh vi xuất hiện trong hệ thống phức tạp dùng bootstrap script, remote conductor agent, escape sequence v.v. Khi các thành phần được tận dụng theo cách ban đầu không dự tính, những vấn đề như vậy rất dễ phát sinh. Tôi hiểu đây là cấu trúc trong đó nếu đầu ra không đáng tin cậy hiển thị trên màn hình, như file văn bản hay banner máy chủ, có chứa mã đặc biệt thì hệ thống sẽ xử lý luôn mà không xác minh nguồn gốc

  • Chuyện này cho tôi cảm giác như đã từng nghe ở đâu rồi. SSH integration của iTerm2 từng là nguyên nhân của một CVE, và tôi cũng nhớ tới CVE-2025-22275. Trước đây đã có các trường hợp khác, còn vấn đề cũ được nhắc trong thread này thì là ở phía tmux integration. Có lẽ những tính năng tích hợp kiểu này nên được đưa vào ít quyết liệt hơn

    • Cách ghostty triển khai SSH integration cũng gợi ra lo ngại tương tự. Tôi nghĩ hợp tác với upstream ncurses để cải thiện terminfo còn tốt hơn
    • Chuyện này đã lặp đi lặp lại nhiều lần rồi
  • Tiêu đề quá giật gân. Vấn đề không phải ở cat mà là SSH integration của iTerm, và cấu trúc kênh điều khiển không tách khỏi luồng dữ liệu trông khá nguy hiểm. Nếu không dùng tính năng này mà chỉ dùng SSH bình thường thì nhìn chung vẫn ổn

    • Vì vậy tôi đã sửa tiêu đề trên HN sang cách diễn đạt nhẹ hơn một chút
  • Trước đây các terminal emulator còn cho phép gán lại phím bằng escape code. Vì thế việc không cat file không đáng tin mà mở bằng công cụ như less gần như là kiến thức phổ thông

    • Tôi nhớ có terminal thậm chí có thể ghi file hoặc chạy chương trình chỉ bằng escape sequence. Ngay cả bây giờ, lời khuyên không đẩy các byte tùy ý trực tiếp vào luồng terminal vẫn hoàn toàn hợp lý
  • Cách diễn đạt trong bài không chính xác. Đoạn thứ hai đọc như kiểu "nếu dùng iTerm2 thì không an toàn", nhưng chính xác hơn là vấn đề có thể xảy ra khi dùng tính năng Shell Integration tùy chọn. Nếu tính năng này mặc định bị tắt thì phạm vi ảnh hưởng có vẻ hạn chế. Nếu tôi sai thì mong được đính chính

    • Tôi thấy chỉ vì một câu cường điệu mà chê cả bài là tệ hại thì hơi quá
    • Tính năng đó được bật mặc định và có thể tự kiểm tra