IoT vulnerabilities research series – Virtualizing devices with QEMU

1. Introduction

In the previous article, we have mentioned that IoT devices such as Router, Access Point, and IP Camera can be compromised and turned into botnets. There are several existing hacking techniques could help attackers implement this kind of attack, and exploiting vulnerabilities enduring in IoT devices is one of them. This research series aims to provide readers with in-depth knowledge and objective perception of different IoT vulnerabilities that hackers can exploit.

In this article, we would like to introduce about QEMU, which stands for Quick EMUlator, can perform hardware virtualization. Using QEMU, researchers can set up virtual environments simulating Router, Access Point and IP Camera to facilitate vulnerability research processes. Studies carried out with QEMU can help security researchers explore unrevealed vulnerabilities hiding inside devices so that manufacturers can patch them.

Why should we use virtual devices instead of real devices?

There are several advantages, namely, cost & time effectiveness and user-friendliness that virtual devices possess when comparing to real physical ones:

  • Cost-saving: There is no need to spend a significant amount of money purchasing expensive devices when utilizing virtual devices.
  • Time-saving: It is incontrovertible that installing virtual devices takes much less time than ordering, shipping, and installing physical devices.
  • User friendly: It is easier for us to work in virtual machines than in physical ones.

However, we can meet some struggles when working with virtual devices because some are not comprehensively similar to physical devices, and some are hard or impossible to be implemented in simulative environments.

2. Virtualizing processes

Environment setup

In this experiment, we are going to use the tools listed below:

For the Linux virtual machine, we recommend using Ubuntu Server 16.04. Please note that you must select the option “Enable hypervisor application in this virtual machine” when configuring the Linux virtual machine. Below are some minimum required specifications for the Linux machine:

  • MEMORY: >= 1GB
  • CORES: >= 2
  • HARD DISK: >= 30GB
Figure 1 – Virtual machine specs

After successfully installing the Linux machine, download the setting script setup.sh and run.

Virtualizing experiment

In this part, an actual experiment is demonstrated so that readers can have a better insight into how all the virtualizing processes take place. We select Router DIR-882 manufactured by D-Link in this experiment since it contains quite comprehensively enough information and requirements to generate virtualizing.

First of all, go to https://support.dlink.com/ProductInfo.aspx?m=DIR-882-US and then download the Firmware of the router.

Step 1: Find the device’s rootfs

After downloading the firmware, we need to perform firmware extracting to obtain rootfs. However, this process’s details are beyond this article’s scope, so they are not presented here. You can find the instruction on implementing this step in this ZDI’s blog post.

Step 2: Examine the device’s architecture

After extracting the device’s rootfs, we need to know the router’s architecture to virtualize it by QEMU. We can run the command $ file rootfs/bin/busybox to obtain this piece of information.

Figure 2 – Obtain architecture information

It is shown in the result that this device uses mipsel architecture (Little-endian), and we need a machine that has the capability of analyzing this architecture. In this experiment, we will utilize a pre-built mipsel virtual machine to facilitate the process. To ease the installation of the mipsel virtual machine, we have prepared a setup script named emumipsel.sh that you can find at this link.

Figure 3 – Running emulator.sh

After installing the mipsel virtual machine, you can log in with the username/password combination root/root.

Step 3: Get rootfs into the QEMU virtual device

It was in step 2 that we succeeded in obtaining rootfs, and now we will copy that into QEMU.

Zip all the rootfs data:

  • $ tar -czvf rootfs.tar.gz rootfs/

Use scp in the Linux machine to copy the created tar file:

Unzip the tar file:

  • $ tar -xvf rootfs.tar.gz

Step 4: Virtualize nvram

NOTE: It is unnecessary to apply this step to virtualize devices that do not encompass nvram.

On exploring the router DIR-882, we recognized the appearance of nvram; however, QEMU does not support the virtualization of nvram, so we must employ another tool to perform this action.

Figure 4 – nvram appears in the router

Wandering around the Internet, we figured out a pretty excellent tool called libnvram that could support virtualizing NVRAM in this case. To build a libnvram, we need to use a cross compiler; therefore, if you do not have a cross compiler in your machine, please download a suitable one following this link:

