# CVE-2023-46012

## LINKSYS AC1900 EA7500v3 IGD UPnP Stack Buffer Overflow Remote Code Execution Vulnerability

This vulnerability allows network-adjacent attackers to execute arbitrary code on affected installations of LINKSYS EA7500 routers. Authentication is not required to exploit this vulnerability. 

The specific flaw exists within the handling of HTTP request data to the IGD UPnP service. When parsing the contents of a user-supplied variable of a given SOAP UPnP Action Request, the process does not 
properly validate the length of user-supplied data prior to copying it to a fixed-length stack buffer. An attacker can leverage this vulnerability to execute code in the context of root.

**Product/Firmware: Linksys EA7500 Firmware ALL VERSIONS including Ver. - Other router models and firmware versions using this binary are also affected**

### Root Cause Analysis

The UPnP IGD service binary is located at `/usr/sbin/IGD` and is running by default on port 49152. This service provides the `IGDdevicedesc.xml` UPnP XML description file that details several functions that can be invoked using HTTP requests with an XML body. 
One of these functions is SetDefaultConnectionService. This function requires one variable of type string. When the SetDefaultConnectionService function is invoked and executed, the program does not validate the length of the user-supplied variable prior to 
performing a strncpy call involving this buffer. Both the source address and copy size variables of the strncpy call are user-controlled, with the copy size being the length of the user-supplied variable. 
The data is then copied to a fixed buffer of 184 bytes, leading to a stack buffer overflow vulnerability. 

### Code Flow

The function SetDefaultConnectionService is labeled as _set_connection_type. The function begins by initializing a 184-byte buffer and then obtains a pointer to the buffer holding the user-supplied string variable included in the request if it is not NULL.
This is done by calling PAL_xml_node_GetFirstbyName and then PAL_xml_node_get_value. See code below:

int _set_connection_type(int **param_1)

  int iVar1;
  char *var_value;
  size_t var_value_length;
  undefined uVar2;
  undefined1 *puVar3;
  char **ppcVar4;
  undefined4 *puVar5;
  char *pcVar6;
  int *piVar7;
  char acStack_d4 [184]; -----> /* Initializing 184-byte buffer */
  iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 now points to the user-supplied value */
  if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Ensures the user-supplied value is not empty and obtains a pointer to it */

### Injection Point

Later in the same function, a strlen call is performed to obtain the size of the user-supplied string plus a static offset of 0x174. The vulnerable condition is triggered in the 
subsequent strncpy call where the destination argument is the address of the newly initialized 184-byte buffer, the source is the pointer to the user-supplied string, and the size of the copy operation is 
the size of the user-supplied string  returned by the call to strlen plus a static offset of 0x174. 
This leads to a buffer overflow vulnerability as both the source address and size variables are controlled by the user and no size validation checks are performed. 
See code below:

int _set_connection_type(int **param_1)


      var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 is a pointer to the user supplied string */
      strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Vulnerable strncpy call */

The offset to overwriting a function return address on the stack is 276 bytes. The next 4 bytes can be utilized to redirect execution to an arbitrary address and thus hijack the control flow of the program. 

### Suggested Fixes

1. Use a safer string copy function: Instead of using strncpy, which does not guarantee null-termination of the destination buffer, a safer string copy function can be used like strncpy_s or memcpy_s. These functions ensure that the destination buffer is always null-terminated and do not allow the copying of more data than the buffer can hold.

2. Input validation: Validate user input to ensure that it does not exceed the size of the destination buffer. If the input is longer than the buffer size, either reject it or truncate it to fit within the buffer.

3. Use a dynamically allocated buffer: Allocate memory for the destination buffer dynamically instead of using a fixed-size stack buffer. This approach allows the buffer size to be adjusted according to the input data size. (Not recommended for a system with limited resources)

PoC Execution: `python 49152`

Software Download Link: []( (Firmware version Ver.

### Notes for Debugging

- The router has a UART interface that can be used to obtain a root shell. Credentials for root access are root:admin. 
- The testing device that was used during this engagement is EA7500 R75. This device has a UART interface with the Rx pin disabled. 
    - To connect the Rx line, a bent paperclip was used to connect the Rx pin to a line on the PCB making it possible to login to the device. 
- With a root shell on the box, drop a statically-compiled gdb-server (I used the prebuilt binary `gdbserver-7.7.1-armel-eabi5-v1-sysv` available here: 
- Use `pkill IGD` to terminate the binary and then relaunch it using `./gdbserver :1337 /usr/sbin/IGD`. The following .gdbinit file can be used to initiate a stable debugging session:
 > set follow-fork-mode child
 > set detach-on-fork off
 > target remote
 > c

### Additional Links