Emulate D-Link DCS-932L Camera using QEMU

No device? No worries 🙂 

I. Requirements

https://shadow-file.blogspot.com/2013/05/running-debian-mips-linux-in-qemu.html

Important: When dealing with old debian system, many libs are missing because it is EOL, I recommend upgrade your system from squeeze/wheezy to newest (current here Debian 10 – buster)

II. Emulator

Our system will look like this:

Step 1 – Finding the ROOTFS Folder in the firmware

First come to the camera page: https://support.dlink.com/ProductInfo.aspx?m=DCS-932L

Download the latest firmware (REV-B_2.18.01_06/12/2019) to the Ubuntu:

Unzip it, we got the firmware bin

Now let’s using binwalk to extract the firmware bin:

As you see binwalk will do the rest job for us (most of time), it detects the header and extract the content corresponding, we got folder _DCS-932L_B1_v2.18.01.bin.extracted

Still too much bin, we need to binwalk again

binwalk –e 50040

And again:

binwalk –e 3AC000

Here it is, we found the rootfs folder

Step 2 – Finding the Architecture & Endianness

We can find those informations by using file command on random binary within the rootfs:

As we can see the firmware architecture is MIPS, the Endian is little => We run the QEMU MIPSEL Image.

Step 3 – Copy the rootfs folder to QEMU MIPSEL

I’m now in QEMU:

First, from Ubuntu, we need to compress the folder:

Then send it to the QEMU MIPSEL:

Now from the mipsel, uncompress it:

Step 4 – chroot the ROOTFS

If the result like the image above, you’ve successful emulated the firmware J But we also need to run its service, mostly web service.

Step 5 – Finding the service command/binary

In general, this step requires you to figure which/where, reading some config code, etc. In this case, the DCS-932L Camera web server is /bin/alphapd binary.

Step 6 – Troubleshoot the problem

When Emulating, you will always encounter many problems, try troubleshoot one by one via its error dump. We run the bin:

Cannot open pid file? Seems it looking for pid file somewhere, let drag the binary into Ghidra to see how it works, come to main():

Yeah, that’s why, let create this file to pass the check

“waiting for nvram_daemon”? We can see it here

Maybe we missing the nvramd.pid too, let create one:

Ok, now we come to the “always happens problem” when emulating: the NVRAM. Non-volatile random-access memory (NVRAM) is random-access memory that is non-volatile. By default, emulator doesn’t have nvram, we need to fake it.

Luckily, there are many nvram emulators available, one of them is: libnvram

https://github.com/firmadyne/libnvram

clone the repository to QEMU MIPSEL, the emulator is pretty old that we need to modify a bit, delete line 338 to 342:

then make it:

We now got libnvram.so! Copy it to our main ROOTFS

The libnvram requires put in appropriate folder, we need to create some:

Now try again, using LD_PRELOAD to load the shared object before any other library (including the C runtime, libc.so)

Then /bin/alphapd, it works!

But we got new problem:

Unable to write ‘random state’? It means The RANDFILE and HOME environment variables are not set. We create an empty .rnd file and set the environment variable:

Run again:

Another error. We come to IDA and find this string, SHIFT + F12 -> xref the string

We can see that it does something in getSysInfoLong, it will get ip from gpio device interface, we are in emulator so we don’t have this interface, we also don’t care, just patch to return the other branch. Using keypatch:

We jump directly to inet_ntoa path, this function will check if IP input is incorrect => return to 0.0.0.0, so our server IP will located at 0.0.0.0. Now replace the original with our new alphapd, give it execute permission, and re-run the service again:

Cool, we able to start the service, let access it

It works! But when we try to access any section, it requires Authentication

Try admin/admin, admin/, it won’t work, let see the log in MIPSEL console:

Its because the value in nvram are not here, the nvram emulator can’t get it.

We back to the repository https://github.com/firmadyne/libnvram, in config.h, it defines the default path, value will be set to nvram, now we will go around the firmware and find the nvram configuration file, then edit the config.h, then recompile the libnvram.so:

We take the record which is not start with # and got the key pair struct to config.h, for example Platform=RT5350 => ENTRY(“Platform”, nvram_set, “RT5350”)

To login, we much fill two key:

ENTRY(“AdminID”, nvram_set, “admin”)

ENTRY(“AdminPassword”, nvram_set, “tsu123”)

Then we recompile the libnvram as above (remember to delete the nvram.o & libnvram.so in the folder first)

Put it in appropriate folder:

Run the service again:

Thanks @chung96vn for supporting.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s