After building a libnvram, you can use the command scp to copy it to the QEMU virtual machine.

Step 5: Configure the QEMU virtual machine

Before proceeding, we must consider the below points:

  • The simulating router will use virtual hardware devices provided by QEMU, so mounting or unmounting those devices can cause an operating problem.
  • The router will utilize the QEMU virtual machine’s network adapter directly, so there stands a chance that the router’s configurations damage the connection between the QEMU machine (guest) and the Linux machine (host).

We must alter some startup configurations of the router so that its operation will not negatively affect the QEMU machine’s functions. 

When reading content inside the file inittab, we saw that the file /etc_ro/rcS is started when the device is on boot, which proves that /etc_ro/rcS is the startup file of the router.

Figure 5 – Finding the startup file

On examining rcS and other files called by rcS, we recognized that the script file makedevlinks.sh was called to execute mount and mknod. We commented out the line of code in rcS that called makedevlinks.sh so that it would not affect the QEMU machine when booting.

Figure 6 – Content of rcS

Step 6: Start visualizing

First, we need to mount some resources so that they can be shared between the QEMU virtual machine and the router.

  • mount -o bind /proc rootfs/proc/
  • mount -o bind /dev rootfs/dev
  • mount -o bind /sys rootfs/sys

In the next step, we move the libvram instance to the rootfs folder and configure it:

  • mv path/libnvram.so rootfs/libnvram.so
  • mkdir rootfs/firmadyne

Perform virtualizing by chroot command:

  • chroot rootfs /bin/sh

Inside the chroot environment, run below commands:

  • export LD_PRELOAD=/libnvram.so
  • /etc_ro/rcS

Wait until the command finishes running.

Figure 7 – Result of the virtualizing process

Step 7: Fix errors (if exist)

Problem: lighttpd service does not appear when checking the system.

Figure 8 – Services running during the virtualizing process (lighttpd does not exist)

By examining events happening after /etc_ro/rcS was executed, we found out that lighttpd should have been started by /bin/init_system, but there was a problem with this process.

Figure 9 – lighttpd is started by init_system

By reverse engineering the file init_system,we figured out that the problem lied in the fact that /var/run/nvramd.pid did not exist in the system.

Figure 10 – Reverse engineer init_system

We tried to run the command executed in init_system to see if the problem could be solved:

  • lighttpd -f /etc_ro/lighttpd/lighttpd.conf -m /etc_ro/lighttpd/lib
Figure 11 – Result of running the command

After running the command, we still saw an error that might have been caused by lighttpd itself. We tried to comment out all lines in the file /etc_ro/lighttpd/lighttpd.conf to see if the error still occurred.

Figure 12 – Comment lines in /etc_ro/lighttpd/lighttpd.conf

After doing that, we finally succeeded in starting lighttpd.

Figure 13 – Successfully start lighttpd
Figure 14 – Website served by lighttpd server

Even though the simulating router could not provide all the features like a real device, we could still take advantage of it to debug lighttpd or other services running on the device.

This writing is quite long up to this point; therefore, we hope that in the future, we can present to you the detailed procedure of setting up an environment for debugging.

3. Conclusion

In essence, creating a virtual device by QEMU is not too hard. However, this process requires the implementers to be knowledgeable about different aspects and carefully understand the machine they want to virtualize. The first attempt of virtualizing a device will cost you time and effort, but you will be familiar with this task when performing it more often.

In the future, we will deliver to you more writings on this topic and other exciting issues. Thank you so much for spending your time with us. Please share and comment if you find this post beneficial.

Credit: @chung96vn

Nghiên cứu lỗ hổng bảo mật trên thiết bị IoT – Ảo hóa thiết bị bằng QEMU

Mở đầu

Xin chào, chúng tôi lại quay trở lại rồi đây.

