Beispiel #1
0
    def __init__(self):
        """Main program entrypoint"""

        # Parse arguments
        args = self.parse_args()
        # Init logger with CLi arguments
        init_log(args.verbose, args.quiet)
        # If template conf , print and exit
        if args.template_conf: self.template_conf()
        # Print "banner"
        log.info(
            "WPWatcher -  Automating WPscan to scan and report vulnerable Wordpress sites"
        )
        # If version, print and exit
        if args.version: self.verion()
        # Init WPWatcher obhect and dump reports
        if args.wprs != False: self.wprs(args.wprs, args.daemon)

        # Read config
        configuration = self.build_config_cli(args)

        # If daemon lopping
        if configuration['daemon']:
            # Run 4 ever
            WPWatcherDaemon(configuration)

        else:
            # Run scans and quit
            # Create main object
            wpwatcher = WPWatcher(configuration)
            exit_code, _ = wpwatcher.run_scans_and_notify()
            exit(exit_code)
Beispiel #2
0
 def __init__(self, conf):
     log.info("Daemon mode selected, looping for ever...")
     # keep data in memory
     wpwatcher = WPWatcher(conf)
     while True:
         # Run scans for ever
         wpwatcher.run_scans_and_notify()
         log.info("Daemon sleeping %s and scanning again..." %
                  conf['daemon_loop_sleep'])
         time.sleep(conf['daemon_loop_sleep'].total_seconds())
Beispiel #3
0
def main(_args: Optional[Sequence[Text]] = None) -> None:
    """Main program entrypoint"""
    # Parse arguments
    args: argparse.Namespace = get_arg_parser().parse_args(_args)

    # Init logger with CLi arguments
    _init_log(args.verbose, args.quiet)

    # If template conf , print and exit
    if args.template_conf:
        template_conf()

    # Print "banner"
    log.info(
        "WPWatcher - Automating WPscan to scan and report vulnerable Wordpress sites"
    )

    if args.version:
        # Print and exit
        version()

    if args.wprs != False:
        # Init WPWatcherDataBase object and dump reports
        wprs(filepath=args.wprs, daemon=args.daemon)

    # Read config
    configuration = Config.fromcliargs(args)

    if args.show:
        # Init WPWatcherDataBase object and dump cli formatted report
        show(
            urlpart=args.show,
            filepath=configuration["wp_reports"],
            daemon=args.daemon,
        )

    # Launch syslog test
    if args.syslog_test:
        syslog_test(configuration)

    # If daemon lopping
    if configuration["daemon"]:

        # Run 4 ever
        daemon = Daemon(configuration)
        daemon.loop()

    else:
        # Run scans and quit
        wpwatcher = WPWatcher(configuration)
        exit_code, reports = wpwatcher.run_scans()
        exit(exit_code)
Beispiel #4
0
    def __init__(self):
        """Main program entrypoint"""

        # Parse arguments
        args = self.parse_args()

        # Init logger with CLi arguments
        init_log(args.verbose, args.quiet)

        # If template conf , print and exit
        if args.template_conf:
            self.template_conf()

        # Print "banner"
        log.info(
            "WPWatcher -  Automating WPscan to scan and report vulnerable Wordpress sites"
        )

        if args.version:
            # Print and exit
            self.verion()

        if args.wprs != False:
            # Init WPWatcherDataBase object and dump reports
            self.wprs(filepath=args.wprs, daemon=args.daemon)

        # Read config
        configuration = self.build_config_cli(args)

        if args.show:
            # Init WPWatcherDataBase object and dump cli formatted report
            self.show(
                urlpart=args.show,
                filepath=configuration["wp_reports"],
                daemon=args.daemon,
            )

        # Launch syslog test
        if args.syslog_test:
            self.syslog_test(configuration)

        # If daemon lopping
        if configuration["daemon"]:
            # Run 4 ever
            WPWatcherDaemon(configuration)
        else:
            # Run scans and quit
            # Create main object
            wpwatcher = WPWatcher(configuration)
            exit_code, _ = wpwatcher.run_scans_and_notify()
            exit(exit_code)
