MindShaRE: Hardware Reversing with the TP-Link TL-WR841N Router - Part 2

December 02, 2019 | Vincent Lee

MindShaRE is our periodic look at various reverse engineering tips and tricks. The goal is to keep things small and discuss some everyday aspects of reversing. You can view previous entries in this series here.


In September 2019, we released a blog post on our adventure in setting up GDB debugging environment on the TP-Link TL-WR841N v14 router. We promised sharing a vulnerability found in the router and today is the day we talk about it! The bug is a classic buffer overflow vulnerability discovered by Nguyen Hoang Thach, a new submitter to the ZDI program. 

As of this blog’s publication, TP-Link has released firmware updates for the multiple regions to address this and other bugs. However, some regions, most notably the EU and Japan, may need to wait.

Here’s a video of the bug exploited to achieve arbitrary code execution on the device:

ZDI-19-992 is a buffer overflow vulnerability that affects the httpd web service. The attacker can trigger this vulnerability by sending a HTTP request with an overly long Host request header to the victim. The mechanics of the bug are straightforward. In the vulnerable function, http_parser_main(), it copies the Host request header into a 512-byte global buffer with strncpy() in a common, vulnerable code pattern[1]:

When the attacker_controlled_buffer variable contains a string longer than vulnerable_buffer, it will cause a buffer overflow.

Below is a disassembly snippet of the http_parser_main() function taken from the httpd binary in firmware version 0.9.1 4.16 v007c.0 Build 180613 Rel.42415n.

Figure 1 - Disassembly of the vulnerable “http_parser_main()” function.

At 0x405F2C, the attacker controlled Host header buffer is passed into strlen() via register $a0 in the delay slot. The returned value of the strlen() is stored in the $v0 register and passed into the vulnerable cstr_strncpy() as the third argument at 0x405F40. The vulnerable cstr_strncpy() call at 0x405F4C causes the global buffer referenced in register $a0 to be overflown by attacker controlled data referenced in register$a1.

Exploitation

Since the vulnerable buffer does not reside on the stack, it is not possible to achieve code execution by overwriting the return address stored on stack. Luckily, the attacker can overflow the member pointers of a linked list Node structure that sits close to the vulnerable buffer. This structure is responsible for keeping track of request parameters and contain pointers to next and previous nodes:

Whenever the httpd service processes an HTTP request with parameters, the http_parser_argStrToList() function will be called. This function, goes through the following bit of code to unlink a node:

Figure 2 - A snippet of the disassembled “http_parser_argStrToList()” function.

As the attacker controls both the next and prev pointers, the attacker obtains a write-what-where primitive. In the exploit snippet below, the attacker sets up the cur and prev pointers to overwrite the atol() entry in the global offset table (GOT) with the shellcode address:

Figure 3 - A snippet of the exploit code for ZDI-19-992

The third HTTP request in the exploit triggers the function call to http_parser_argStrToList() and overwrites the GOT address by sending an HTTP request with parameters to the victim. A final HTTP request containing the shellcode is sent to the victim to trigger the call to atol() and achieve code execution. You can find the full exploit code here.

Conclusion

This concludes our reverse engineering with the TL-WR841N router blog post series. I hope this series has motived you to get your feet wet with bug hunting in routers. I look forward to seeing your hardware-related submissions in the future. Until then, you can find me on Twitter @TrendyTofu, and follow the team for the latest in exploit techniques and security patches.

---
Footnote

1 - Vulnerability modeling of this code pattern in router firmware could be an interesting exercise for the curious readers. My colleague Jasiel Spelman has written a fantastic blog on static program analysis.