Trong bài viết trước của nhóm, có lẽ nhiều bạn đọc vẫn còn thắc mắc là tại sao một thiết bị Router, Access Point, Camera IP lại có thể bị thỏa hiệp và biến thành một máy trạm trong một hệ thống Botnet. Có thể bài viết này và một số bài viết sau của chúng tôi sẽ giúp bạn đọc có cái nhìn khách quan hơn về lỗ hổng bảo mật trong các thiết bị IoT, đó là một trong những nguyên nhân chính dẫn đến việc các thiết bị IoT bị tấn công và trở thành một phần của mạng Botnet.

Trong bài viết dưới đây, mình sẽ chia sẻ về kỹ thuật sử dụng QEMU trong việc ảo hóa các thiết bị Router, Access Point, Camera IP nhằm đơn giản hóa quá trình nghiên cứu. Qua đó giúp quá trình tìm kiếm, phát hiện các lỗ hổng bảo mật trở nên đơn giản và hiệu quả hơn.

Những nghiên cứu này nhằm mục đích tìm và phát hiện các lỗ hổng bảo mật trên các nhóm thiết bị nêu trên, qua đó giúp cho nhà cung cấp có thể sửa đổi, khắc phục để nâng cao chất lượng cũng như đảm bảo an toàn thông tin cho người dùng.

Tại sao tôi lại chọn ảo hóa thiết bị mà không phải là nghiên cứu trên các thiết bị thật?

Với những dòng thiết bị tôi đang nghiên cứu thông thường có giá bán trên thị trường cao hoặc không tìm mua được ở Việt Nam mà phải đặt mua ở nước ngoài về, đó chính là những rào cản trong việc sở hữu một thiết bị thật để nghiên cứu. Chính vì thế tôi chọn việc ảo hóa thiết bị để có thể thực hiện được công việc của mình, và đây là những ưu điểm mà tôi thấy được từ việc sử dụng ảo hóa:

  • Tiết kiệm chi phí nghiên cứu
  • Tiết kiệm thời gian không phải chờ mua thiết bị
  • Tương tác với môi trường ảo hóa dễ dàng hơn tương tác với thiết bị thật

Ngoài ra ảo hóa cũng có những nhược điểm nhất định như sau:

  • Không giống hoàn toàn thiết bị thực tế
  • Một số thiết bị khó ảo hóa và tốn nhiều thời gian để thực hiện hoặc không thể thực hiện được ảo hóa

Ảo hóa thiết bị

Cài đặt môi trường?

Ở đây tôi sử dụng những công cụ sau:

  • Một máy ảo linux (nên dùng ubuntu server)
  • QEMU
  • binwalk
  • squashfs-tools
  • jefferson
  • pwndbg
  • gdb-multiarch

Đầu tiên cần phải cài một máy ảo linux, ở đây tôi khuyến khích mọi người sử dụng ubuntu server 16.04.

Lưu ý đối với cấu hình máy ảo cần được tích chọn “Enable hypervisor application in this virtual machine”.

Yêu cầu cấu hình máy ảo:

  • MEMORY: >= 1GB
  • CORES: >= 2
  • HARD DISK: >= 30GB
Cấu hình được dùng cho máy ảo linux

Sau khi cài đặt thành công máy ảo, download file cài đặt setup.sh và khởi chạy.

Ảo hóa thiết bị như nào?

Trong phần này tôi sẽ làm một ví dụ cụ thể để mọi người có cái nhìn cụ thể hơn về hướng mà tôi đã làm để có thể ảo hóa thiết bị. Ở đây tôi chọn Router DIR-882 của nhà cung cấp D-Link bởi tôi thấy nó có đầy đủ các thông tin cũng như các bước cần thiết để có thể thực hiện được ảo hóa đối với nhiều thiết bị khác.

Việc đầu tiên cần làm là tải về firmware của thiết bị đó về.

Bước 1: Phân tích tìm rootfs của thiết bị

Sau đó thực hiện extract firmware vừa tải được để lấy được rootfs của thiết bị. Tôi xin phép không nói cụ thể về việc này bởi việc này đã được hướng dẫn trong một blog của ZDI từ những kỹ thuật mà tôi đã đính kèm trong những báo cáo lỗ hổng bảo mật. Mọi người có thể tham khảo thêm thông tin tại blog của zdi.

