LimeSurvey is an open source and commercial web application that enables its users to quickly design and setup scalable surveys. RIPS automatically detected two vulnerabilities in LimeSurvey < 2.72.3: An unauthenticated persistent cross-site scripting vulnerability (CVE-2017-18358) and an authenticated arbitrary file write vulnerability which can be chained.

Unauthenticated Persistent Cross-Site Scripting

LimeSurvey 2.72.3 is prone to a persistent cross-site scripting vulnerability which is exploitable through the unauthenticated perspective. When submitting a public survey, the Continue Later feature allows users to save their partially completed survey repose and reload it at a later time. In order to identify the returning user, he provides an email address and a password when saving his response. This email address is persistently displayed unsanitized in the admin panel’s HTML context allowing the execution of malicious JavaScript.

application/views/admin/saved/savedlist_view.php

46 47 < td >< a href = 'mailto: <?php echo $oResult -> email ; ?> ' > <?php echo $oResult -> email ; ?> </ td >

The JavaScript is executed in the browser of an authenticated victim who is visiting a specially crafted link or who is viewing the partially saved repose data in the administrator’s control panel. Through this vulnerability the attacker can perform actions in the name of the victim and therefore gains access to the authenticated perspective of the web application which allows the adversary to leverage the next vulnerability.

Authenticated Arbitrary File Write

The exploitation of this vulnerability is only possible if the attacker can read, update and import templates . The attacker imports a new template by uploading a zip file containing a single config.xml file. The XML file specifies the path of the file to be modified:

template.zip/config.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?xml version="1.0" encoding="UTF-8"?> <config> <files> <css> <filename> ../../../index.php </filename> </css> <js> </js> <print_css> </print_css> <rtl> <css> <filename> ../../../index.php </filename> </css> <js></js> <print_css></print_css> </rtl> <logo> <filename> files/logo.png </filename> </logo> </files> <files_editable> <css> <filename> ../../../index.php </filename> </css> <js> </js> </files_editable> <engine> </engine> </config>

In this particular example the attacker modifies the index.php file of the LimeSurvey web root by using the built-in template file editor. This is possible because the web application does not properly sanitize the filenames which are passed within the <files_editable> -tag. Therefore a path traversal attack will mislead the application logic to treat the index.php of the web root as an editable file of the template. The following method templatesave_changes() is invoked when processing modifications to the template through the built-in template editor.

application/controllers/admin/templates.php

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 public function templatesavechanges () { ⋮ if ( returnGlobal ( 'changes' )) { $changedtext = returnGlobal ( 'changes' ); $changedtext = str_replace ( '<?' , '' , $changedtext ); if ( get_magic_quotes_gpc ()) $changedtext = stripslashes ( $changedtext ); } ⋮ $editfile = returnGlobal ( 'editfile' ); $aScreenFiles = $this -> getValidScreenFiles ( $sTemplateName ); $cssfiles = $this -> _initcssfiles ( $oEditedTemplate ); $jsfiles = $this -> _getEditableJsFiles ( $oEditedTemplate ); ⋮ // Check if someone tries to submit a file other than one of the allowed if ( in_array ( $editfile , $aScreenFiles ) === false & amp ; & amp ; in_array ( $editfile , $cssfiles ) === false & amp ; & amp ; in_array ( $editfile , $jsfiles ) === false ) { ⋮ // throw error } $savefilename = gettemplatefixlename ( Yii :: app () -> getConfig ( 'user templaterootdir' ) . "/" . $sTemplateName , $editfile ); if ( is_writable ( $savefilename )) { if ( ! $handle = fopen ( $savefilename , 'w' )) { ⋮ // throw error } if ( ! fwrite ( $handle , $changedtext )) { ⋮ // throw error } ⋮ fclose ( $handle ); } ⋮ }

On line 610 the new content of the file is received through the parameter changes . The variable $editfile holds the name of the file and is received on line 616 . The if statement ranging from line 622 to line 624 is the only check to prevent an attacker from changing files which are not part of the template. By previously importing the malicious template, the array $cssfiles will contain the file index.php causing the check to complete successfully and the file is finally opened and written to on line 633 and 637 respectively.

Time Line

What 2017/11/08 Provided vulnerability details and PoC to vendor 2017/11/08 Vendor acknowledged and fixes cross-site scripting 2017/11/10 Fixed version released

Impact & Summary: What can an attacker do?