Blind SQL Injection 모의해킹

2024. 7. 28. 13:18CERT

목차

  • Blind SQL Injection 이론
  • Blind SQL Injection 실습
  • Blind SQL Injection 대응방안

 

Blind SQL Injection 이론

  • 쿼리의 결과를 참 또는 거짓으로만 출력하는 페이지에서 사용할 수 있는 SQL Injection 공격 기법
  • 출력 내용이 참 또는 거짓으로만 구성된 웹 페이지에서 참/거짓 정보를 이용해 데이터베이스의 내용을 추측하는 공격 방식
  • Brute Force 공격과 비슷하게 상당히 많은 경우의 수를 대입해보며 공격을 수행해야 하기 때문에 일반적으로 자동화 도구를 이용하여 공격을 수행한다.

 

Blind SQL Injection 실습

 

  • Blind SQL Injection 공격을 실습하기 위해 해당 탭으로 들어온 모습
  • User ID 입력란에 번호를 입력하면 해당 번호에 사용자 계정의 유무를 판단해주는 기능이 있으며,
  • 해당 번호에 사용자가 존재하는 경우, 좌측 사진과 같이  User ID exists in the database. 라는 문구를 출력해주는 것을 확인할 수 있고, 사용자 계정이 존재하지 않는 번호를 조회할 경우 우측 사진과 같이 User ID is MISSING from the database. 라는 문구를 출력하는 것을 확인할 수 있다.

 

  • 이전과 같은 방식(Error based SQL Injection)을 시도하였지만, T/F 결과값만을 보여준다.
  • 따라서 그에 맞는 시나리오를 다시 세운다.
    • DB 명(스키마) 길이 확인
    • DB 명(스키마) 문자열 확인
    • Table 이름(스키마) 문자열 확인
    • Table을 이용하여 특정 계정 id 및 password 값 확인
    • 해당 값으로 계정 로그인 시도

 

 

  • 비슷하게 1' and length(database()) =  질의문을 이용하여 DB의 이름 길이를 알아낼 수 있습니다. 위 사진에서 보듯이 1, 2, 3 값을 입력했을 때는 오류가 나타나지만 4 값을 입력했을 때는 참 값을 출력하는 것으로보아 DB의 이름의 길이는 4글자이다.
  •  이제 데이터베이스의 이름 길이를 알아냈으니, 데이터베이스의 이름을 알아내기 위해 모든 알파벳을 대입해 보는 방식으로 데이터베이스의 이름을 알아낼 수 있다.
  • 하지만 수작업으로 이 모든 과정을 처리한다면 막대한 시간이 소요되기 때문에, 이후 실습은 자동화 프로그램(SQLmap)을 사용하도록 한다.

 

  •  먼저 버프스위트의 http history에 들어가서 지금 사용하던 웹 애플리케이션의 쿠키값을 추출한다. 
  •  그리고 터미널에서 쿠키값을 이용하여 SQLmap을 작동시킨다. 명령어는 다음과 같다.
  •  sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie="쿠키값"  --current-db 
  • 최근한 사용한 db를 조회하도록 옵션값을 설정해주었다.
  • dvwa라는 데이터베이스에 접근할 수 있다는 것을 확인하였다

 

  • 알아낸 데이터베이스 이름을 기반으로 SQLMAP을 이용하여 데이터베이스에 있는 테이블들을 --tables 옵션을 사용하여 알아내는 공격을 수행한 결과이다.
  • dvwa 라는 이름의 데이터베이스에는 guestbook 이라는 테이블과 users 라는 이름의 테이블이 존재하는 것을 확인할 수 있다.

 

  • 이 중 users 라는 테이블에 모든 사용자의 계정 정보와 패스워드 정보가 있을 확률이 높을 것으로 예상되어 users 라는 테이블을 좀 더 상세하게 살펴보기로 하였다

 

  • 알아낸 데이터베이스 이름과 테이블 정보를 기반으로 users 테이블의 모든 항목을 덤프한 결과이다.
  • 우측 사진에 보이는 것과 같이 users 테이블에 있는 모든 정보들이 출력되는 모습을 확인할 수 있다.
  • 이 중 password 라는 이름의 Columns 에 있는 정보들은 MD5 해시 값으로 저장되어 있는 것을 확인할 수 있는데 해당 정보는 복호화하여 우측에 표시 해주는 것도 확인할 수 있다.

 

  • 이전 users 테이블에 있는 정보에서 pablo 라는 사용자 계정과 패스워드를 이용해 DVWA 웹 페이지에서 로그인한 결과 계정 탈취에 성공하여 로그인에 성공한 모습을 확인할 수 있었다

 

Blind SQL Injection 대응방안

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

public class LoginExample {
    public static void main(String[] args) {
        // 데이터베이스 연결 정보
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String dbUsername = "root";
        String dbPassword = "password";
        
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        
        Scanner scanner = new Scanner(System.in);

        try {
            // 사용자로부터 로그인 정보 입력받기
            System.out.print("Enter username: ");
            String username = scanner.nextLine();
            
            System.out.print("Enter password: ");
            String password = scanner.nextLine();

            // Step 1: 데이터베이스 연결
            connection = DriverManager.getConnection(url, dbUsername, dbPassword);
            
            // Step 2: Prepared Statement로 SQL 쿼리 작성
            String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
            preparedStatement = connection.prepareStatement(sql);

            // Step 3: 사용자가 입력한 값 바인딩
            preparedStatement.setString(1, username); // 첫 번째 '?'에 username 바인딩
            preparedStatement.setString(2, password); // 두 번째 '?'에 password 바인딩

            // Step 4: 쿼리 실행 및 결과 처리
            resultSet = preparedStatement.executeQuery();

            if (resultSet.next()) {
                System.out.println("Login successful! Welcome, " + username + "!");
            } else {
                System.out.println("Invalid username or password.");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // Step 5: 리소스 해제
            try {
                if (resultSet != null) resultSet.close();
                if (preparedStatement != null) preparedStatement.close();
                if (connection != null) connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            scanner.close();
        }
    }
}
  • 자바 코드 기준으로 preparedStatement 구문과 Setstring 문을 사용한다.
    • preparedStatement 구문이란 반복적으로 사용되는 쿼리 템플릿을 미리 파싱 과정(DBMS가 구문이나 문법 분석, 실행 계획 등)과 메모리에 적재하는 과정을 실행 전 미리 거치는 구문이다.
    • 사용자 입력 값은 변수로 설정하고, 입력 받은 인자 값을 문자열로 취급하도록 Setstring 함수를 거치고, 방금 메모리에 저장한 쿼리 템플릿 부분에 바인딩처리를 한다.
    • 그 다음, DBMS가 바인딩된 쿼리에 대해 실행 계획 최적화를 한다.   
    • 그 후, 최종적으로 DBMS가 실행 계획을 기계어로 컴파일 하여 메모리에 적재한 뒤, CPU가 그 기계어들을 실행시킨다.

 

  • WAS 설정 파일(위 예시는 php 설정 파일)에서 에러메시지는 출력 되지 않도록 설정해야 한다.
  • 웹 방화벽(WAF, Web Application Firewall)을 사용하여 부적절한 요청이 전송될 경우 차단한다.

 

'CERT' 카테고리의 다른 글

XSS 모의해킹  (0) 2024.07.28
Weak Session ids 모의해킹  (0) 2024.07.28
Insecure Captcha 모의해킹  (0) 2024.07.27
File Inclusion 모의해킹  (0) 2024.07.27
BruteForce 모의해킹  (0) 2024.07.27