Beispiel #5
0
 def wprs(filepath=None, daemon=False):
     """Generate JSON file database summary"""
     db = WPWatcherDataBase(filepath, daemon=daemon)
     sys.stdout.buffer.write(
         WPWatcher.results_summary(db._data).encode("utf8"))
     sys.stdout.flush()
     exit(0)
Beispiel #6
0
 def test_should_notify(self):
     # test send_errors, send_infos, send_warnings, resend_emails_after, email_errors_to
     # Init WPWatcher
     CONFIG=DEFAULT_CONFIG+"\nsend_infos=Yes\nsend_errors=Yes\nsend_warnings=No"
     wpwatcher = WPWatcher(WPWatcherConfig(string=CONFIG).build_config()[0])
     # wpwatcher.scanner.mail
     # TODO
Beispiel #7
0
    def test_send_report(self):
           
        # Init WPWatcher
        wpwatcher = WPWatcher(WPWatcherConfig(string=DEFAULT_CONFIG+"\nattach_wpscan_output=Yes").build_config()[0])


        print(wpwatcher.__dict__)
        print(wpwatcher.scanner.__dict__)
        print(wpwatcher.scanner.mail.__dict__)

        # Send mail
        for s in WP_SITES:
            report={
                "site": s['url'],
                "status": "WARNING",
                "datetime": "2020-04-08T16-05-16",
                "last_email": None,
                "error": '',
                "infos": [
                    "[+]","blablabla"],
                "warnings": [
                    "[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).\n| Found By: Emoji Settings (Passive Detection)\n",
                    "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
                ],
                "alerts": [],
                "fixed": ["This issue was fixed"],
                "summary":None,
                "wpscan_output":"This is real%s"%(s)
            }

            

            # notif=WPWatcherNotification(WPWatcherConfig(string=DEFAULT_CONFIG+"\nattach_wpscan_output=Yes").build_config()[0])
            wpwatcher.scanner.mail.send_report(report, email_to='test', wpscan_command= 'just testing')
Beispiel #8
0
 def test_scan_localhost_error_not_wordpress(self):
     # test info, warnings and alerts
     scanner = WPWatcherScanner(
         WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])
     report = scanner.scan_site(
         WPWatcher.format_site({'url': 'http://localhost:8080'}))
     self.assertEqual(report['status'], 'ERROR')
     self.assertRegex(report['error'],
                      'does not seem to be running WordPress')
Beispiel #9
0
    def test_config(self):
        config="""
[wpwatcher]
wpscan_args=[   "--format", "cli",
                "--no-banner",
                "--random-user-agent", 
                "--disable-tls-checks" ]
wp_sites=%s
send_email_report=Yes
send_infos=Yes
send_errors=Yes
send_warnings=No
attach_wpscan_output=Yes
resend_emails_after=5d
wp_reports=./test.json
follow_redirect=Yes
"""%(json.dumps(self.get_sites()))
        w=WPWatcher(WPWatcherConfig(string=config).build_config()[0])
        exit_code, results=w.run_scans_and_notify()
        self.assertEqual(0, exit_code)
