Mở đầu
Gần đây mình có làm một project nghiên cứu nho nhỏ với đề tài ngắn gọi lại là: Hack 3 con camera. Thế nào lại báo cáo đúng thời điểm ca sĩ nào đó bị lộ hàng nóng vì camera bị hack ( ͡° ͜ʖ ͡°). Thấy anh em cùng phòng hỏi quá nên mình viết một bài “demystify” lỗi trên mấy con cam cùi vậy.
Target 1.
Target đầu tiên là một con camera cây nhà lá vườn được mình “trưng dụng”. Nhớ lại thì ngày trước mua vài con gắn tại cửa hàng của gia đình. Trên camera không có bất cứ thông tin gì từ nhà sản xuất ngoại trừ credential mặc định.
Recon.
Nmap scan thấy 3 port tcp: 23 – telnet, 80 – http, 9600 (?).
Mình sử dụng 1 wordlist các password hay dùng của mấy con camera Trung Quốc bruteforce thử telnet. Ra credential là root – 123456.
Do UPnP được tự động bật, Shodan scan thấy nhiều thiết bị:
Confirm các port mở:
Tới đây thì mình tìm cách lấy binary trên thiết bị, do busybox trên thiết bị hỗ trợ tftp nên cách dễ nhất là setup server gửi file về.
Phân tích binary encoder.
Binary không sử dụng các cơ chế bảo vệ nào, nếu tìm được stack overflow khả năng cao sẽ lên được shell.
Tuy nhiên với target này không cần đến stack overflow, mình tìm thấy kha khá lỗi cho phép sử dụng command injection với data từ web interface.
Chức năng update binary.
Thiết bị sử dụng GoAhead webserver với chức năng riêng được implement qua CGI module. Các CGI module được compile trực tiếp vào binary, access bằng các link có đuôi .cgi và xác thực sử dụng username và password admin trong request.
Riêng với chức năng update binary, update html, camera control và decoder control. Xác thực CGI bị bỏ qua.
Firmware file được xử lý bằng nhiều binary:
RE một lúc thì có được cấu trúc update file info header.
Trong đoạn code parse update header tại sysdepack có lỗi command injection thực thi lệnh qua system.
– Chỉ cần set dirname + file name = lệnh là đã có 128 byte buffer cho command. Set size = -1 để thoát update function mà không ghi đè firmware.
Có thể sử dụng lỗi này để thực hiện unauth RCE. Tuy nhiện thiết bị reboot ngay sau khi chạy script update nên với lỗi này không làm gì được nhiều.
Chức năng mail và ftp.
Mình cũng thấy các lỗi injection tương tự trong chức năng gửi mail và ftp. Tuy nhiên cần cung cấp credential để dùng 2 chức năng cgi này.
Test script được tạo trong chức năng testftp sau đó được thực thi:
Chèn lệnh trong chức năng testmail qua địa chỉ mail trong biến v1, lần này câu lệnh được gọi bằng popen:
Leak info.
Đối với các request file không có đuôi .cgi. Đoạn code xử lý authentication tóm gon như sau:
Nếu trong request tồn tại cặp “loginuse” + “loginpas” hoặc “user” + “pwd” (không cần valid). Phần xác thực hoàn toàn bị bỏ qua.
2 file đáng chú ý là:
– system.ini – chứa config camera như các tài khoản quản trị, tài khoản mail, ftp
– network.ini – chứa ip, DNS config, tài khoản wifi
Kết hợp lỗi này lấy tài khoản admin với lỗi chèn lệnh trong chức năng mail hoặc ftp => reliable unauthenticated RCE.
Target 2.
Recon.
Con camera này minh mua trên shopee có tên carecam.
Thiết bị sử dụng app cùng tên để điều khiển. Search một hồi thì ra trang chủ: www.smartcloudcon.com
Port scan ra một loạt các port, từ telnet, http, https tới các port lạ như 843, 1234, 1300…
Do con cam này thiếu dấu hiệu đặc trưng nên khó scan. Mình dùng zmap scan dải của VN thấy 58 thiết bị. nhưng false positive cũng khá nhiều.
Như con cam trước mình thử tìm đường vào qua telnet => không bruteforce được credential.
Hàn dây vào chân serial của thiết bị, mình lấy được firmware qua uboot, cách lây theo phương pháp này bạn đọc có thể tham khảo tại https://tradahacking.vn/cam9-ph%C3%ADa-sau-m%E1%BB%99t-c%C3%B4-g%C3%A1i-90e5192554ec
Extract qua binwalk. Mình thấy password telnet mặc định trong file shadow trên thiết bị là root – 123. Nhưng sau khi bootscript chạy. File /etc/shadow bị ghi đè với file /app/shadow – root:z1YC93pV6OlQI:17771:0:99999:7:::.
Sửa lại firmware xóa file này đi => cuối cùng cũng có shell.
List các binary đang mở cổng trên camera:
Mình search thông tin về các binary thì tìm được series này của các bạn bên VNPT sec: https://sec.vnpt.vn/2018/12/tan-man-ve-1-chiec-ip-camera-nao-do/
Hóa ra con cam này với loại camera liveyes clone từ 1 source ra. Tới đây thì confirm lại bug thôi.
RCE as a feature
Port 1300 được binary noodles sử dụng, Chức năng chính của binary này là handle download, upload file cũng như thực hiện update firmware, cụ thể:
Request gửi tới port này được parse theo tag để nhận thông tin file và chọn function xử lý cụ thể theo các case đã nêu, sau đó mới nhận nội dung file nếu có.
Trong các case xử lý có 3 chức năng khá hay là ELFEXEC, SYSTEM, SYSTEMEX trong đó:
– ELFEXEC nhận binary, script,… từ user và thực thi. Quá trình thực thi qua hai bước:
o Nhận thông tin file qua data gửi lên port 1300 dưới format ‘<ELFEXEC><FNAME>’ + filename + ‘</FNAME><FSIZE>’ + filesize + ‘</FSIZE></ELFEXEC>’
o Nhận file data, ghi ra file và thực thi.
– Chức năng SYSTEM và SYSTEMEX cũng hoạt động tương tự, nhưng nhận lệnh thay vì file.
– Để sử dụng 3 chức năng này không cần qua bất cứ xác thực nào.
Các lỗi tràn bộ đệm và command injection.
Trong chức năng UPGRADE:
Trong đoạn code xử lý của chức năng “UPGRADE”, Buffer ‘s’ có độ dài tối đa 0x1cc byte có thể bị tràn khi hàm sub_F208 sao chép mọi dữ liệu từ giữa hai nhãn <METHOD></METHOD> mà không kiểm tra độ dài, khi request gửi tới có thể dài tới 0x400 byte.
Trong hàm sub_9DE4, là hàm thực thi download dữ liệu theo yêu cầu và ghi ra file. Tồn tại cả hai lỗi chèn lệnh và tràn bộ đệm do sử dụng hàm sprintf với chuỗi lệnh thực thi nhưng không kiểm tra xác thực và độ dài.
– Đoạn code dưới đây là đoạn code bị lỗi khi “file_name_0” có độ dài tối đa 0x110 (là dữ liệu người dùng gửi tới chức năng qua thẻ <FNAME></FNAME>) được sprintf vào câu lệnh điều khiển tại biến “v25” có độ dài tối đa là 0xc8, lỗi tràn bộ đệm xảy ra và có thể chiếm được con trỏ lệnh, trước đó câu lệnh tại “v25” được thực thi cho phép thực hiện lỗi command injection.
Trong chức năng UPLOAD:
Cũng tương tự lỗi trên tại hàm sub_9B5C được thực thi trong chức năng “UPLOAD”:
– Đoạn code dưới đây sprintf dữ liệu được gửi đến vào biến chứa lệnh ‘s’, sau đó thực thi, dẫn tới khả năng bị command injection.
– Biến ‘s’ có thể chứa tối đa 0xA0 bytes, hàm sprint sử dụng tham biến tag của hàm sub_9B5C lấy trực tiếp dữ liệu từ thẻ <LOCALNAME ></LOCALNAME> có độ dài tối đa 0x100 bytes dẫn đến overflow.
Tuy có thể khai thác bằng buffer overflow. Command injection vẫn là cách hay nhất để khai thác do không gây crash service. Chỉ cần gửi command theo format <UPLOAD><LOCALNAME> cmd </UPLOAD></LOCALNAME> tới port 1300 là có thể thực thi lệnh trên thiết bị.
Tạm kết
Trong quá trình thực hiện project mình còn làm một con camera khác (yoosee). Nội dung blog cũng khá lan man rồi nên mình tạm dùng bài viết này ở đây. Hẹn các bạn trong bài viết sau (maybe :>)