CVE-2020-13576
A code execution vulnerability exists in the WS-Addressing plugin functionality of Genivia gSOAP 2.8.107. A specially crafted SOAP request can lead to remote code execution. An attacker can send an HTTP request to trigger this vulnerability.
Genivia gSOAP 2.8.107
https://www.genivia.com/products.html#gsoap
9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-680 - Integer Overflow to Buffer Overflow
The gSOAP toolkit is a C/C++ library for developing XML-based web services. It includes several plugins to support the implementation of SOAP and web service standards. The framework also provides multiple deployment options including modules for both IIS and Apache, standalone CGI scripts and its own standalone HTTP service.
One of the many plugins provided by gSOAP includes the wsa plugin for supporting the WS-Addressing specification which provides an asynchronous mechanism for routing SOAP requests and responses. The specification includes a
It starts by looking for the :
in the uri and assumes that if it’s not part of ://
that is is the seperator between the username and password.
21234 s = strchr(endpoint, ':');
21235 if (s && s[1] == '/' && s[2] == '/') // Skip the :// part of the parameter
21236 s += 3;
21237 else // Assume it's the seperator and start from the beginning of the element
21238 s = endpoint;
Processing continues by trying to find the @
to seperate the user:pass from the hostname. At this point, parsing of the username and password occurs assuming we have found both seperators (@
and :
)
21240 t = strchr(s, '@'); // attempts to find the seperator
21241
21242 if (t && *s != ':' && *s != '@')
21243 {
21244 size_t l = t - s + 1; // Calculate the size of the user:pass part of the string
21245 char *r = (char*)soap_malloc(soap, l); // Allocate enough storage to hold both the user and pass
21246 n = s - endpoint;
21247 if (r)
21248 {
21249 s = soap_decode(r, l, s, ":@"); // s is still pointing to the beginning of the data in this element
21250 soap->userid = r; // r is now a copy of the user part of the string up to the :
21251 soap->passwd = SOAP_STR_EOS;
21252 if (*s == ':') // s now points to the : seperator
21253 {
21254 s++; // Step past the seperator and now we should be pointing to the password section
21255 if (*s != '@') // Make sure the password isn't empty
21256 {
21257 l = t - s + 1; // t points to the @ seperator so here we calculate the length of the password by subtracting between the two seperators
21258 r = r + strlen(r) + 1; // r currently points to the copied username so we skip past to copy the password into the same buffer.
21259 s = soap_decode(r, l, s, "@"); // l is now a very large number allowing us to write us much data to the head as we like and cleanly terminate the copy with an @
21260 soap->passwd = r;
21261 }
21262 }
21263 }
21264 s++;
21265 soap_strcpy(soap->endpoint + n, sizeof(soap->endpoint) - n, s);
21266 }
Here the code makes an assumption about the order of the :
and @
seperators. It assumes that the @
(t
) is after :
(s
) and calculates the size for the second soap_decode based on this assumption. If the :
comes after the @
, this calculation causes the calculated size to be negative and wrap around and become a very large length value to soap_decode
to parse the password.
Within soap_decode, an attempt to copy the data into a the new heap buffer occurs. As the length is a very large number and the counter is counting backwards, we are able to write an arbitrary amount of data past our destination buffer.
7919 soap_decode(char *buf, size_t len, const char *val, const char *sep)
7920 {
7921 const char *s;
7922 char *t = buf;
7923 size_t i = len;
7924 for (s = val; *s; s++)
7925 if (*s != ' ' && *s != '\t' && !strchr(sep, *s))
7926 break;
7927 if (len > 0)
7928 {
7929 if (*s == '"')
7930 {
7931 s++;
7932
7933 while (*s && *s != '"' && --i)
7934 *t++ = *s++;
7935 }
Starting program: /gsoap-2.8/gsoap/samples/wsa/wsademo 8080
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Server is running
malloc(): memory corruption
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff70af8b1 in __GI_abort () at abort.c:79
#2 0x00007ffff70f8907 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7225dfa "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff70ff97a in malloc_printerr (str=str@entry=0x7ffff722406e "malloc(): memory corruption") at malloc.c:5350
#4 0x00007ffff7103a04 in _int_malloc (av=av@entry=0x7ffff745ac40 <main_arena>, bytes=bytes@entry=72) at malloc.c:3738
#5 0x00007ffff710616c in __GI___libc_malloc (bytes=72) at malloc.c:3057
#6 0x000055555556ddae in soap_malloc (soap=soap@entry=0x7ffff7fba010, n=56, n@entry=48) at stdsoap2_ssl.c:10428
#7 0x000055555556de7f in soap_strdup (soap=soap@entry=0x7ffff7fba010, s=s@entry=0x555555589430 "http://www.w3.org/2005/08/addressing/soap/fault") at stdsoap2_ssl.c:2806
#8 0x000055555557eedd in soap_try_connect_command (soap=soap@entry=0x7ffff7fba010, http_command=http_command@entry=2000,
endpoint=endpoint@entry=0x55555579db40 "http://%@AAAA:", 'B' <repeats 186 times>..., action=action@entry=0x555555589430 "http://www.w3.org/2005/08/addressing/soap/fault")
at stdsoap2_ssl.c:21486
#9 0x0000555555582cdb in soap_connect_command (soap=soap@entry=0x7ffff7fba010, http_command=http_command@entry=2000,
endpoints=0x55555579db40 "http://%@AAAA:", 'B' <repeats 186 times>..., action=0x555555589430 "http://www.w3.org/2005/08/addressing/soap/fault") at stdsoap2_ssl.c:21455
#10 0x0000555555582de0 in soap_connect (soap=soap@entry=0x7ffff7fba010, endpoint=<optimized out>, action=<optimized out>) at stdsoap2_ssl.c:21408
#11 0x0000555555562ebb in soap_wsa_fault_subcode_action (soap=soap@entry=0x7ffff7fba010, flag=flag@entry=1, faultsubcode=faultsubcode@entry=0x555555589856 "wsa5:ActionNotSupported",
faultstring=faultstring@entry=0x555555589d50 "The [action] cannot be processed at the receiver.", faultdetail=faultdetail@entry=0x0, action=action@entry=0x0)
at ../../plugin/wsaapi.c:1088
#12 0x0000555555563145 in soap_wsa_fault_subcode (faultdetail=0x0, faultstring=0x555555589d50 "The [action] cannot be processed at the receiver.",
faultsubcode=0x555555589856 "wsa5:ActionNotSupported", flag=1, soap=0x7ffff7fba010) at ../../plugin/wsaapi.c:1022
#13 soap_wsa_sender_fault_subcode (faultdetail=0x0, faultstring=0x555555589d50 "The [action] cannot be processed at the receiver.", faultsubcode=0x555555589856 "wsa5:ActionNotSupported",
soap=0x7ffff7fba010) at ../../plugin/wsaapi.c:1126
#14 soap_wsa_error (soap=soap@entry=0x7ffff7fba010, fault=fault@entry=wsa5__ActionNotSupported, info=0x0) at ../../plugin/wsaapi.c:1428
#15 0x0000555555563a7d in soap_wsa_set_error (soap=0x7ffff7fba010, c=0x55555579bbf0, s=0x55555579bc20) at ../../plugin/wsaapi.c:1623
#16 0x000055555558535f in soap_set_fault (soap=soap@entry=0x7ffff7fba010) at stdsoap2_ssl.c:22051
#17 0x00005555555861f3 in soap_send_fault (soap=0x7ffff7fba010) at stdsoap2_ssl.c:22314
#18 0x00005555555588f3 in main (argc=2, argv=<optimized out>) at wsademo.c:85
2020-11-05 - Vendor Disclosure
2020-12-16 - Vendor advised patch released on 2020-11-20
2021-01-05 - Public Release
Discovered by a member of Cisco Talos.