Beispiel #10
0
    def __init__(self):
        args = self.parse_args()
        init_log(args.verbose, args.quiet)
        # If template conf , print and exit
        if args.template_conf:
            print(WPWatcherConfig.TEMPLATE_FILE)
            exit(0)
        log.info(
            "WPWatcher -  Automating WPscan to scan and report vulnerable Wordpress sites"
        )
        # If version, print and exit
        if args.version:
            log.info("Version:\t\t%s" % VERSION)
            log.info("Authors:\t\t%s" "" % AUTHORS)
            exit(0)
        # Init WPWatcher obhect and dump reports
        if args.wprs != False:
            if args.wprs == None:
                f = WPWatcher(WPWatcherConfig().build_config()
                              [0]).find_wp_reports_file()
            else:
                f = args.wprs
            log.info("Reports: %s" % (f))
            with open(f) as r:
                results = json.load(r)
            print(results_summary(results))
            exit(0)

        # Read config
        configuration = self.build_config_cli(args)
        # Create main object
        wpwatcher = WPWatcher(configuration)
        # If daemon lopping
        if wpwatcher.conf['daemon']:
            log.info("Daemon mode selected, looping for ever...")
            results = None  # Keep databse in memory
            while True:
                # Run scans for ever
                exit_code, results = wpwatcher.run_scans_and_notify()
                timesleep = wpwatcher.conf['daemon_loop_sleep']
                log.info("Daemon sleeping %s and scanning again..." %
                         timesleep)
                time.sleep(timesleep.total_seconds())
                wpwatcher = WPWatcher(self.build_config_cli(args))
                wpwatcher.wp_reports = results

        # Run scans and quit
        else:
            exit_code, results = wpwatcher.run_scans_and_notify()
            exit(exit_code)
Beispiel #11
0
    def test_init_wpwatcher(self):
        # Init deafult watcher
        wpwatcher = WPWatcher(Config.fromstring(DEFAULT_CONFIG))

        self.assertEqual(type(wpwatcher.scanner), Scanner,
                         "Scanner doesn't seem to have been initialized")
        self.assertEqual(type(wpwatcher.scanner.mail), EmailSender,
                         "EmailSender doesn't seem to have been initialized")
        self.assertEqual(
            type(wpwatcher.scanner.wpscan), WPScanWrapper,
            "WPScanWrapper doesn't seem to have been initialized")
        self.assertEqual(
            shlex.split(Config.fromstring(DEFAULT_CONFIG)['wpscan_path']),
            wpwatcher.scanner.wpscan._wpscan_path,
            "WPScan path seems to be wrong")
Beispiel #12
0
    def test_init_wpwatcher(self):
        # Init deafult watcher
        wpwatcher = WPWatcher(
            WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])
        flag = WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0]

        self.assertEqual(
            type(wpwatcher.scanner), WPWatcherScanner,
            "WPWatcherScanner doesn't seem to have been initialized")
        self.assertEqual(
            type(wpwatcher.scanner.mail), WPWatcherNotification,
            "WPWatcherNotification doesn't seem to have been initialized")
        self.assertEqual(
            type(wpwatcher.scanner.wpscan), WPScanWrapper,
            "WPScanWrapper doesn't seem to have been initialized")
        self.assertEqual(
            shlex.split(
                WPWatcherConfig(
                    string=DEFAULT_CONFIG).build_config()[0]['wpscan_path']),
            wpwatcher.scanner.wpscan.wpscan_executable,
            "WPScan path seems to be wrong")
Beispiel #13
0
 def test_wpscan_output_folder(self):
     RESULTS_FOLDER = "./results/"
     WPSCAN_OUTPUT_CONFIG = DEFAULT_CONFIG + "\nwpscan_output_folder=%s" % RESULTS_FOLDER
     wpwatcher = WPWatcher(
         WPWatcherConfig(string=WPSCAN_OUTPUT_CONFIG).build_config()[0])
     self.assertTrue(
         os.path.isdir(RESULTS_FOLDER),
         "WPscan results folder doesn't seem to have been init")
     for s in WP_SITES:
         report = {
             "site":
             s['url'],
             "status":
             "WARNING",
             "datetime":
             "2020-04-08T16-05-16",
             "last_email":
             None,
             "errors": [],
             "infos": ["[+]", "blablabla"],
             "warnings": [
                 "[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).\n| Found By: Emoji Settings (Passive Detection)\n",
                 "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
             ],
             "alerts": [],
             "fixed": [],
             "wpscan_output":
             "This is real%s" % (s)
         }
         f = wpwatcher.scanner.write_wpscan_output(report)
         f1 = os.path.join(
             RESULTS_FOLDER, 'warning/',
             get_valid_filename('WPScan_output_%s_%s.txt' %
                                (s['url'], "2020-04-08T16-05-16")))
         self.assertEqual(f, f1, "Inconsistent WPScan output filenames")
         self.assertTrue(os.path.isfile(f1),
                         "WPscan output file doesn't exist")
         with open(f1, 'r') as out:
             self.assertEqual(out.read(), "This is real%s" % (s))
     shutil.rmtree(RESULTS_FOLDER)
Beispiel #14
0
 def show(urlpart, filepath=None, daemon=False):
     """Inspect a report in database"""
     db = WPWatcherDataBase(filepath, daemon=daemon)
     matching_reports = [r for r in db._data if urlpart in r["site"]]
     eq_reports = [r for r in db._data if urlpart == r["site"]]
     if len(eq_reports):
         sys.stdout.buffer.write(
             format_results(eq_reports[0], format="cli").encode("utf8"))
     elif len(matching_reports) == 1:
         sys.stdout.buffer.write(
             format_results(matching_reports[0],
                            format="cli").encode("utf8"))
     elif len(matching_reports) > 1:
         sys.stdout.buffer.write(
             "The following sites match your search: \n".encode("utf8"))
         sys.stdout.buffer.write(
             WPWatcher.results_summary(matching_reports).encode("utf8"))
         sys.stdout.buffer.write(
             "\nPlease be more specific. \n".encode("utf8"))
     else:
         sys.stdout.buffer.write("No report found".encode("utf8"))
         exit(1)
     exit(0)
Beispiel #15
0
 def test_should_notify(self):
     # test send_errors, send_infos, send_warnings, resend_emails_after, email_errors_to
     # Init WPWatcher
     CONFIG = DEFAULT_CONFIG + "\nsend_infos=Yes\nsend_errors=Yes\nsend_warnings=No"
     wpwatcher = WPWatcher(Config.fromstring(CONFIG))
