The following exploit works against both the admin portal on port 11115 as well as the user portal on port 443. Since the admin portal might be in a different VLAN, I’m going to demonstrate how to leak memory contents by (ab)using the user portal this time.
Requirements for Successful Exploitation
To exploit this memory disclosure vulnerability, you need to be able to establish an authenticated session with the device (aka, you need credentials). It is totally sufficient to have a low-privileged account on the user portal. The previously important User-Agent and REMOTE_ADDR requirements are not relevant for this exploit to work.
The sessionId must have never been used before – so only the authentication request and nothing further must have happened with it. If the
sessionId has been used in any other authenticated request, the exploit won’t work anymore. This turns this bug into an authenticated vulnerability since if you authenticate using a browser, the
sessionId is immediately “used” after the login command in different JSON requests.
Leaking Memory Contents
As initially mentioned, the requirement to be successful is an active but unused session on any of the two available portals, i.e. on the user portal:
While fuzzing around the format of the HTTP request, I noticed that any request subsequent to the authentication request (even an empty one) returns some seemingly unreadable content in the
Considering that most parts of the UTM are written in C/C++ (Fast-CGI), this immediately rang a lot of alarm bells on my side. When having a look into the hex view of the contents, you could notice that this unreadable string translates to the hex value of 0x556efbf5aba0.
Doesn’t this look like a memory address? When attaching IDA Pro to the relevant process on the device, you can see that it roughly matches the address range of the remote process around the
Cool. This by itself means that we have an information leak here that could be useful in terms of i.e. ASLR bypasses. Let’s see what else we could leak using BurpSuite’s intruder:
Yay. Environment variables.
I was quite interested in finding the root cause for this bug, and since I love Reverse Engineering and almost all of the UTM is written in C/C++, I decided to bindiff the patched version of the UTM (v188.8.131.52) with the vulnerable version (v12.2.5), and it turns out that we’re dealing with an uninitialized variable here.
The fixed version (on the right) introduced a call to
_sp_io_set_sessionid() with its argument set to 0 quite early in the call hierarchy of the spcig.cgi process:
When having a look at
sp_io_set_sessionid(), you quickly see that all it does is set a fixed variable to the value of its argument:
This variable is later used in the
json_send_response() method responsible for returning the JSON object:
So it appears that
json_send_response() was initially referencing an uninitialized variable, which led to the leak of random memory contents.
Good catch 🙂
I’ve responsibly coordinated both vulnerabilities with the vendor SecurePoint and notified them about both issues on 5th January 2023. They did an amazing job acknowledging the vulnerability and providing a fix within a single business day. I barely see (hardware) vendors reacting so fast. Well done!