Having performed a thorough test on the web application, I was left empty-handed and felt frustrated. Fortunately, there are more services than just web applications running on standard ports. The results of the port scan discovered an unknown service labelled "gSOAP 2.8". A quick Google-search taught me that it was a C/C++ development toolkit by a company called Genivia, that you can create your very own SOAP-based service. It also revealed that the source code is open to the public, a lucky turn of events providing me something to investigate further!
Being my characteristically stubborn self, the next step was to download the source code, write my very own test application, and see what would happen. Although the toolkit provided plenty of supporting functions for building your application, I had no idea what kind of code my client had written and had to find something in the source for the gSOAP server itself. After a cursory glance, the source code was clean and strict, clearly having taken security into account while it was written. However, I wasn’t going to let that deter me, so I pressed on.
After days and nights of staring at C code, I finally identified a function that piqued my interest: "soap_putsetcookies". What this function does is to create the "Set-Cookie" header for the response. It does this by writing the necessary data to a fixed-length buffer within the function, with the intent to use at most 4064 bytes to set the cookie by combining the name and value..
The soap_putsetcookies function in all of its glory.
These values are also URL-encoded by a function that takes a pointer to the buffer it is to write to, as well as a maximum limit of data it is allowed to write. So far, so innocent.
The soap_putsetcookies function in all of its glory.
The code shows that the limit for the encoding function is calculated as such: 4064 - space used. This makes perfect sense. Two things had been overlooked though…
Light at the end of the tunnel!
The first of these is the equals sign connecting the cookie name and value to one another. This addition was not checked for whether it pushed the space used past the established limit of 4064 bytes. But of course, if that was the case, the allowed limit for the soap_encode_url function results in -1 bytes, which ought to mean that it will not write anything. However, this leads to the second oversight: The fact that the encoding function's size limit is of type size_t, which is a form of unsigned integer, a famous allergen to anything negative.
So, what does this all mean? It means that when a cookie name of size 4064 bytes is supplied and the equals sign is appended, the next time the soap_encode_url function is called in order to write the cookie value to the buffer, an integer underflow takes place. So instead of having no space left to write to, the function is sent a limiter of the maximum possible value of a size_t type. In effect, we are now allowed to write some few billion bytes to the buffer if we want to, allowing us to supply a much too long cookie value, that it will run right past the buffer limits and overflow the stack.
In summary: We have an integer underflow leading to a stack-based buffer overflow, known as "pretty cool" in the security community, and "really boring" in other circles.
The proof is in the pudding
The only thing left was to trigger the soap_putsetcookies function in a proof-of-concept. I compiled the server code with the ‘WITH_COOKIES’-flag enabled. Then I ran the server locally and verified that everything was working as intended.
When a cookie is altered, it is flagged as changed and it will be written to the response headers through this function. This can be done by supplying a cookie with a dummy value in the request headers, and then a cookie with the same name, but the intended payload. As the request is parsed, cookies are set, and since a cookie with the same name already exist, it will be overwritten, and flagged as having been modified.
After sending the payload as cookie value to the server, I observed a segmentation fault on the server resulting in a crash, proving my theory right.
The tricky part
Now the most tricky and unpredictable part, the responsible disclosure procedure. Disclose what we have found to the vendor and work together to resolve the vulnerability. At Outpost24 we adhere to our Responsible Disclosure policy to ensure what we find is adequately addressed and resolved. In doing so we hope to remediate these zero-day findings before adversaries can abuse them. However, following our policy does not necessarily mean that the vendor is always happy about receiving such information. Some vendors are impossible to reach, others ignore you, or in worst case they try to sue you for doing your due diligence… let’s hope for the best!
When we contacted Genivia, they were quick to respond. We shared our writeup and concerns, Genivia investigated and reported back a full list of gSOAP versions affected by the vulnerability and we agreed on how to proceed with vulnerability identified.
"Because we take security seriously, we fixed the problem immediately and contacted our customers with a warning and recommendations to upgrade. Fortunately, we received few indications from our customers, as only web server applications built with cookies are affected which is not a common configuration. Although web services typically do not rely on cookies, we highly value the disclosure of this vulnerability by Outpost24. Because of this, we can ensure our customers are running reliable and secure web server applications." – Genivia
Well done to Genivia for having taken this seriously, as well as being genuinely pleasant to work with during this whole process.
Proof of concept
- 9 January 2019 – Initial discovery
- 10 January 2019 – Internal verification and write-up
- 10 January 2019 – Initial contact with vendor
- 10 January 2019 – Response from Genivia, shared vulnerability details
- 13 January 2019 – Vulnerability verified by Genivia
- 14 January 2019 – Advisory & workaround released on website Genivia
- 15 January 2019 – Follow-up call to speak through details, proposed fix and disclosure timelines
- 15 January 2019 – Patch released by Genivia
- 9 February 2019 – CVE Reference (CVE-2019-7659)
- 15 March 2019 – Disclosure due date
- 21 March 2019 – Full disclosure in collaboration with Genivia
Make sure you have a responsible disclosure policy in place for your organisation, visibly on your website. If anyone finds something on your website they know how to report it and by what rules they should play.
About Ghost Labs
Ghost Labs is the specialist security unit within Outpost24, offering enhanced security services such as advanced network penetration testing, (web)application testing, Red Teaming assessments and complex web application exploitation. In addition, the Ghost Labs team is an active contributor to the security community with vulnerability research and coordinated responsible disclosure programs.
Ghost Labs performs hundreds of success penetration tests for its customers ranging from global enterprises to SMEs. Our team consists of highly skilled ethical hackers, covering a wide range of advanced testing services to help companies keep up with evolving threats and new technologies.