Bug Type

Command Injection

Target

attack vector

Host (Domain) at the syscmd.htm endpoint of the administrator page: command inspection is possible where input is made.

image.png

function saveClick() {
    var hostObj = document.formSysCmd.sysHost;
    var cmd = document.formSysCmd.sysCmd.value;
    if (cmd == "ping" || cmd == "traceroute") {
        if (hostObj.value == "") {
            alert(syscmd_host + syscmd_empty_alert);
            hostObj.value = hostObj.defaultValue;
            hostObj.focus();
            return false;
        }
    }
    return true;
}

In the syscmd.htm file, the saveClick() function checks whether cmd == "ping" or cmd == "traceroute". It then retrieves the value entered by the user using var hostObj = document.formSysCmd.sysHost; and stores it in hostObj.

<form action="/boafrm/formSysCmd" method="POST" name="formSysCmd">

The formSysCmd.sysHost value is then sent to /boafrm/formSysCmd because of the <form> tag in the HTML.

The formSysCmd processing code is present in the /bin/boa file of the firmware on tew831dr.

int __fastcall sysform(_DWORD *a1) {
    int v2; // $s5
    _BYTE *v3; // $s4
    int v4; // $v0
    const char *syshost_input_save; // $s1
    int v6; // $v0
    int v7; // $s2
    int v8; // $s6
    int *v9; // $s6
    int i; // $s3
    _DWORD *v11; // $a0
    int v12; // $s3
    int v13; // $v0
    _BYTE v15[24]; // [sp+28h] [-218h] BYREF
    _BYTE cmd_input_save[256]; // [sp+40h] [-200h] BYREF
    char syshost_input_save_buf[256]; // [sp+140h] [-100h] BYREF

    memcpy(v15, off_45C178, sizeof(v15));
    memset(syshost_input_save_buf, 0, sizeof(syshost_input_save_buf));
    v2 = syshost_input(a1, (int)"submit-url", (int)"");
    v3 = (_BYTE *)syshost_input(a1, (int)"sysCmd", (int)"");
    syshost_input_save = (const char *)syshost_input(a1, (int)"sysHost", (int)"");
    v4 = syshost_input(a1, (int)"checkNum", (int)"4");
    v7 = atoi(v4);
    v6 = syshost_input(a1, (int)"sysMagic", (int)"");
    if (!v7) {
        v7 = 4;
    }
    v8 = v6;
    if (!*v3) {
LABEL_19:
        v11 = a1;
        return sub_40AE5C(v11, v2);
    }
    if (strcmp(v3, "telnetd")) {
        v9 = (int *)v15;
        for (i = 0;; ++i) {
            v13 = *v9;
            v9 += 2;
            if (!v13) {
                break;
            }
            if (!strcmp(v3, v13)) {
                if (!*syshost_input_save) {
                    goto LABEL_19;
                }
                if (!strchr(syshost_input_save, 59) ||
                    sub_44856C(0, syshost_input_save, 59, syshost_input_save_buf, 256) == -1) {
                    printf("\\n%s[%d] sysHost = %s\\n", "fmmgmt.c", 4656, syshost_input_save);
                    strncpy(syshost_input_save_buf, syshost_input_save, 256);
                    v12 = 8 * i;
                } else {
                    printf("\\n%s[%d] sysHost = %s, entry = %s\\n", "fmmgmt.c", 4651, syshost_input_save, syshost_input_save_buf);
                    v12 = 8 * i;
                }
                snprintf(cmd_input_save, 256, "%s %d %s 2>&1 > %s", *(const char **)&v15[v12 + 4], v7,
                         syshost_input_save_buf, "/tmp/syscmd.log");
                goto LABEL_17;
            }
        }
        goto LABEL_19;
    }
    if (!strcmp(v8, "535A5943")) {
        snprintf(cmd_input_save, 100, "telnetd & 2>&1 > %s", "/tmp/syscmd.log");
    LABEL_17:
        cmd_run(cmd_input_save);
        v11 = a1;
    } else {
        v11 = a1;
    }
    return sub_40AE5C(v11, v2);
}

In the sysform function:

syshost_input_save = (const char *)syshost_input(a1, (int)"sysHost", (int)"");

This part retrieves the input value, which is the command entered by the user. For example, if the user enters 127.0.0.1 | cat /etc/passwd, the value is stored in syshost_input_save. Then:

strncpy(syshost_input_save_buf, syshost_input_save, 256);

This code constructs a command string using snprintf and stores it in cmd_input_save. For example: