Exemple #1
0
async def test_scan_db():
    # TO DO: Add tests for all ScanDatabase methods
    os.mkdir(report_folder)
    try:
        await ScanDatabase.create_db_and_schema(report_folder)
        async with ScanDatabase(report_folder=report_folder) as db:
            fake_data = {
                "ip": "127.0.0.1",
                "hostname": "test",
                "url": "https://127.0.0.1:443/",
                "screenshot": f"{report_folder}/test.png",
                "port": 443,
                "scheme": "https",
                "title": "Test page",
                "server": "Test server",
                "headers": {"Wat": "Test"},
                "body": "<html><body> Test </body></html>",
            }
            await db.add_host_and_service(**fake_data)

            assert await db.get_host_count() == 1
            assert await db.get_service_count() == 1
            assert len(await db.get_hosts()) == 1
            assert len(await db.get_services()) == 1

    finally:
        shutil.rmtree(report_folder, ignore_errors=True)
Exemple #2
0
    async def _print_hosts(self, hosts, table_title=None):
        table_data = [["Id", "IP", "Hostname", "Discovered Services", "Matched Signature(s)"]]

        async with ScanDatabase(connection=self.db) as db:
            for entry in hosts:
                host_id, hostname, ip = entry
                service_count = await db.get_service_count_on_host(host_id)
                matched_sigs = map(
                    lambda x: x[0].split(','), 
                    filter(
                        lambda x: x[0] is not None, 
                        await db.get_matched_sigs_on_host(host_id)
                    )
                )

                table_data.append([
                    host_id,
                    ip,
                    hostname,
                    service_count,
                    ','.join(set(sig_name for result in matched_sigs for sig_name in result))
                ])

        table = AsciiTable(table_data)
        table.inner_row_border = True
        table.title = table_title
        print(table.table)
Exemple #3
0
    async def scan(self):
        """
        Peform a signature scan on all discovered servers
        """

        self.signatures.load()

        log.debug("Starting signature scan...")
        start_time = time()
        async with ScanDatabase(connection=self.db) as db:
            tasks = [
                self.signatures.find_match(service)
                for service in await db.get_services()
            ]

            matches = list(
                filter(lambda x: len(x[0]) > 0, await asyncio.gather(*tasks)))

            for match in matches:
                await db.add_matched_sigs_to_service(
                    match[1][0], ",".join([sig["name"] for sig in match[0]]))

            completed_time = strftime("%Mm%Ss", gmtime(time() - start_time))
            log.debug(
                f"Signature scan completed, identified {len(matches)} service(s) in {completed_time}"
            )
Exemple #4
0
async def worker(browser, queue):
    while True:
        url = await queue.get()

        page = await browser.newPage()
        page.setDefaultNavigationTimeout(
            args.timeout *
            100)  # setDefaultNavigationTimeout() accepts milliseconds

        #page.on('request', lambda req: asyncio.create_task(on_request(req)))
        #page.on('requestfinished', lambda req: asyncio.create_task(on_requestfinished(req)))
        #page.on('response', lambda resp: asyncio.create_task(on_response(resp)))

        try:
            r = await asyncio.wait_for(screenshot(url, page),
                                       timeout=args.timeout)
            logging.info(r)
            async with ScanDatabase(report_folder) as db:
                await db.add_host_and_service(**r)
            logging.info(f"Took screenshot of {url}")
        except asyncio.TimeoutError:
            logging.info(f"Task for url {url} timed out")
        except Exception as e:
            #if not any(err in str(e) for err in ['ERR_ADDRESS_UNREACHABLE', 'ERR_CONNECTION_REFUSED', 'ERR_CONNECTION_TIMED_OUT']):
            logging.error(f"Error taking screenshot: {e}")
        finally:
            stats.execs += 1
            await page.close()
            queue.task_done()
Exemple #5
0
 async def show(self, *args, **kwargs):
     """
     Preview screenshot in Terminal
     """
     async with ScanDatabase(connection=self.db) as db:
         entry = await db.get_service_by_id(int(*args[0]))
         _,_,screenshot_path,_,_,_,_,_,_ = entry
         imgcat(open(screenshot_path))
Exemple #6
0
 async def open(self, *args, **kwargs):
     """
     Open screenshot in browser/previewer
     """
     async with ScanDatabase(connection=self.db) as db:
         entry = await db.get_service_by_id(int(*args[0]))
         _,_,screenshot_path,_,_,_,_,_,_ = entry
         screenshot_path = str(pathlib.Path(screenshot_path).absolute())
         webbrowser.open(screenshot_path.replace("/", "file:////", 1))
Exemple #7
0
    async def servers(self, args):
        """
        Show discovered servers
        """
        async with ScanDatabase(connection=self.db) as db:
            if len(args):
                query_results = await db.search_services(args[0])
            else:
                query_results = await db.get_services()

            await self._print_services(query_results)
Exemple #8
0
    async def hosts(self, *args, **kwargs):
        """
        Show hosts
        """
        async with ScanDatabase(connection=self.db) as db:
            table_data = [["Id", "IP", "Hostname"]]
            for entry in await db.get_hosts():
                host_id, hostname, ip = entry
                table_data.append([host_id, ip, hostname])

            table = AsciiTable(table_data)
            table.inner_row_border = True
            print(table.table)
Exemple #9
0
    async def servers(self, *args, **kwargs):
        """
        Show discovered servers
        """
        async with ScanDatabase(connection=self.db) as db:
            table_data = [["Id", "URL", "Title", "Server"]]
            for entry in await db.get_services():
                service_id, url, title, headers = entry
                table_data.append(
                    [service_id, url, title,
                     json.loads(headers)['server']])

            table = AsciiTable(table_data)
            table.inner_row_border = True
            print(table.table)
Exemple #10
0
    async def open(self, args):
        """
        Open a screenshot in your default browser/previewer
        """

        try:
            server_id = int(args[0])
        except IndexError:
            print("No server id given")
        except ValueError:
            print("Invalid server id")
        else:
            async with ScanDatabase(connection=self.db) as db:
                entry = await db.get_service_by_id(server_id)
                screenshot_path = self.scan_folder_path / entry[2]
                webbrowser.open(screenshot_path.absolute().as_uri())
Exemple #11
0
    async def open(self, args):
        """
        Open a screenshot in your default browser/previewer
        """

        try:
            server_id = int(args[0])
        except IndexError:
            print("No server id given")
        except ValueError:
            print("Invalid server id")
        else:
            async with ScanDatabase(connection=self.db) as db:
                entry = await db.get_service_by_id(server_id)
                screenshot_path = str(db_path.parent.joinpath(entry[2]).absolute())
                webbrowser.open(screenshot_path.replace("/", "file:////", 1))
Exemple #12
0
    async def show(self, args):
        """
        Preview a screenshot in the terminal
        """

        try:
            server_id = int(args[0])
        except IndexError:
            print("No server id given")
        except ValueError:
            print("Invalid server id")
        else:
            async with ScanDatabase(connection=self.db) as db:
                entry  = await db.get_service_by_id(server_id)
                imgcat(
                    open(db_path.parent.joinpath(entry[2]).absolute())
                )
Exemple #13
0
    async def show(self, args):
        """
        Preview a screenshot in the terminal
        """

        try:
            server_id = int(args[0])
        except IndexError:
            print("No server id given")
        except ValueError:
            print("Invalid server id")
        else:
            async with ScanDatabase(connection=self.db) as db:
                entry = await db.get_service_by_id(server_id)
                with open((self.scan_folder_path / entry[2]).absolute(),
                          "rb") as image:
                    imgcat(image)
Exemple #14
0
async def generate_csv_report(scan_folder, db):
    result_limit = 100
    csv_path = scan_folder / "witnessme_report.csv"

    with open(csv_path, "w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([
            "url",
            "ip",
            "hostname",
            "port",
            "scheme",
            "title",
            "server",
            "screenshot",
            "matched_sigs",
        ])

        log.info("Generating CSV report, please wait...")
        async with ScanDatabase(connection=db) as db:
            offset = 0
            while True:
                services = await db.get_services_with_host(limit=result_limit,
                                                           offset=offset)
                if not services:
                    break

                for service in services:
                    writer.writerow([
                        service[1],
                        service[12],
                        service[11],
                        service[3],
                        service[4],
                        service[5],
                        service[6],
                        service[2],
                        service[9],
                    ])

                offset += result_limit
            log.info("Done")
Exemple #15
0
    async def hosts(self, args):
        """
        Show hosts
        """

        async with ScanDatabase(connection=self.db) as db:
            try:
                filter_term = args[0]
            except IndexError:
                hosts = await db.get_hosts()
                await self._print_hosts(hosts)
            else:
                try:
                    host = await db.get_host_by_id(int(filter_term))
                    if not host: raise ValueError(f"No host found with id: {filter_term}")
                except ValueError:
                    query_results = await db.search_hosts(filter_term)
                    await self._print_hosts(query_results)
                else:
                    await self._print_hosts([host])
                    services = await db.get_services_on_host(host[0])
                    await self._print_services(services)
Exemple #16
0
async def generate_html_report(scan_folder, db):
    results_per_page = 100
    template_path = pkg_resources.resource_filename(__name__,
                                                    "templates/template.html")

    log.info("Generating HTML report, please wait...")
    async with ScanDatabase(connection=db) as db:
        service_count = await db.get_service_count()
        total_pages = (service_count // results_per_page if service_count %
                       results_per_page == 0 else
                       (service_count // results_per_page) + 1)

        current_page = 1
        offset = 0
        while True:
            services = await db.get_services_with_host(limit=results_per_page,
                                                       offset=offset)
            if not services:
                break

            report_file = scan_folder / f"report_page_{current_page}.html"
            if current_page == 1:
                report_file = scan_folder / "witnessme_report.html"

            with open(report_file, "w") as report:
                with open(template_path) as file_:
                    template = Template(file_.read())
                    report.write(
                        template.render(
                            name="WitnessMe Report",
                            current_page=current_page,
                            total_pages=total_pages,
                            services=services,
                        ))

            current_page += 1
            offset += results_per_page
        log.info("Done")
Exemple #17
0
 async def add_to_database(self, browser, results):
     log.info(f"Took screenshot of {results['url']}")
     async with ScanDatabase(self.report_folder) as db:
         await db.add_host_and_service(**results)