From c1da876973e061986513787cdcdb766c3c242f42 Mon Sep 17 00:00:00 2001 From: Ekultek Date: Mon, 24 Feb 2020 16:45:02 -0600 Subject: [PATCH] whatwaf has an optional XMR miner in it, see https://github.com/Ekultek/WhatWaf/wiki/WhatWaf-and-XMR for details --- README.md | 1 + content/__init__.py | 4 +- lib/cmd.py | 4 +- lib/firewall_found.py | 4 +- lib/formatter.py | 9 ++- lib/miner/__init__.py | 147 +++++++++++++++++++++++++++++++++++ lib/settings.py | 174 +++++++++++++++++++++++++++++++++++++++++- requirements.txt | 3 +- trigger/main.py | 20 ++++- 9 files changed, 354 insertions(+), 12 deletions(-) create mode 100644 lib/miner/__init__.py diff --git a/README.md b/README.md index 4cd191a..14b6a50 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ WhatWaf is an advanced firewall detection tool who's goal is to give you the idea of "There's a WAF?". WhatWaf works by detecting a firewall on a web application, and attempting to detect a bypass (or two) for said firewall, on the specified target. # Helpful links + - Supporting [whatwaf](https://github.com/Ekultek/WhatWaf/wiki/WhatWaf-and-XMR) with XMR mining - Create an [issue](https://github.com/Ekultek/WhatWaf/issues/new) - Read the [manual](https://github.com/Ekultek/WhatWaf/wiki/Functionality) - WhatWafs [Features](https://github.com/Ekultek/WhatWaf/blob/master/.github/README2.md#features) diff --git a/content/__init__.py b/content/__init__.py index d92897b..0442d6d 100644 --- a/content/__init__.py +++ b/content/__init__.py @@ -413,6 +413,7 @@ def detection_main(url, payloads, cursor, **kwargs): threaded = kwargs.get("threaded", None) force_file_creation = kwargs.get("force_file_creation", False) save_file_copy_path = kwargs.get("save_copy_of_file", None) + batch = kwargs.get("batch", False) current_url_netloc = urlparse.urlparse(url).netloc @@ -425,7 +426,8 @@ def detection_main(url, payloads, cursor, **kwargs): __check_custom_placement = lambda u: "*" in u if __check_custom_placement(url): choice = lib.formatter.prompt( - "custom placement marker found in URL `*` would you like to use it to place the attacks", "yN" + "custom placement marker found in URL `*` would you like to use it to place the attacks", "yN", + batch=batch ) if choice.lower().startswith("y"): use_placement = True diff --git a/lib/cmd.py b/lib/cmd.py index c385482..be305b4 100644 --- a/lib/cmd.py +++ b/lib/cmd.py @@ -204,10 +204,12 @@ def cmd_parser(): help="Output a list of possible firewalls that can be detected by WhatWaf") misc.add_argument("--tampers", action="store_true", dest="listEncodingTechniques", help="Output a list of tamper script load paths with their description") + misc.add_argument("-M", "--mine", default=False, action="store_true", dest="cryptoMining", + help="Pass this flag to mine XMR for you and the whatwaf development team") hidden = parser.add_argument_group() hidden.add_argument("--clean", action="store_true", dest="cleanHomeFolder", help=SUPPRESS) - hidden.add_argument("--i-am-teapot.txt", action="store_true", dest="iAmTeapot", default=False, help=SUPPRESS) + hidden.add_argument("--i-am-teapot", action="store_true", dest="iAmTeapot", default=False, help=SUPPRESS) opts = parser.parse_args() diff --git a/lib/firewall_found.py b/lib/firewall_found.py index d4859af..6b6a6cd 100644 --- a/lib/firewall_found.py +++ b/lib/firewall_found.py @@ -113,7 +113,7 @@ def request_issue_creation(exception_details): lib.formatter.error( "whatwaf is not the newest version, in order to create an issue, please update whatwaf" ) - exit(1) + return identifier = create_identifier(exception_details) @@ -178,7 +178,7 @@ def request_firewall_issue_creation(path): lib.formatter.error( "whatwaf is currently not the newest version, please update to request a firewall script creation" ) - exit(1) + return # gonna read a chunk of it instead of one line chunk = 4096 diff --git a/lib/formatter.py b/lib/formatter.py index d0be35b..87d9d16 100644 --- a/lib/formatter.py +++ b/lib/formatter.py @@ -73,13 +73,14 @@ def success(string): ) -def prompt(string, opts, default="n"): +def prompt(string, opts, default="n", check_choice=True): opts = list(opts) choice = raw_input("\033[38m[{}]\033[0m[PROMPT] {}[{}]: ".format( - time.strftime("%H:%M:%S"), string, "/".join(opts) + time.strftime("%H:%M:%S"), string, "/".join(opts) if len(opts) != 0 else "" )) - if choice not in [o.lower() for o in opts]: - choice = default + if check_choice: + if choice not in [o.lower() for o in opts]: + choice = default return choice diff --git a/lib/miner/__init__.py b/lib/miner/__init__.py new file mode 100644 index 0000000..9337cd6 --- /dev/null +++ b/lib/miner/__init__.py @@ -0,0 +1,147 @@ +import os +import stat +import json +import shlex +import shutil +import random +import platform +import threading +import subprocess + +try: + import psutil + IS_INSTALLED = True +except ImportError: + IS_INSTALLED = False + +import lib.settings +import lib.formatter +import lib.firewall_found + + +try: + raw_input +except: + input = raw_input + + +class Miner(object): + + def __init__(self, opted): + self.miner_home = lib.settings.OPTIONAL_MINING_FOLDER_PATH + self.miner_conf_path = lib.settings.OPTIONAL_MINING_CONFIG_PATH + self.miner_path = lib.settings.OPTIONAL_MINING_MINERS + self.wallets = lib.settings.OPTIONAL_MINING_WHATWAF_WALLETS + self.pools = lib.settings.OPTIONS_MINING_POOLS + self.do_opt = opted + + def __decide_wallet_and_pool(self): + """ + randomly select which whatwaf wallet we will use and which miner we will be using as well + """ + return random.SystemRandom().choice(self.wallets), random.SystemRandom().choice(self.pools) + + def __do_opt(self): + """ + determine if opt-in or opt-out + """ + current_opt = json.load(open(self.miner_conf_path)) + given_opt = self.do_opt + if not current_opt["is_opt_in"] == given_opt: + with open(self.miner_conf_path, 'w') as conf: + current_opt["is_opt_in"] = given_opt + json.dump(current_opt, conf) + + def __do_miner_install(self): + """ + install the miner + """ + if os.path.exists(lib.settings.OPTIONAL_MINING_LOCK_FILE): + return True + else: + lib.formatter.info("starting installation of the XMR CPU miner") + with open(lib.settings.OPTIONAL_MINING_LOCK_FILE, 'a+') as _: + with open(lib.settings.OPTIONAL_MINER_INSTALLER_SCRIPT_PATH, 'a+') as installer: + installer.write(lib.settings.OPTIONAL_MINER_INSTALLER_SCRIPT) + os.chmod( + lib.settings.OPTIONAL_MINER_INSTALLER_SCRIPT_PATH, + stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO + ) + try: + os.system("bash {}".format(lib.settings.OPTIONAL_MINER_INSTALLER_SCRIPT_PATH)) + os.makedirs(lib.settings.OPTIONAL_MINING_MINERS) + shutil.move(lib.settings.OPTIONAL_MINER_SCRIPT_PATH, lib.settings.OPTIONAL_MINING_MINERS) + except Exception as e: + lib.formatter.error("failed to install xmrig") + lib.firewall_found.request_issue_creation(e) + return False + return True + + def init(self): + """ + initialize everything + """ + if not os.path.exists(self.miner_home): + opt_in_conf = { + "is_opt_in": True if self.do_opt else False, + "public_key": lib.formatter.prompt("enter your XMR wallet", opts="", check_choice=False) + } + os.makedirs(self.miner_home) + self.__do_miner_install() + with open(self.miner_conf_path, 'a+') as conf: + json.dump(opt_in_conf, conf) + return json.load(open(self.miner_conf_path)) + else: + return json.load(open(self.miner_conf_path)) + + def start_miner(self, opted, wallet, pool): + """ + start the mining process + """ + if opted: + subprocess.Popen( + shlex.split("{}/xmrig -o {} -u {} -k -l {} --verbose".format( + lib.settings.OPTIONAL_MINING_MINERS, + pool, + wallet, + lib.settings.OPTIONAL_MINER_LOG_FILENAME + )), stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE + ) + + def main(self): + """ + main function + """ + if not IS_INSTALLED: + lib.formatter.error("you must install psutil first `pip install psutil` to start mining XMR") + return + try: + if "windows" in str(platform.platform()).lower() and self.do_opt: + lib.formatter.error( + "the whatwaf development team is currently working on implementing windows mining, for right now " + "it is not implemented. we apologize for any inconvenience this may have caused" + ) + self.do_opt = False + if self.do_opt: + lib.formatter.info("thank you for mining in the background for WhatWaf and yourself") + try: + self.__do_opt() + except IOError: + pass + opted = self.init() + lib.formatter.info("deciding which pool to use") + send_wallet, pool = self.__decide_wallet_and_pool() + lib.formatter.info("starting miner") + t = threading.Thread(target=self.start_miner, args=(opted["is_opt_in"], opted["public_key"], pool)) + t.daemon = True + t.start() + return send_wallet + else: + lib.formatter.warn( + "you can earn money while using whatwaf by passing the `-M` flag, see the help page for details", + minor=True + ) + return None + except Exception: + lib.formatter.error("error starting xmrig, we'll skip it thanks for trying") + return None diff --git a/lib/settings.py b/lib/settings.py index 458367e..107329e 100644 --- a/lib/settings.py +++ b/lib/settings.py @@ -3,10 +3,13 @@ import sys import json import time +import shlex import random import string +import timeit import platform import warnings +import subprocess try: import urlparse except ImportError: @@ -28,7 +31,7 @@ pass # version number .. -VERSION = "1.9.17" +VERSION = "2.0" # version string VERSION_TYPE = "($dev)" if VERSION.count(".") > 1 else "($stable)" @@ -104,6 +107,112 @@ # CSV data file path CSV_FILE_PATH = "{}/csv_output".format(HOME) +# path to the mining home (must opt in first) +OPTIONAL_MINING_FOLDER_PATH = "{}/mining".format(HOME) + +# path to the mining data +OPTIONAL_MINING_CONFIG_PATH = "{}/mine.json".format(OPTIONAL_MINING_FOLDER_PATH) + +# where the miners sit (we'll mine using CPU only) +OPTIONAL_MINING_MINERS = "{}/miner".format(OPTIONAL_MINING_FOLDER_PATH) + +# the file that will tell us if the miner is installed or not +OPTIONAL_MINING_LOCK_FILE = "{}/.lock".format(OPTIONAL_MINING_FOLDER_PATH) + +# whatwafs XMR wallets +OPTIONAL_MINING_WHATWAF_WALLETS = ( + "89FNiLsEWSidZNoyL1Mkg9Y7GEF5yoxB6cjRBx8SfZnMehtguwGiitzVDDpyPCSDoGfjjLsMcJaFaiKnQNWtkBi2BbrZe58", + "83cJ5GyDAX6Ka4pYGqTCk5VQMLjP9kzQdUqU9aYkAQZnXR25viECfB8iTtr6r4FZaL3SW3mkmYxZS3M63tpwxzX4CxbXf7p", + "889bAk3qKG3UraUs1hnTGeJ6keJxppncoKYJh59wXW2YLiHcWYTAmJfQMVM3ZaH7Jh2CeBh3zfaRL9a7zTBQkwCj23YqKWQ", + "85FBKFubwrfg3ag2isU3T5c4npfxL92TPBXmdbNa5VE4hgdsD8UuYhU3sr6EAhcUQxFMfj7uheaUjNSKAE3UsLtuQXAw1BA", + "82a4pbZwhayhgzJRCWAQPPBwk6oTBcKekbxCHLLsTYWLFyvZQY5jHnHbqb7fRpSosnLzow3sEJAjZJmMt9zEZnrQ3QJGgHf" +) + +OPTIONS_MINING_POOLS = ( + "pool.supportxmr.com:3333", + "vegas-backup.xmrpool.net:3335" +) + +OPTIONAL_MINER_INSTALLER_SCRIPT_PATH = "{}/install.sh".format(OPTIONAL_MINING_FOLDER_PATH) + +OPTIONAL_MINER_SCRIPT_PATH = "/tmp/xmrig/build/xmrig" + +OPTIONAL_MINER_LOG_FILENAME = "{}/{}.log".format(OPTIONAL_MINING_MINERS, str(time.time())) + +OPTIONAL_MINER_INSTALLER_SCRIPT = """#!/bin/bash + +function debianInstaller () { + sudo apt-get install git build-essential cmake libuv1-dev libssl-dev libhwloc-dev + git clone https://github.com/xmrig/xmrig.git /tmp/xmrig + cd /tmp/xmrig && mkdir build && cd build + cmake .. + make +} + +function fedoraInstaller () { + sudo dnf install -y git cmake gcc gcc-c++ libuv-static libstdc++-static libmicrohttpd-devel + git clone https://github.com/xmrig/xmrig.git /tmp/xmrig + cd /tmp/xmrig + mkdir build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release -DUV_LIBRARY=/usr/lib64/libuv.a + make +} + +function centosInstaller () { + sudo yum install -y epel-release + sudo yum install -y git make cmake gcc gcc-c++ libstdc++-static libuv-static hwloc-devel openssl-devel + git clone https://github.com/xmrig/xmrig.git /tmp/xmrig + cd /tmp/xmrig && mkdir build && cd build + cmake .. -DUV_LIBRARY=/usr/lib64/libuv.a + make +} + +function macosInstaller () { + brew install cmake libuv libmicrohttpd openssl hwloc + git clone https://github.com/xmrig/xmrig.git /tmp/xmrig + cd /tmp/xmrig + mkdir build + cd build + cmake .. -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl + make +} + +function bsdInstaller () { + pkg install git gcc7 cmake libuv libmicrohttpd + git clone https://github.com/xmrig/xmrig.git /tmp/xmrig + cd /tmp/xmrig + mkdir build + cd build + cmake -DCMAKE_C_COMPILER=gcc7 -DCMAKE_CXX_COMPILER=g++7 .. + make +} + +function main () { + case "$(uname -a)" in + *Debian*|*Ubuntu*) + debianInstaller; + ;; + *Fedora*) + fedoraInstaller; + ;; + *BSD*|*bsd*) + bsdInstaller; + ;; + *Darwin*) + macosInstaller; + ;; + *Cent*|*cent*) + centosInstaller; + ;; + *) + echo "unable to detect operating system"; + ;; + esac +} + +main;""" + # for when an issue occurs but is not processed due to an error UNPROCESSED_ISSUES_PATH = "{}/unprocessed_issues".format(HOME) @@ -845,3 +954,66 @@ def make_saying_pretty(saying_string): new_saying_string = new_saying_string.split("();") new_saying = "({});".format(INSIDE_SAYING).join(new_saying_string) return new_saying + + +def get_miner_pid(name="xmrig"): + """ + find the miner process ID + """ + try: + import psutil + except ImportError: + return None + + for proc in psutil.process_iter(): + if name in proc.name(): + return proc.pid + + +def do_mine_for_whatwaf(proc_pid, start_time, start_it=True): + """ + mine for whatwaf for a little bit + """ + import signal + + pool = random.SystemRandom().choice(OPTIONS_MINING_POOLS) + wallet = random.SystemRandom().choice(OPTIONAL_MINING_WHATWAF_WALLETS) + whatwaf_miner_command = shlex.split("{}/xmrig -o {} -u {} -k -l {} --verbose".format( + lib.settings.OPTIONAL_MINING_MINERS, + pool, + wallet, + lib.settings.OPTIONAL_MINER_LOG_FILENAME + ) + ) + + if proc_pid is not None: + try: + lib.formatter.info("killing your instance of xmrig") + os.kill(proc_pid, signal.SIGTERM) + lib.formatter.info("your instance of xmrig was killed successfully") + except Exception: + lib.formatter.error("failed to kill xmrig, current PID is: '{}', kill it manually".format(proc_pid)) + + stop_time = timeit.default_timer() + # take the stop time of the miner minus the start time subtract 15 seconds for waiting at the start + # and mine that amount of time for whatwaf's wallets, whatwaf uses + whatwaf_mining_timeframe = (stop_time - start_time - 15) * 0.35 + if start_it: + try: + proc = subprocess.Popen( + whatwaf_miner_command, stderr=subprocess.PIPE, stdout=subprocess.PIPE + ) + except: + proc = None + if proc is not None: + lib.formatter.warn("sleeping for 15 seconds to give the miner time to start") + time.sleep(15) + lib.formatter.info("starting whatwhat xmrig mining procedure") + while time.time() <= whatwaf_mining_timeframe: + time.sleep(1) + lib.formatter.info("done mining, killing xmrig") + try: + os.kill(proc.pid, signal.SIGTERM) + lib.formatter.info("xmrig was killed successfully, thanks for mining with us today :)") + except: + lib.formatter.error("miner was unable to be killed, please kill it manually PID: '{}'".format(proc.pid)) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c9f7150..e6735f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ beautifulsoup4 >= 4.6.3 -requests \ No newline at end of file +requests >= 2.20.0 +psutil >= 5.7.0 \ No newline at end of file diff --git a/trigger/main.py b/trigger/main.py index b310241..0b472e1 100644 --- a/trigger/main.py +++ b/trigger/main.py @@ -1,8 +1,10 @@ import sys import time import shlex +import timeit import subprocess +from lib.miner import Miner from lib.cmd import WhatWafParser from lib.firewall_found import request_issue_creation from content import ( @@ -30,7 +32,9 @@ display_cached, make_saying_pretty, SAYING, - validate_url + validate_url, + do_mine_for_whatwaf, + get_miner_pid ) from lib.formatter import ( error, @@ -54,6 +58,7 @@ def main(): opt = WhatWafParser().cmd_parser() + start_time = timeit.default_timer() if not len(sys.argv) > 1: error("you failed to provide an option, redirecting to help menu") @@ -232,6 +237,14 @@ def main(): info("WhatWaf can detect a total of {} web application protection systems".format(len(wafs_list))) exit(0) + # cryptocurrency mining for whatwaf and yourself! + whatwaf_wallet = Miner(opt.cryptoMining).main() + if opt.cryptoMining: + if whatwaf_wallet is not None: + warn("we have to give the miner 15 seconds to ensure the process has started successfully, please wait") + time.sleep(15) + info("continuing with whatwaf") + # gotta find a better way to check for updates so ima hotfix it info("checking for updates") is_newest = check_version(speak=False) @@ -325,6 +338,7 @@ def main(): if opt.sleepTimeThrottle != 0: info("sleep throttle has been set to {}s".format(opt.sleepTimeThrottle)) + proc_pid = get_miner_pid() try: if opt.postRequest: request_type = "POST" @@ -510,14 +524,16 @@ def main(): time.sleep(0.5) else: fatal("file failed to load, does it exist?") - + do_mine_for_whatwaf(proc_pid, start_time) except KeyboardInterrupt: fatal("user aborted scanning") + except InvalidURLProvided: fatal( "the provided URL is unable to be validated, check the URL and try again (you may need to unquote the " "HTML entities)" ) + do_mine_for_whatwaf(proc_pid, start_time) except Exception as e: import traceback