SQL Injection(Error Bases Injection) 모의해킹

2024. 7. 21. 10:49CERT

목차

  • SQL Injection(Error Bases Injection) 이론 
  • SQL Injection(Error Bases Injection) 실습
  • SQL Injection(Error Bases Injection) 대응방안

SQL Injection(Error Bases Injection) 이론

데이터베이스와 연동된 어플리케이션의 보안 상의 허점을 이용하여 악의적인 SQL문을 실행되게 함으로써 데이터베이스를 비정상적으로 조작하는 코드 인젝션 공격 방법을 말한다.

 

안랩 SQL Error Bases Injection 설명 사진

 

  • 1번 쿼리문은 일반적으로 로그인 시 많이 사용되는 SQL 구문이다. 해당 구문에서 입력값에 대한 검증이 없음을 확인한 공격자가 임의의 SQL 구문을 주입한다. 
  • 주입된 내용은 ‘ OR 1=1 -- 
  • ‘ or 1=1을 이용하면 1=1은 참이고, or 문은 앞 조건문이 거짓이더라도 뒤에 오는 조건문만 참이면, 전체 조건문을 참으로 만들 수 있다. 뒤에 -- 를 통해 뒤에 오는 SQL 문을 주석처리하게된다.
  • 그러면 where 조건문과 뒤에 오는 SQL 문까지 무시한채 전체 SQL 문을 실행하게된다.
  • 위 구문은 로그인 폼에서 자주 사용되는 SQL 구문이며, 해당 구문의 WHERE 절을 항상 참인 조건으로 만들어 SELECT * FROM users 와 같은 쿼리 효과를 통해 로그인 과정을 우회하여 관리자 계정이나 기타 사용자 계정을 인증한다.
  • 또 이러한 방식으로 로그인 폼을 우회하여 접속을 할 경우 가장 첫 번째로 생성된 계정의 권한으로 로그인이 되는데 보통 관리자 권한의 계정인 경우가 많아 공격에 많이 활용된다고 한다.

 

SQL Injection(Error Bases Injection) 실습

시나리오

  • dvwa page 로그인 폼에 에러 베이스 sql 문 삽입을 통해 로그인 인증 우회 시도하여 DB 상 첫번째로 놓여져있는 유저에 로그인 시도

 

  • 그래서 앞서 배운 이론 내용을 바탕으로 에러를 일으키는 SQL 문을 삽입해보았고, DB안 사용자 목록 전체가 조회되는 것을 확인해볼 수 있다.
  • 그러나 이것만으로 로그인을 할 수는 없는 듯 해서 다른 SQL문과 조합하여 password 정보도 탈취한 뒤, 로그인 시도를 해보도록 시나리오를 수정했다.

 

 

order by 구문을 활용하여 칼럼의 개수를 확인해보는 사진: order by 2으로 작성하자, 2번째 칼럼이 있어서 정상 페이지를 출력하는 모습

 

