We continue to analyze vulnerabilities of industrial switches: we execute arbitrary code without a password

In Positive Research 2019, we reviewed the Moxa Industrial Switch Management Protocol. This time, we will continue this topic and analyze in detail the vulnerability CVE-2018-10731 in the Phoenix Contact switches of the FL SWITCH 3xxx, FL SWITCH 4xxx, and FL SWITCH 48xx models identified by our experts. This vulnerability, detected in the device’s web interface, allows arbitrary code to be executed without knowledge of the device’s credentials and is rated 9 out of 10 points on the CVSS version 3 scale.

First look

The devices mentioned above are running Linux, and you can use the web interface to configure them. As with many other IoT devices, domestic and industrial, the web interface consists of many CGI applications that process user HTTP requests. In our case, CGI applications actively use the cgic library, which makes it easier to work with HTTP requests, and the functions of this library are built into the shared library libipinfusionweb.solocated in the file system of the device.

When processing an HTTP request, the web server passes the user request data to the CGI application as a set of environment variables. Their initial processing is performed by the function main libraries libipinfusionweb. Next function main calls a function cgiMain CGI-applications, in which further processing of the request occurs.

Figure 1. Processing an HTTP request

In the course of their work, the main function of the library libipinfusionweb calls a function get_login_userwhich, based on the passed cookie values, determines whether the user has authenticated with the system.

Figure 2. A fragment of the main function pseudo-code

Function get_login_user gets cookie value c_session using function cookies_get_value and saves it to a variable local_e0. The variable itself local_e0 represents an array of single-byte characters 0x80 long and is located at a distance 0xE0 from the beginning of the stack.

Figure 3. Pseudo-code snippet of get_login_user function

However, in the function code cookies_get_value it can be seen that obtained using the function cgiCookieString Cookie parameter has a maximum length of 0x400 bytes.

Figure 4. A fragment of the pseudo-code of the cookies_get_value function

Thus, when passing a Cookie parameter longer than 0xE0 (224) characters, the function get_login_user saves the value of this parameter to its stack, as a result of which all the information on the stack behind the variable local_e0will be overwritten, including the function return address.

Note: When one function calls another, the return address is stored on the stack. Control is transferred to this address when the called function finishes its work. Accordingly, if you rewrite this address, you can gain control over the program execution process. For example, an attacker can replace this address with the address of a malicious shellcode located in the address space of the program.

Note that the rewrite of the return address occurs before authentication is verified, which makes it possible to exploit this vulnerability to an attacker who does not know the credentials of the device.

Exploitation

We considered several options for demonstrating the possibility of exploiting this vulnerability. The simplest thing is to write the payload code onto the stack (0x400 – 0xE0 = 800 bytes remains for it, it’s enough for the code) and rewrite the return address with the code address. Theoretically, this option was possible, since the processor of the vulnerable switch does not support the NX-bit function (that is, it allows the execution of code located anywhere, including on the stack), but in practice it had serious limitations.

The vulnerable switch processor has an MIPS architecture; many of the processor instructions in this architecture are encoded in byte sequences containing zero bytes. The buffer contents are written down to the first zero byte (due to the use of the function strcpy), therefore, it is only necessary to use operands that do not contain a null byte, which is impossible, since any payload would use at least several of these bytes.

During construction ROP chains again, I would have to deal with the limitations of the null byte: the address of the ROP gadgets should not contain zeros, which greatly complicates their search. By and large, we could only use one zero, copied by the strcpy function. This imposes a limitation on the creation of a full-fledged ROP chain, and in addition to this, the gadgets we needed were extremely few. However, during searches in the libipinfusionweb library, the following code fragment was found:

Figure 5. Snippet of libipinfusionweb library executable code

Provided that the contents of the register $ s0 are controlled, this code fragment allows you to execute the OS command using the function mysystem (initially this function did not have a name, but we renamed it, since it is very similar to the system function in Linux in many ways).

Since we are rewriting the return address from the get_login_user function, this function will be executed to the end. In the epilogue of the get_login_user function, you can see that the value of the register $ s0 is restored from the previously saved value on the stack (at offset 0xD8 from the top of the stack). However, at this point, this area of ​​the stack is already under our control, that is, in fact, we can achieve control over the contents of the register $ s0 and thus execute arbitrary OS commands using the function mysystem.

Figure 6. Snippet of executable code of get_login_user function

Thus, in order to successfully demonstrate the exploitation of this vulnerability, we need to send as a parameter Cookie c_session a long line containing:

  • OS string command, which will be subsequently passed to the mysystem function;
  • the address of this command on the stack;
  • new return address (address of the code fragment shown in Fig. 5).

The final payload should look like this:

Figure 7. Payload

At this point, we already had a shell on the device obtained using a vulnerability, for the operation of which we needed administrator rights. Therefore, we were able to obtain additional information that helped us to operate:

  • ASLR on the device under study was disabled – therefore, the addresses of the gadget used and the OS commands will always be the same.

Figure 8. ASLR status on the device under investigation

  • The range of memory addresses in which the stack could lie. To calculate the exact address, we went over all the addresses in this range.

As a payload, we implemented the loading of a web shell, a CGI application with the following contents:

#!/bin/sh
eval $HTTP_CMD 2>&1

Since, according to the CGI protocol, the contents of the HTTP headers are passed to the CGI application in the form of environment variables with the names HTTP_<Имя заголовка>this shell with the command eval will execute the contents of the CMD HTTP header. The figure below shows the result of the successful operation and execution of the ls command using the loaded shell.

Figure 9. The result of the successful operation and execution of the ls command

Conclusion

We have demonstrated the ability to exploit this vulnerability. As we already mentioned, its operation does not require knowledge of the password; it can even be performed by an unauthenticated attacker.

Hacking an industrial network switch can lead to a compromise of the entire production. Violation of network interaction can adversely affect the process until it stops completely.

Information about the vulnerability and PoC were transmitted to the vendor, who released the corrected firmware version 1.34, and the identifier CVE-2018-10731 was assigned to the vulnerability itself.

Author: Vyacheslav Moskvin, Positive Technologies

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *