- Một trường hợp lần theo nguyên nhân khi phát hiện hiện tượng truyền hàng trăm gói tin chỉ với một lần nhấn phím trong phiên SSH
- Kết quả phân tích bằng
tcpdump cho thấy phần lớn gói tin là các thông điệp lặp lại có kích thước 36 byte, xuất hiện với khoảng cách khoảng 20ms
- Nguyên nhân là tính năng “làm rối thời điểm gõ phím” (keystroke timing obfuscation) được thêm vào SSH từ năm 2023, gửi nhiều gói “chaff” (SSH2_MSG_PING) để che giấu thời điểm người dùng nhập liệu
- Khi tắt tính năng này hoặc sửa để máy chủ không quảng bá phần mở rộng
[email protected], mức sử dụng CPU và băng thông giảm xuống còn chưa đến một nửa
- Đây là ví dụ cho thấy một tính năng bảo mật của SSH có thể trở thành gánh nặng lớn trong các ứng dụng đòi hỏi hiệu năng thời gian thực, chẳng hạn như game
Phát hiện vấn đề
- Trong lúc thử nghiệm TUI của một trò chơi hiệu năng cao chạy qua SSH, đã xác nhận hiện tượng 270 gói tin phát sinh chỉ với một lần nhấn phím
- Kết quả
tcpdump: 66% là thông điệp 36 byte, 33% là TCP ACK, phần còn lại là một lượng nhỏ dữ liệu khác
- Trung bình 90 gói/giây, dữ liệu được truyền cách nhau khoảng 11ms
- Trong quá trình thử nghiệm, máy chủ bị cấu hình sai nên chỉ gửi thông báo “your screen is too small”, và khi đó mức sử dụng CPU và băng thông giảm còn một nửa
- Dù dữ liệu game lẽ ra không được truyền thì mức dùng CPU phải gần 0%, nhưng vẫn duy trì quanh 50%
- Từ đó đặt ra khả năng có overhead truyền thông từ chính SSH
Quá trình điều tra
- Dùng
tcpdump để so sánh lưu lượng SSH giữa trạng thái hoạt động bình thường và trạng thái lỗi
- Ngay cả trong trạng thái lỗi, các gói 36 byte vẫn tiếp tục xuất hiện đều đặn mỗi 20ms
- Cùng một mẫu cũng được xác nhận trên SSH client mặc định của MacOS
- Kết quả phân tích file pcap bằng Claude Code cho thấy
- Trong tổng số 413.703 gói tin, 66% là 36 byte và 34% là ACK 0 byte
- Chính SSH client là bên chủ động tạo ra các gói tin này
Nguyên nhân gốc rễ
Cách khắc phục
- Ở phía client, có thể tắt tính năng này bằng tùy chọn
ObscureKeystrokeTiming=no
- Sau khi áp dụng, mức dùng CPU và băng thông giảm mạnh, trong khi việc truyền dữ liệu vẫn diễn ra bình thường
- Ở phía máy chủ, để xử lý vấn đề, phần quảng bá phần mở rộng
[email protected] đã bị loại bỏ khỏi thư viện SSH của Go
- Kết quả thử nghiệm sau khi hoàn tác commit liên quan:
- Mức sử dụng CPU 29.9% → 11.6%,
system call 3.10s → 0.66s,
tính toán mã hóa 1.6s → 0.11s,
băng thông 6.5Mbit/s → 3Mbit/s
- Hiệu năng cải thiện hơn 50%
Trải nghiệm gỡ lỗi với LLM
- Dùng Claude Code để tự động hóa phân tích
tcpdump và tshark, giúp nhanh chóng thu hẹp nguyên nhân vấn đề
- Có thể quan sát quá trình chạy lệnh theo thời gian thực để duy trì mô hình tư duy
- ChatGPT lại từng đánh giá sai rằng hành vi của SSH là “bình thường”, cho thấy sự khác biệt giữa các mô hình
- LLM không thay thế toàn bộ quá trình giải quyết vấn đề, nhưng cho thấy hiệu quả cao như một công cụ phân tích hỗ trợ
- Đây là một trường hợp kết hợp suy luận của con người với phân tích của LLM để giải quyết vấn đề hiệu năng mạng phức tạp
1 bình luận
Ý kiến Hacker News
Việc fork thư viện crypto của Go nghe có phần đáng ngại
Tôi đang nghĩ cách để giữ cho bản vá nhỏ của mình an toàn
Thực ra tôi nghĩ kiểu tính năng này nên được đưa upstream thành một tùy chọn của thư viện ssh
Trong môi trường không đáng tin cậy, việc gửi các gói chaff (gói nhiễu) làm mặc định là hợp lý, nhưng cũng có nhiều trường hợp muốn tiết kiệm băng thông
Giải pháp đúng là thêm một tùy chọn để máy chủ có thể báo cho máy khách rằng “không cần cái này”, còn máy khách thì có thể chấp nhận hoặc cảnh báo
Nó chỉ áp dụng cho phiên TTY, và máy khách có thể tắt đi
Chỉ là trường hợp lần này khá ngoại lệ vì máy chủ biết trước đây là một kết nối không quan trọng
Trong đa số trường hợp, máy khách sẽ kỳ vọng thiết lập ObscureKeystrokeTiming được tôn trọng
Thư viện crypto là một codebase rất thiên về quan điểm, đến mức ngay cả thứ tự TLS cipher suite cũng không cho đổi
Đây có vẻ là một trường hợp sử dụng rất đặc thù của SSH
Nếu phơi ra quá rộng, rất dễ dẫn đến kiểu “cấu hình rồi quên”, khiến bảo mật còn yếu đi
Cũng từng truyền thông qua modem 1200bps, còn modem 56K thì thực ra bị thổi phồng khá nhiều
Khoảng năm 1994 tôi làm ở một học viện quân sự tại Anh và lần đầu tiếp xúc với WWW, lúc đó còn nghĩ “cũng thường thôi”
Nghĩ lại bây giờ mới thấy thời thế đổi thay thật đáng kinh ngạc
Đây là lần đầu tôi nghe về tính năng obfuscation này, khá thú vị
Khi debug cách ssh hoạt động, vá
Nonecipher để xem trực tiếp nội dung gói tin cũng là một cách hayNếu là một trò chơi terminal mà bảo mật không quan trọng còn hiệu năng mới là ưu tiên, thì dùng telnet cũng đáng cân nhắc
Tôi không biết SSH lại làm chuyện này
Tôi hiểu vì sao nó được bật mặc định, nhưng trong môi trường của tôi có lẽ nên tắt đi
Vì vậy tôi định đặt
ObscureKeystrokeTiming=no. Có lý do gì khiến tôi không nên làm vậy không?(1) Không phải lúc nào con người cũng phân biệt được khi nào mình đang nhập bí mật, và toàn bộ hoạt động có thể bị phân tích mẫu
(2) Đây là kiểu tấn công mà ngay cả mức phòng thí nghiệm đại học cũng làm được — xem bài báo USENIX và ca nghiên cứu
(3) Trên một Internet mà traffic video chiếm áp đảo, hy sinh bảo mật chỉ để tiết kiệm vài byte từ phím gõ là không có ý nghĩa gì
Nếu kẻ tấn công phân tích timing phím gõ, họ có thể suy đoán lệnh và mẫu của mật khẩu đã mã hóa
Tất nhiên khóa phiên thay đổi mỗi lần nên việc giải mã là khó, nhưng khả năng đó vẫn tồn tại
Tôi cũng dán phần lớn mật khẩu từ trình quản lý mật khẩu
Đa số mọi người thấy mình tắt các tính năng bảo mật của SSH mà vẫn chẳng có vấn đề gì, nhưng đó chỉ là vì may mắn
Nếu thực sự cần hiệu năng thì dùng Telnet, còn nếu thực sự cần bảo mật thì nên dùng tổ hợp ContainerSSH + OAuth2
Năm 2004 tôi từng nghiên cứu phân tích độ trễ giữa các lần gõ phím trong phiên SSH để suy đoán lệnh
Xem tài liệu phân tích khi đó
Bản vá năm 2023 rốt cuộc đã giải quyết vấn đề đó
Tài liệu trình bày
Thời gian trôi thật nhanh
Tôi không chắc Claude thực sự có giúp được gì nhiều cho việc debug
Có vẻ tác giả đã biết sẵn hướng đi rồi, còn Claude chỉ như phụ họa theo
Việc Claude nói kiểu “Holy Cow!” hơi gây khó chịu
Tôi cũng dùng Claude khi debug cách hệ thống hoạt động; dù không có câu trả lời trực tiếp, nó vẫn giúp sắp xếp hiểu biết và giữ động lực
Rubber Duck Debugging wiki
Việc tác giả thích phản ứng kiểu “holy cow” và đưa nó vào blog cho thấy Claude đã bắt đúng không khí
Dùng TCP_CORK có thể giảm số gói tin mà không làm tăng độ trễ
Tắt TCP_NODELAY cũng là một cách, nhưng cái giá phải trả là độ trễ tăng lên
Khi cork socket, kernel sẽ buffer dữ liệu rồi chỉ gửi khi uncork hoặc khi đạt MSS
Tức là nó gom nhiều gói lại để gửi
Tài liệu tham khảo
Có lẽ vẫn nhận ping bình thường, nhưng có thể giảm số lần gửi pong
Tôi đã thử TCP_NODELAY rồi, nhưng độ trễ tăng lên nên không hợp với game của tôi
Bài HN trước đó
Vì mục đích obfuscation, chuyện gộp trễ (coalescing) có lẽ là không thể
Cụm “The smoking gun!” nghe buồn cười thật
Tôi không phải người bản ngữ tiếng Anh, mà Claude hay dùng nên tôi mới học được lần đầu
Giờ nó thật sự lan ra như một câu cửa miệng
Sự phụ thuộc vào LLM hơi đáng tiếc
Chuyện này có lẽ chỉ cần xem packet capture bằng Wireshark là giải quyết nhanh hơn
SSH dissector của nó khá trưởng thành
Chỉ cần bắt một lần gõ phím bằng tcpdump thôi cũng ra hàng trăm gói mã hóa
Dù sao thì nhờ LLM mà tác giả học được điều thú vị rồi chia sẻ lại, như vậy cũng đáng giá
Sau thông điệp NEWKEYS thì nó không parse được nữa, và kể cả khi vá sang mã hóa
nonethì cũng không diễn giải hoàn toàn luồng dữ liệuVẫn còn chỗ để cải thiện
Học hỏi bằng cách tận dụng công cụ cũng hoàn toàn có giá trị
Chỉ bắt gói đơn thuần thì rất khó thu được thông tin có ý nghĩa
Tôi không hiểu vì sao đó lại là điều đáng buồn
Năm 2023, SSH đã thêm tính năng làm rối timing phím gõ
Vì có thể suy đoán ký tự từ tốc độ gõ, SSH trộn thêm gói chaff để kẻ tấn công không phân biệt được
Nhưng tôi thấy đây là cách tiếp cận sai
Nếu thật sự muốn, chỉ cần gửi mọi lần gõ phím theo khoảng 50ms là được
Cách triển khai hiện tại là gom theo đơn vị 20ms, rồi nếu một lúc không có nhập liệu thì dừng gửi chaff
Cốt lõi của SSH là bảo mật, nhưng nếu không cần bảo mật thì tôi thắc mắc vì sao còn dùng SSH
Ví dụ netcat(nc) được cài sẵn trên hầu hết nền tảng
SSH còn có những cân nhắc khác như hiệu năng, sự tiện lợi, v.v.
Tác giả chỉ nói rằng tính năng làm rối phím gõ (privacy) là không cần thiết mà thôi
Họ vẫn có thể muốn giữ mã hóa hay đảm bảo tính toàn vẹn
Tức là giữ nguyên phần lớn tính năng bảo mật của SSH và chỉ tắt một phần