SQL Injection(Error Bases Injection) 모의해킹
2024. 7. 21. 10:49ㆍCERT
목차
- SQL Injection(Error Bases Injection) 이론
- SQL Injection(Error Bases Injection) 실습
- SQL Injection(Error Bases Injection) 대응방안
SQL Injection(Error Bases Injection) 이론
데이터베이스와 연동된 어플리케이션의 보안 상의 허점을 이용하여 악의적인 SQL문을 실행되게 함으로써 데이터베이스를 비정상적으로 조작하는 코드 인젝션 공격 방법을 말한다.
- 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 구문을 활용하여 원본 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 |