order by 구문을 활용하여 칼럼의 개수를 확인해보는 사진: order by 3으로 작성하자, 3번째 칼럼이 없어서 오류 페이지를 출력하는 모습

 

  • 이번 공격은 ORDER BY 구문을 활용하여 원본 SELECT 문이 검색하는 Columns의 개수를 알아내는 공격을 수행한 모습이다.
  • 우선 해당 공격을 수행한 이유는 뒤에 나올 Union 구문을 이용한 공격을 수행하기 위해 우선 Columns의 개수를 알아내는 공격을 먼저 수행한 것이다.
    • Union 구문을 사용하는 이유는 첫번째 SQL 문의 칼럼 개수만 맞추면, 두번째 SQL 문이 무엇이 오더라도 실행하게 된다.
    • 이를 이용하면, 두번째 SQL 문을 내가 원하는 정보를 쿼리할 수 있는 SQL 문으로 작성하면 Union 구문 덕분에 실행시킬 수 있다는 뜻이다.  
    • Union 구문의 경우 합집합이라는 의미의 SQL 구문으로 1번 SELECT문 + 2번 SELECT문을 하여 결과를 출력해주는 구문이다.(1번 SELECT문 union 2번 SELECT문)
    • 그래서 일단, 조회하고자 하는 테이블의 칼럼 개수부터 알아야한다는 것이다.
  • 우선 공격한 것을 해석하기 전 ORDER BY 구문의 역할을 간략하게 알아보면 ORDER BY 구문은 입력된 Columns 기준으로 데이터를 정렬하는 명령어이다.
    • 원본 테이블의 칼럼 수를 알고자 1부터 입력해보았고, 2까지는 정상 작동 하였으나 위 사진처럼 3에서는 오류 페이지가 나온다.
    • 즉, 원본 SELECT 문이 검색하는 Columns의 개수는 2개인 것을 확인할 수 있다.

  • ORDER BY 구문을 이용하여 알아낸 Columns 개수를 기반으로 Union 구문을 작성하고 database() 함수와 @@version 을 입력하여 DB이름, DBMS 정보를 수집한 결과
  • DB 이름은 'dvwa', 사용하는 DBMS 버전은 10.6.10-MariaDB+1+b1 이라는 것을 알아냈다

 

 

  • DB는 데이터를 위한 데이터라고 불리는 메타데이터라는 것이 있다. MySQL을 기반으로한 DB는 INFORMATION_SCHEMA라는 DB가 바로 메타데이터인데 이곳에서 모든 데이터베이스의 구조를 알아낼 수 있다.
  • INFORMATION_SCHEMA라는 DB안에 SCHEMATA 라는 이름의 테이블에서 스키마 이름을 조회한 결과이다. 방금 알아낸 dvwa DB에 대한 table 정보를 알아내는 것이 주목적이기에 dvwa에 대한 스키마 정보를 조회해보기로 했다.

 

 

  • 앞에서 알아낸 데이터베이스 이름을 기반으로 해당 데이터베이스에 존재하는 모든 테이블을 조회하는 공격을 수행해본 결과이다.
  • dvwa 라는 이름의 데이터베이스에는 guestbook 테이블과 users 라는 테이블이 존재하는 것을 확인할 수 있었다.
  • 이 중 users 테이블에 사용자 계정 정보가 있을 것으로 예상되어 users 테이블에 있는 Columns 정보를 조회해보았다.

 

  • users 테이블에 있는 Columns 정보를 조회한 결과의 모습이다.
  • 여러 Columns이 존재하는 것을 확인할 수 있었는데 이 중 users 와 password 라는 이름의 Columns에 사용자 계정 정보와 패스워드 정보가 있을 것으로 예상되어 해당 Columns 내용을 조회하는 공격을 수행하였다.

 

 

 

  • users 테이블의 user, password 라는 이름의 Columns의 내용을 조회한 결과
    • 모든 사용자 계정과 패스워드가 조회된 모습을 확인할 수 있었다.
    • 이 중 패스워드의 경우는 해시함수를 이용하여 암호화되어 테이블에 저장되어 있는 모습을 확인할 수 있었다.
    • 탈취 목적 계정인 admin의 password 해시 함수 값을 구글에 검색해보았다.

 

  • 해당 해시 함수 결과 값은 MD5 해시 함수 알고리즘에 의한 결과 값이며, 나아가 해당 값을 복호화한 결과, 4444인 것을 알아냈다. 애초에 MD5 해시 함수 알고리즘 자체가 내부 결함에 의해 이렇게 쉽게 복호화된 것을 확인해볼 수 있다.

 

 

 

  • 마지막으로 지금까지의 공격으로 탈취한 사용자 계정과 패스워드로 DVWA 웹 페이지에서 로그인한 결과 계정 탈취에 성공하여 admin 계정으로 로그인에 성공한 모습을 확인할 수 있었다.

SQL Injection(Error Bases 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();
        }
    }
}
  • 자바 코드 기준으로 Prepared statement 구문과 Setstring 문을 사용한다.
    • preparedStatement  구문이란 반복적으로 사용되는 쿼리 템플릿을 미리 파싱 과정(DBMS가 구문이나 문법 분석, 실행 계획 등)과 메모리에 적재하는 과정을 실행 전 미리 거치는 구문이다.
    • 사용자 입력 값은 변수로 설정하고, 입력 받은 인자 값을 문자열로 취급하도록 Setstring 함수를 거치고, 방금 메모리에 저장한 쿼리 템플릿 부분에 바인딩처리를 한다.
    • 그 다음, DBMS가 바인딩된 쿼리에 대해 실행 계획 최적화를 한다.   
    • 그 후, 최종적으로 DBMS가 실행 계획을 기계어로 컴파일 하여 메모리에 적재한 뒤, CPU가 그 기계어들을 실행시킨다.

'CERT' 카테고리의 다른 글

File Inclusion 모의해킹  (0) 2024.07.27
BruteForce 모의해킹  (0) 2024.07.27
File Upload 모의해킹  (0) 2024.06.22
CSRF 모의해킹  (0) 2024.06.15
Command Injection 모의해킹  (2) 2024.06.15