[Web Hacking] SQL Injection : Union Based SQL Injection #2

2023. 12. 14. 18:54정보 보안/Web

 

 Union Based SQL Injection 

 

  Union Based SQL Injection 공격은 SQL Injection 공격 중 한 종류로서 SQL 문법 중 하나인 Union 문법을 사용하여 게시판 같이 SQL 질의문 결과가 출력되는 곳에서 사용 가능한 공격이다. 이를 통해 공격대상의 DB 데이터를 추출하는 공격을 진행하여 피해를 입힐 수 있다. 그렇다면 먼저 Union 문법에 대해 간단히 알아보자.

 

1) Union

 

  Union이란 2개 이상의 select문을 하나의 select문으로 합치는 문법이다. 이때 생기는 중복된 값들은 하나만 남기고 모두 제거한다. Union 문법을 쓰기 위해서는 여러 조건들이 존재하며 이를 지켜야 사용가능하다. 조건들은 다음과 같다.

 

  • 컬럼명이 동일해야 한다.
  • 컬럼별 데이터 타입이 동일해야 한다.
  • 출력할 컬럼의 개수가 동일해야 한다.
  • 만약 컬럼명이 동일하지 않는 경우 AS를 통해 동일하게 맞춰준다.

 

2) Union 예시

 

TABLE_1
TABLE_2

 

  TABLE_1과 TABLE_2라는 이름을 가진 두 테이블이 존재하며 두 테이블의 컬럼명과 컬럼 수는 같으므로 Union 문법을 사용하기 위한 조건을 만족한다. 이제 이를 사용하기 위해 SQL 질의문을 입력한다.

 

Union SQL 질의문 예시
Union 질의문 결과

 

  Union 질의문 결과는 먼저 입력된 SELECT문 데이터 결과 밑으로 합쳐진다. 만약 중복된 값이 존재하면 가장 먼저 조회된 값만 남기고 나머지는 제거하여 합친다.

 

Union Based SQL Injection을 이용한 DB 추출 공격

  

  Union Based SQL Injection을 이용한 DB 추출 공격은 아래의 과정에 따라 진행한다. 

 

  1. SQL Injection 작동 여부
  2. COLUMN 개수 찾기
  3. 출력되는 COLUMN 위치 찾기
  4. DB 이름 찾기
  5. TABLE 이름 찾기
  6. COLUMN 이름 찾기
  7. DATA 추출

 

[1] SQL Injection 작동 여부

 

  가장 먼저 수행되어야 할 작업이다. SQL Injection 공격을 하려면 우선 질의문을 삽입했을 때 정상적으로 작동해야 한다. 질의문으로 항등원을 삽입하여 정상 작동되면 해당 포인트는 SQL Injection 공격이 유효하다는 뜻이다.

 

실습용 웹 어플리케이션

 

  해당 공격은 위 사진의 실습용 웹 어플리케이션을 활용할 것이다. 웹 페이지는 게임의 이름을 입력했을 때 그 게임의 이름과 점수, 제작사의 정보를 출력한다. 조회에 사용되는 질의문은 select * from game where name like '%게임이름%'으로 조회하고 싶은 게임의 이름에 포함된 문자가 입력되면 조건에 맞는 모든 데이터를 출력해 준다. 그렇다면 조건에 맞게 질의문을 삽입해 보자.

 

 

  입력창에 over%' and '1%'='1을 입력했더니 정상적인 결과가 출력됐다. 항등원이란 연산 결과가 자기 자신이 나오는 걸 의미한다. 이는 and 연산자를 사용하고 뒤에 오는 피연산자를 문법에 맞게 항상 참인 결과를 나타내는 구문으로 만들어 앞의 결과가 출력되도록 한다. 그 결과 질의문을 삽입했을 때와 삽입하지 않았을 때 같은 결과가 출력이 되면 이는 SQL Injection 공격이 유효하다는 것을 의미한다. 

 

=> 예시 : %' and '1%'='1 (이는 예시이므로 사용되는 질의문에 맞게 문법을 변경해주어야 한다.)

 

[2] COLUMN 개수 찾기

 

  Union 문법을 사용하기 위해서는 질의문에 입력된 컬럼의 개수를 알아야한다. 컬럼의 개수를 알기 위해서는 'ORDER BY' 문법을 사용하면 되는데 이는 ORDER BY 문법의 오류가 발생하는 원리를 이용한다. 그렇다면 간단하게 ORDER BY 문법이 어떤 건지 알아보자.

 

