1 . Tổng quan
Gần đây,mình quan sát sự xuất hiện ngày càng nhiều của các CVE liên quan đến router và camera của những thương hiệu lớn, với điểm chung là đa số các lỗ hổng bảo mật này được phát hiện bởi các nhà nghiên cứu đến từ Trung Quốc. Trong bối cảnh đó, vai trò của một BlueTeam trở nên vô cùng quan trọng. Blueteam cần phải nắm bắt, nghiên cứu sâu rộng về những lỗ hổng bảo mật này để có thể đưa ra được những cảnh báo sớm đồng thời phát hiện và ngăn chặn các nguy cơ tấn công từ bên ngoài. Điều này đòi hỏi một quá trình nghiên cứu và phân tích tỉ mỉ, liên tục, mà sau một thời gian mình đã nghiên cứu và tìm hiểu sâu hơn.
Hôm nay, mình muốn chia sẻ một phần công việc mà BlueTeam thường làm đó chính là phân tích và tìm kiếm lỗ hổng trên firmware để xác định những điểm yếu tiềm ẩn có thể bị kẻ tấn công khai thác, từ đó đề xuất các giải pháp khắc phục hiệu quả, nhằm bảo vệ hệ thống mạng một cách toàn diện và đảm bảo an ninh thông tin cho tổ chức. Bài viết này sẽ cung cấp cái nhìn tổng quan cho những ai mới bắt đầu quan tâm đến lĩnh vực này. Sau khi xem xét nhiều hãng thiết bị router khác nhau thì mình để ý đến các sản phẩm của Linksys.
Và để các bạn có hướng tiếp cận thực tế nhất, mình sẽ khai thác lỗ hổng trên một trong những router được bán và sử dụng nhiều ở Việt Nam đó là Linksys E1700.
2. Chuẩn bị
Để chuẩn bị cho công việc khai thác lỗ hổng phần mềm trên router Linksys E1700, mình sẽ chuẩn bị các công cụ cho việc giải nén, và phân tích firmware bao gồm: IDA, binwalk. Công cụ để thực hiện khai thác sẽ là Burpsuite. Ngoài ra, chuẩn bị thêm 1 router Linksys E1700 để trực tiếp khai thác trên router này mà không qua môi trường giả lập.
Trích xuất firmware:
Đầu tiên, tải về firmware của Linksys E1700 được cung cấp bởi nhà sản xuất tại địa chỉ sau: https://downloads.linksys.com/downloads/firmware/FW_E1700_v1.0.04.003_20171201.bin
Sau khi tải về, dùng Binwalk phân tích xem và được kết quả như sau:
Từ kết quả thu được, có thể thấy 64 bytes đầu của tệp tin là Image Header, chứa các thông tin cơ bản về firmware như Timestamp, Image Size, Entry Point, OS, CPU, Image Name.
Phần dữ liệu phía sau từ vị trí 0x40 thì được nén bằng LZMA.
Ở đây, cờ -e đã được sử dụng nên phần dữ liệu sẽ được trích xuất để thực hiện các bước phân tích tiếp theo.
Như hình 1 và hình 2, phần dữ liệu ở vị trí đã được lưu dưới tên trùng với vị trí của nó, ở đây là “40”. Tệp tin 40.7z là một tệp nén của vùng dữ liệu này.
Tiếp tục sử dụng Binwalk với tệp tin 40 này.
Nhìn vào những gì binwalk phân tích, có thể thấy tệp tin này có chứa một AES S-Box, CRC32 Table, đặc biệt tại offset 0x4E9424 và 0x587000 là 2 vùng có chứa dữ liệu nén dưới dạng XZ compressed data.
Tuy nhiên khi kiểm tra lại phần hash của các vùng dữ liệu này, thu được kết quả tương tự như các tệp tin được trích xuất từ hình 4
Tiếp tục sử dụng Binwalk với vùng dữ liệu 0x587000 còn lại:
Tiếp tục sử dụng Binwalk với vùng dữ liệu 0x587000 còn lại:
Dữ liệu mà mình cần cuối cùng cũng đã được trích xuất:
Từ đây, mình đã có thể bắt đầu phân tích và tìm kiếm lỗ hổng.
3. Phân tích
Để có thể chiếm quyền điều khiển của router thì điều đầu tiên mà mình nghĩ tới chính là tìm cách bypass authentication. Điều này sẽ là tiền đề giúp mình khai thác được những lỗ hổng nghiêm trọng khác.
Trước khi đi vào phân tích source code, mình có fuzz qua một số endpoint xuất hiện nhiều trong cách tính năng của router. Phương pháp fuzzing yêu cầu người kiểm thử truyền dữ liệu ngẫu nhiên kết hợp phân tích hành vi của đối tượng được kiểm thử qua đó tìm kiếm được các lỗ hổng bảo mật. Sau một thời gian, mình đã tìm được lỗi có thể lấy được phiên làm việc hiện tại của quản trị. Đây là lỗi nghiêm trọng dẫn đến lỗ hổng Authentication Bypass nằm trong giao diện quản trị của router mà mình cần tìm.
Các bước thưc hiện khai thác như sau:
Đầu tiên, để lấy được ID phiên làm việc hiện tại của người quản trị, mình cần người quản trị đăng nhập vào giao diện quản lý web để router có thể tạo ra một chuỗi ID phiên làm việc hợp lệ.
Thứ hai, một khi người quản trị đã đăng nhập vào giao diện web, mình có thể gửi một yêu cầu GET đến URI: /goform/* với tiêu đề “Referer” chứa từ “login” để lấy ID phiên làm việc hiện tại của người quản trị.
Sử dụng session_id của người quản trị, mình có thể thực hiện các hành động tương tự như người quản trị bằng cách gửi các request cùng với session_id đã thu thập. Đơn giản hơn, mình chỉ cần sử dụng chức năng ExportSettings để lấy mật khẩu đăng nhập của Admin và sử dụng mật khẩu này cho các lần đăng nhập sau:
Tuy nhiên như đã trình bày ở trên điều kiện để khai thác được lỗ hổng này là admin phải thực hiện đăng nhập trước để có thể tạo và lưu chuỗi ID phiên trên hệ thống và ID phiên này vẫn chưa bị hết hạn. Từ đó mình mới có thể lấy được ID phiên này.
Với lỗ hổng này, hacker có thể tùy ý thay đổi cấu hình của router, qua đó dẫn tới rất nhiều nguy cơ bảo mật cho người trong mạng như nghe lén, điều hướng đến trang web độc hại, thậm chí là tấn công các máy tính kết nối tới mạng wifi này.
Như vậy mình đã thực hiện tìm kiếm và khai thác xong lỗ hổng đầu tiên. Do cũng chưa có kinh nghiệm nhiều trong việc kiểm thử firmware nên mình có đọc một số bài phân tích các lỗ hổng firmware mới gần đây của các “pháp sư” đến từ Trung Hoa thì mình nhận ra rằng các đa số các lỗ hổng thực thi lệnh tùy ý mà họ tìm ra đều nhờ khai thác lỗi command injection.
Đối với lỗ hổng Command Injection, các lỗ hổng này được gây ra thường do người lập trình đã không kiểm tra hoặc làm sạch dữ liệu đầu vào, sau đó đưa trực tiếp dữ liệu này vào hàm thực thi mã lệnh. Trong ngôn ngữ lập trình C, system() là một hàm thường được sử dụng để thực thi lệnh. Như vậy, mình sẽ thử tìm lỗi bằng cách tìm các đoạn mã mà trong đó, dữ liệu người dùng nhập được đưa trực tiếp vào hàm system(). Trong việc phân tích mã nguồn tìm lỗi, đây được gọi là “sink”.
Để đi theo hướng này, đầu tiên mình sẽ sử dụng chức năng Xrefs để tìm các đoạn mã và các hàm gọi tới hàm system().
Sau khi đọc qua toàn bộ các hàm có gọi system(), nhận thấy hàm doSystem() được thiết kế riêng cho việc thực thi command và trong hàm có cả chức năng chống lỗi buffer overflow:
Tiếp tục đi tìm referrer của hàm doSystem(), mình thấy hàm doSystem() được gọi tới 464 lần.
Sau khi kiểm tra các ref này, thấy hàm setDateTime() gọi doSystem() và doSystem() nhận giá trị truyền vào trực tiếp từ hàm sub_3970() – là hàm nhận giá trị truyền vào từ người dung thông qua phương thức POST mà không được kiểm tra hay làm sạch.
Như vậy, hàm setDateTime() chính là “sink” cần tìm. Việc tiếp theo là tìm cách để gọi được hàm setDateTime() ra. Tiếp tục đi tìm hàm gọi của setDateTime() qua chức năng Xrefs, thấy setDateTime được gọi qua hàm NTP().
Tại đây, dễ dàng nhận thấy rằng setDateTime() sẽ được gọi khi thỏa mãn các điều kiện:
- Giá trị của: time_zone không được bỏ trống, không có dấu ‘;’
- Giá trị của: timeTag phải là ‘manual’
Tiếp theo, mình có thể thực hiện chèn lệnh bằng cách đặt bất kỳ tham số nào sau đây: manual_year_select, manual_month_select, manual_day_select, manual_hour_select, manual_min_select, manual_sec_select và bao gồm cả ký tự backtick (`).
Tiếp tục sử dụng Xrefs để tìm điểm vào của NTP():
Như vậy, hàm sub_43A0C là hàm sẽ gọi đến NTP():
Phân tích hàm này cho thấy hàm này xử lý các request đến URI: /goform/*. Như vậy, request tấn công sẽ cần phải được gửi đến /goform/NTP. Ngoài ra, để sự dụng chức năng goform, mình cũng cần cung cấp giá trị token do trong hàm xử lý có kiểm tra giá trị này.
Token là một giá trị để verify request trong hầu hết các chức năng của router. Ở đây mình sẽ sử dụng /network/ddns.shtml để lấy giá trị token này. Mã nguồn:
Lấy token sử dụng burpsuite:
Như vậy, mình có thể vẽ được luồng thực thi để khai thác lỗ hổng như sau:
Như vậy, từ tất cả các thông tin đã thu thập, có thể tạo request để thực thi chạy mã từ xa có nhiệm vụ tạo file pwn.js với nội dung “pwned” nằm trong web root như sau:
Sau khi thực thi, thấy file pwn.js đã được tạo thành công:
Như vậy mình đã hoàn thành việc khai thác lỗ hổng thực thi mã từ xa.
4. Tổng kết
Đến đây là đã kết thúc toàn bộ các bước mình chiếm quyền điều khiển của một router. Mình hi vọng thông qua bài phân tích này có thể giúp các bạn có thể hiểu hơn về quá trình phân tích một firmware và tìm được các lỗ hổng khác có impact cao như Stack-based buffer overflow, Out-of-bounds write, …. Đối với việc phân tích lỗ hổng vượt qua xác thực, bạn đọc có thể tự mày mò đọc mã nguồn để hiểu được tại sao lỗ hổng này lại xảy ra. Cảm ơn các bạn đã đọc bài viết của mình, mong rằng các bạn đã phần nào đó có thêm kiến thức về cách phân tích firmware. Ở những phần sau mình sẽ có những phân tích chi tiết hơn. Rất vui nếu nhận được các ý kiến đóng góp từ mọi người!
———————————————————————-
Update: bug đã được gán CVE-2024-22543 và CVE-2024-22544
By,
Blue_Team