Bước 2: Xác định kiến trúc của thiết bị

Sau khi có được rootfs của thiết bị, cần kiểm tra xem thiết bị sử dụng kiến trúc nào? Thông thường tôi thực hiện chạy lệnh $ file rootfs/bin/busybox để xem xem file này thuộc kiến trúc nào.

Có thể thấy thiết bị sử dụng kiến trúc mipsel (little endian)

Sau khi biết được thiết bị sử dụng kiến trúc gì, ta cần chạy một máy ảo chạy kiến trúc đó bằng QEMU. Ở đây tôi sử dụng một máy ảo mipsel được build sẵn và chia sẻ ở trên mạng.

Mình có viết một script hỗ trợ việc chạy máy ảo mipsel, mọi người có thể tải file cài đặt emumipsel.sh về và chạy chúng.

Lần đầu chạy file emumipsel.sh

Sau khi máy ảo QEMU đã chạy thành công, mọi người có thể thực hiện đăng nhập với username/password là root/root.

Bước 3: Đưa rootfs vào trong máy ảo QEMU

Ở bước 1 chúng ta đã có được rootfs của thiết bị này. Ở bước này chúng ta thực hiện đưa toàn bộ file trong này lên máy ảo QEMU.

Đầu tiên nén rootfs thành một tập tin bằng câu lệnh sau:

  • tar -czvf rootfs.tar.gz rootfs/

Sử dụng scp trong máy ảo QEMU để đưa rootfs vào trong máy ảo QEMU:

Giải nén tập tin tại máy ảo QEMU bằng câu lệnh sau:

  • tar -xvf rootfs.tar.gz

Bước 4: Ảo hóa nvram

Lưu ý: Với những thiết bị không sử dụng nvram thì không cần làm bước này.

Nhận thấy thiết bị có sử dụng nvram tuy nhiên máy ảo QEMU không hỗ trợ nvram, chính vì thế cần phải có một công cụ giúp hỗ trợ ảo hóa nvram cho trường hợp này. Sau khi tìm kiếm trên mạng và phát hiện được một công vụ giúp hỗ trợ ảo hóa nvram khá ổn là libnvram của firmadyne.

Thiết bị có sử dụng nvram

Để tạo được một libnvram ta cần phải sử dụng cross compiler để có thể build được một libnvram với kiến trúc mipsel để sử dụng được bên trong máy ảo QEMU. Các bạn có thể tải về cross compiler phù hợp từ đường dẫn sau:

Sau khi build được libnvram thì đưa chúng vào trong máy ảo QEMU bằng câu lệnh scp.

Bước 5: Chỉnh sửa cấu hình để chạy ảo hóa.

Ở bước này chúng ta cần phải chỉnh sửa một số nội dung các file khởi chạy ban đầu để phù hợp với điều kiện chạy trong máy ảo. Cần có một số chú ý như sau:

  • Thiết bị sẽ sử dụng các device có sẵn của máy ảo QEMU và việc mount hay unmount các device khác là không phù hợp và có thể không tương thích dẫn đến máy ảo bị crash và dừng lại.
  • Thiết bị sử dụng card mạng của máy ảo QEMU, chính vì thế các cấu hình mạng mặc định của thiết bị có thể làm hỏng cấu hình mạng của máy chủ dẫn đến việc kết nối từ máy ảo QEMU (guest) đến máy ảo linux (host) bị hỏng.

Từ những lưu ý trên, chúng ta cần phải sửa những câu lệnh có ảnh hưởng đến các device hoặc các cấu hình liên quan đến card mạng. Trước tiên cần tìm được file khởi chạy ban đầu của thiết bị, đọc nội dung trong file inittab cho thấy file /etc_ro/rcS được khởi chạy ngay sau khi thiết bị được bật.

Cấu hình khởi động của thiết bị

Đọc nội dung của file rcS và các file được rcS gọi tới chúng tôi phát hiện tập tin makedevlinks.sh trong đó có chạy các lênh mount, mknod. Để không ảnh hưởng đến máy ảo QEMU trong quá trình chạy ảo hóa thiết bị, tôi đã thực hiện comment dòng lệnh này.