ORDER BY 문법 예시

 

  ORDER BY 문법은 데이터를 정렬하여 조회해 준다. 이때 기준은 ORDER BY 뒤에 나오는 '컬럼명 혹은 컬럼이 적혀진 순서'가 정렬 기준이 된다. 예를 들어 위 질의문에서 DATE를 기준으로 데이터를 조회하고 싶다 하면 ORDER BY 뒤에 'DATE' 혹은 '4'를 입력하면 조회 시 DATE 컬럼을 기준으로 오름차순 정렬을 하여 출력한다. 정렬 방법은 기본값으로 오름차순 정렬이며 내림차순 정렬로 출력하고 싶다면 뒤에 'DESC'를 추가적으로 입력해주면 된다.(오름차순 정렬은 ASC) 

 

  그렇다면 ORDER BY 문법이 어떻게 해야 오류가 발생하는지 알아보자. ORDER BY 문법 사용 시 뒤에 입력하는 정렬 기준이 되는 컬럼명 혹은 컬럼 순서를 입력했을 때 존재하지 않으면 오류가 발생한다. 컬럼명은 알 수 없으므로 컬럼 순서를 1부터 차례대로 입력함으로써 오류가 발생하는 순번을 통해 해당 질의문에 컬럼이 몇 개 입력되어 있는지 간접적으로 알 수 있다.

 

출력되는 컬럼은 3개이지만 order by 4으로 인해 총 컬럼 수는 4개이상이라는것을 추측할 수 있다.
order by 5를 입력했더니 오류가 발생하였다. 이를 통해 총 컬럼 수는 4개라는 것을 알 수 있다.

 

=> 예시 : %' order by 4 #

 

[3] 출력되는 COLUMN 위치 찾기

 

  전단계에서 컬럼의 개수를 찾고 난 후 Union 문법 사용 시 어떤 컬럼에 데이터가 출력되는지 찾아야한다. 

 

 

  어느 컬럼에 데이터가 출력되는지 알려면 위 사진에 나와있는 질의문처럼 입력하면 된다. union select를 통해 데이터를 추가하여 추가 데이터가 어떤 컬럼으로 나오는지 알 수 있다. 해당 질의문의 결과로 보건대 첫 번째 컬럼은 출력이 되지 않는 것을 알 수 있다. 그렇다면 나중에 데이터 출력 시 2,3,4번 자리에 입력하면 된다.

 

=> 예시 : %' union select 1,2,3,4 #

 

[4] DB 이름 찾기

 

  현재 사용 중인 DB 이름은 'select database()' 질의문을 사용하면 알 수 있다. 해당 질의문을 전단계에 사용한 질의문에 대입하면 그 결과를 출력할 수 있다. 이전 단계들로부터 첫 번째 컬럼은 데이터를 출력하지 않으므로 2,3,4번 중 한 자리에 입력한다.

 

 

  두 번째 컬럼 자리에 'database()'을 입력 후 조회하게 되면 'name' 컬럼에 현재 사용 중인 DB 이름이 출력된다. 사용중인 DB 이름은 'segfault_sql'이란 것을 알 수 있다.

 

=> 예시 : %' union select 1,database(),3,4 #

 

[5] TABLE 이름 찾기

 

  현재 사용 중인 DB 이름을 찾았다면 이제 그 DB에 존재하는 테이블의 이름을 알아야 한다. 이를 알기 위해 DB의 메타 정보를 모아둔 DB인 information_schema DB에 존재한다. information_schema DB에는 COLUMNS, TABLES, SCHEMATA 등 여러 가지 테이블이 존재한다. 전단계에서 찾은 DB의 테이블 이름을 알기 위해서는 다음과 같이 질의문을 입력하면 된다. 

 

TABLE 이름을 찾는 질의문

 

  'DB 이름'이 적혀있는 위치에 전단계에서 찾은 DB 이름인 'segfault_sql'을 입력하면 해당 DB에 존재하는 테이블 이름이 모두 출력된다. 그렇다면 해당 질의문을 union select 질의문에 대입하여 그 결과를 출력해 보자.

 

 

  출력 결과 'segfault_sql' DB에는 'game, member, secret, secret_member' 테이블들이 존재하는 것을 확인할 수 있다.

 

=> 예시   %' union select 1,table_name,3,4 from information_schema.tables where table_schema = 'segfault_sql' # 

 

[6] COLUMN 이름 찾기

 

  전단계에서 찾은 각테이블을 구성하는 컬럼 이름을 찾는 방법은 테이블 이름을 찾는 방법과 동일하다. 

 

COLUMN 이름을 찾는 질의문

 

   'TABLE 이름'이 적혀있는 위치에 전단계에서 찾은 TABLE 이름 중 하나인 'game'을 입력하면 해당 TABLE에 존재하는 컬럼 이름이 모두 출력된다. 그렇다면 해당 질의문을 union select 질의문에 대입하여 그 결과를 출력해 보자.

 

 

  출력 결과 'game' TABLE에는 'idx, name, score, production' 컬럼들이 존재하는 것을 확인할 수 있다.

 

=> 예시 

%' union select 1,column_name,3,4 from information_schema.columns where table_name = 'game' # 

 

[7] DATA 추출

 

  이제 데이터 조회를 위한 모든 정보를 수집하였으니 이를 이용하여 데이터를 추출하는 일만 남았다.

 

 

  출력 결과 'game' TABLE에는 3개의 데이터가 존재하는 것을 확인할 수 있다.

 

=> 예시 : %' union select * from game #