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
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
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.
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
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:
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
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