Nội dung file khởi động của thiết bị

Bước 6: Bắt đầu chạy ảo hóa

Việc đầu tiên cần làm là thực hiện chia sẻ tài nguyên giữa máy ảo QEMU với thiết bị sẽ được ảo hóa bằng các lệnh mount:

  • mount -o bind /proc rootfs/proc/
  • mount -o bind /dev rootfs/dev
  • mount -o bind /sys rootfs/sys

Sau đó thực hiện đưa libnvram vào thư mục rootfs và cấu hình ảo hóa nvram:

  • mv path/libnvram.so rootfs/libnvram.so
  • mkdir rootfs/firmadyne

Thực hiện ảo hóa bằng câu lệnh chroot:

  • chroot rootfs /bin/sh

Bên trong môi trường chroot thực hiện chạy những câu lệnh sau:

  • export LD_PRELOAD=/libnvram.so
  • /etc_ro/rcS

Chờ câu lệnh chạy xong và xem các kết quả hiển thị ra để xác định các lỗi có thể gặp phải.

Kết quả chạy ảo hóa thiết bị

Bước 7: Fix các lỗi gặp phải khi chạy (nếu có)

Kiểm tra các tiến trình đã được chạy của thiết bị ảo hóa thì không thấy có dịch vụ lighttpd (dịch vụ web service).

Các tiến trình được chạy bởi ảo hóa thiết bị

Tìm kiếm dựa vào những gì hiển thị sau khi chạy /etc_ro/rcS tôi tìm được dịch vụ lighttpd được chạy bởi /bin/init_system

lighttpd được chạy bởi init_system

Thực hiện dịch ngược file init_system tôi tìm được nguyên nhân dẫn đến lighttpd không được chạy là do file /var/run/nvramd.pid không tồn tại trong hệ thống.

Dịch ngược file init_system

Sau khi dịch ngược tập tin init_system tôi thấy để chạy được lighttpd chỉ cần chạy câu lệnh được sử dụng trong file: lighttpd -f /etc_ro/lighttpd/lighttpd.conf -m /etc_ro/lighttpd/lib

Chạy lighttpd

Thực hiện chạy câu lệnh trên và xem kết quả nhận được, có thể thấy lỗi xảy ra do một số cấu hình của lighttpd chưa được đẩy đủ. Để khắc phục vấn đề này, tôi thực hiện comment hết những dòng không cần thiết trong file /etc_ro/lighttpd/lighttpd.conf để có thể khởi chạy được lighttpd.

Những nội dung cần comment lại
lighttpd server đã được chạy thành công
Truy cập vào web page

Có thể thấy dịch vụ lighttpd đã chạy thành công tuy nhiên không hoàn chỉnh được như một thiết bị thật. Dẫu vậy ta vẫn có thể sử dụng phiên bản emulator này để debug dịch vụ lighttpd hoặc các dịch vụ khác đang được chạy trên thiết bị.

Do bài viết đã dài nên tôi xin phép không chia sẻ thêm về cách cài đặt để có thể debug được ứng dụng mà sẽ nói trong bài viết tiếp theo.

Kết Luận

Như vậy có thể thấy được để ảo hóa một thiết bị bằng QEMU không quá khó, tuy nhiên nó đòi hỏi nhiều kiến thức cũng như am hiểu về các thiết bị mà mình muốn ảo hóa. Thông thường lần đầu tiên thực hiện sẽ tốn nhiều thời gian còn những lần tiếp theo sẽ tốn ít thời gian hơn.

Chúng tôi sẽ còn chia sẻ thêm nhiều những bài viết, những chia sẻ về kỹ thuật hữu ích đến các bạn trong thời gian sắp tới. Trong bài viết tiếp theo có thể tôi sẽ chia sẻ cách để debug dịch vụ lighttpd được chạy trên thiết bị DIR-882 được sử dụng trong ví dụ trên.

Xin cảm ơn các bạn đã dành thời gian để đọc. Hãy chia sẻ nếu thấy hay và để lại những bình luận góp ý phía bên dưới nhé!

Credit: @chung96vn