Beispiel #16
0
    def test_scan_radom_sites(self):
        # This test might be illegal in your country
        
        # Get list of Wordpress sites if not already downloaded
        filename='/tmp/wp_sites'
        if not os.path.isfile(filename):
            myfile = requests.get(SOURCE)
            open(filename, 'wb').write(myfile.content)

        # Select X from the 50M
        idxs = random.sample(range(50000), HOW_MANY)
        urls=[linecache.getline(filename, i) for i in idxs]

        # Prepare scan config
        CONFIG1="""
[wpwatcher]
wp_sites=%s
smtp_server=localhost:1025
[email protected]
email_to=["*****@*****.**"]
wpscan_args=["--rua", "--stealthy", "--format", "cli", "--no-banner", "--disable-tls-checks"]
false_positive_strings=["You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"]
send_email_report=Yes
log_file=./TEST-wpwatcher.log.conf
wp_reports=./TEST-wp_reports.json.conf
asynch_workers=10
follow_redirect=Yes
wpscan_output_folder=./TEST-wpscan-results/
send_infos=Yes
"""%json.dumps([{'url':s.strip()} for s in urls])

        # Select X from the 50M
        idxs = random.sample(range(50000), HOW_MANY)
        urls=[linecache.getline(filename, i) for i in idxs]

        # Prepare scan config
        CONFIG2="""
[wpwatcher]
wp_sites=%s
smtp_server=localhost:1025
[email protected]
email_to=["*****@*****.**"]
wpscan_args=["--rua", "--stealthy", "--format", "json", "--no-banner", "--disable-tls-checks"]
false_positive_strings=["You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"]
send_email_report=Yes
log_file=./TEST-wpwatcher.log.conf
wp_reports=./TEST-wp_reports.json.conf
asynch_workers=10
follow_redirect=Yes
wpscan_output_folder=./TEST-wpscan-results/
attach_wpscan_output=Yes
send_infos=Yes
send_errors=Yes
email_errors_to=["admins@domain"]
# prescan_without_api_token=Yes
"""%json.dumps([{'url':s.strip()} for s in urls])

        # Select X from the 50M
        idxs = random.sample(range(50000), HOW_MANY)
        urls=[linecache.getline(filename, i) for i in idxs]

        # Prepare scan config
        CONFIG3="""
[wpwatcher]
wp_sites=%s
smtp_server=localhost:1025
[email protected]
email_to=["*****@*****.**"]
wpscan_args=["--rua", "--stealthy", "--format", "json", "--no-banner", "--disable-tls-checks"]
false_positive_strings=["You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"]
send_email_report=Yes
log_file=./TEST-wpwatcher.log.conf
wp_reports=./TEST-wp_reports.json.conf
asynch_workers=10
follow_redirect=Yes
wpscan_output_folder=./TEST-wpscan-results/
attach_wpscan_output=Yes
send_warnings=No
send_errors=Yes
fail_fast=Yes
"""%json.dumps([{'url':s.strip()} for s in urls])
        
        # Launch SMPT debbug server
        smtpd.DebuggingServer(('localhost',1025), None )
        executor = concurrent.futures.ThreadPoolExecutor(1)
        executor.submit(asyncore.loop)

        # Init WPWatcher
        w1 = WPWatcher(WPWatcherConfig(string=CONFIG1).build_config()[0])

        # Run scans
        res1=w1.run_scans_and_notify()

        # Init WPWatcher
        w2 = WPWatcher(WPWatcherConfig(string=CONFIG2).build_config()[0])

        # Run scans
        res2=w2.run_scans_and_notify()

        # Init WPWatcher
        w3 = WPWatcher(WPWatcherConfig(string=CONFIG3).build_config()[0])

        # Run scans
        res3=w3.run_scans_and_notify()

        # Close mail server
        asyncore.close_all()

        self.assertEqual(type(res1), tuple, "run_scans_and_notify returned an invalied result")
Beispiel #17
0
    def test_interrupt(self):
        wpwatcher = WPWatcher(Config.fromstring(DEFAULT_CONFIG))

        with self.assertRaises(SystemExit):
            wpwatcher.interrupt()
Beispiel #18
0
    def test_update_report(self):
        # Init WPWatcher
        wpwatcher = WPWatcher(
            WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])
        for s in WP_SITES:
            old = {
                "site":
                s['url'],
                "status":
                "WARNING",
                "datetime":
                "2020-04-08T16-05-16",
                "last_email":
                "2020-04-08T16-05-17",
                "errors": [],
                "infos": ["[+]", "blablabla"],
                "warnings": [
                    "[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).\nblablabla\n",
                    "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
                ],
                "alerts": [],
                "fixed": ["This issue was fixed"],
                "wpscan_output":
                ""
            }

            new = {
                "site":
                s['url'],
                "status":
                "",
                "datetime":
                "2020-04-10T16-00-00",
                "last_email":
                None,
                "errors": [],
                "infos": ["[+]", "blablabla"],
                "warnings": [
                    "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
                ],
                "alerts": [],
                "fixed": [],
                "wpscan_output":
                ""
            }

            expected = {
                "site":
                s['url'],
                "status":
                "",
                "datetime":
                "2020-04-10T16-00-00",
                "last_email":
                "2020-04-08T16-05-17",
                "errors": [],
                "infos": ["[+]", "blablabla"],
                "warnings": [
                    "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
                ],
                "alerts": [],
                "fixed": [
                    "This issue was fixed",
                    'Issue regarding component "%s" has been fixed since last report.\nLast report sent the %s.\nFix detected the %s\nIssue details:\n[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).\nblablabla\n'
                    %
                    ("[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).",
                     old['last_email'], new['datetime'])
                ],
                "wpscan_output":
                ""
            }

            wpwatcher.scanner.update_report(new, old, s)
            print(new)
            print(expected)
            self.assertEqual(
                new, expected,
                "There is an issue with fixed issues feature: the expected report do not match the report returned by update_report()"
            )
Beispiel #19
0
    def test_wp_reports(self):
        SPECIFIC_WP_REPORTS_FILE_CONFIG = DEFAULT_CONFIG + "\nwp_reports=%s"

        # Compare with config and no config
        wpwatcher = WPWatcher(
            WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])
        paths_found = wpwatcher.wp_reports.find_wp_reports_file()
        wpwatcher2 = WPWatcher(
            WPWatcherConfig(string=SPECIFIC_WP_REPORTS_FILE_CONFIG %
                            (paths_found)).build_config()[0])
        self.assertEqual(
            wpwatcher.wp_reports._data, wpwatcher2.wp_reports._data,
            "WP reports database are different even if files are the same")

        # Test Reports database
        reports = [{
            "site":
            "exemple.com",
            "status":
            "WARNING",
            "datetime":
            "2020-04-08T16-05-16",
            "last_email":
            None,
            "errors": [],
            "infos": ["[+]", "blablabla"],
            "warnings": [
                "[+] WordPress version 5.2.2 identified (Insecure, released on 2019-06-18).\n| Found By: Emoji Settings (Passive Detection)\n",
                "[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.\n[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
            ],
            "alerts": [],
            "fixed": []
        }, {
            "site": "exemple2.com",
            "status": "INFO",
            "datetime": "2020-04-08T16-05-16",
            "last_email": None,
            "errors": [],
            "infos": ["[+]", "blablabla"],
            "warnings": [],
            "alerts": [],
            "fixed": []
        }]
        wpwatcher = WPWatcher(
            WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])
        wpwatcher.wp_reports.update_and_write_wp_reports(reports)
        # Test update
        for r in reports:
            self.assertIn(
                r, wpwatcher.wp_reports._data,
                "The report do not seem to have been saved into WPWatcher.wp_report list"
            )
        # Test write method
        wrote_db = wpwatcher.wp_reports.build_wp_reports(
            wpwatcher.wp_reports.filepath)
        with open(wpwatcher.wp_reports.filepath, 'r') as db:
            wrote_db_alt = json.load(db)
        for r in reports:
            self.assertIn(
                r, wrote_db,
                "The report do not seem to have been saved into db file")
            self.assertIn(
                r, wrote_db_alt,
                "The report do not seem to have been saved into db file")
        self.assertEqual(
            wpwatcher.wp_reports._data, wrote_db_alt,
            "The database file wrote differ from in memory database")
        self.assertEqual(
            wpwatcher.wp_reports._data, wrote_db,
            "The database file wrote differ from in memory database")
Beispiel #20
0
from wpwatcher.core import WPWatcher
from wpwatcher.config import WPWatcherConfig
from wpwatcher.utils import get_valid_filename
from wpwatcher.parser import parse_results
from wpwatcher.notification import WPWatcherNotification
from wpwatcher.scan import WPWatcherScanner
import random
import linecache

# Constants
NUMBER_OF_CONFIG_VALUES = 31

# Read URLS file
# URLS="./wpwatcher-test-sites.txt.conf"
WP_SITES = [
    WPWatcher.format_site(s) for s in [{
        "url": "exemple.com"
    }, {
        "url": "exemple2.com"
    }]
]
# with open(URLS, 'r') as f: [ WP_SITES.append({'url':url.strip()}) for url in f.readlines() ]

DEFAULT_CONFIG = """
[wpwatcher]
wp_sites=%s
smtp_server=localhost:1025
[email protected]
email_to=["*****@*****.**"]
""" % json.dumps(WP_SITES)
Beispiel #21
0
    def test_interrupt(self):
        wpwatcher = WPWatcher(
            WPWatcherConfig(string=DEFAULT_CONFIG).build_config()[0])

        with self.assertRaises(SystemExit):
            wpwatcher.interrupt()