[normaltic 취업반 5기] 2023-12-06 7주차 내용 정리

2023. 12. 7. 11:07normaltic 취업반 5기/내용 정리

 

Error Based SQL Injection

 

  Error Based SQL Injection 공격은 SQL Injection 공격 중 한 종류로서 SQL 쿼리문에 문제가 있을 때 출력되는 에러 메시지를 이용한다. SQL 쿼리문이 에러가 발생하는 원인에는 여러 가지가 존재하며 그중에서도 특정 에러를 유발하는 SQL 쿼리문을 사용해야 한다. 

 

  SQL 쿼리문에서 유발시킬 수 있는 에러는 두 가지가 존재한다.

 

  1. 문법 에러 : 문법 에러는 쿼리문 자체가 문법적으로 문제가 있어 실행 자체가 안 되는 에러다. 그렇기에 해당 에러를 발생시켜 출력되는 에러 메시지는 이용 가치가 없다.
  2. 로직 에러 : 로직 에러는 쿼리문으로서는 문제가 없어 실행은 되나 그 안에 문제가 되는 부분을 에러 메시지로 출력한다. 해당 에러를 유발시킴으로써  Error Based SQL Injection 공격을 실행할 수 있다.

  결과적으로 Error Based SQL Injection 공격을 실행하기 위해서는 SELECT 쿼리문이 우선적으로 실행되어야 하기 때문에 에러가 발생해도 쿼리문이 실행되는 로직 에러를 SQL 쿼리문으로 유발 시켜야한다. 

 

Error Based SQL Injection Payload 

 

  Error Based SQL Injection Payload는 다음과 같은 순서로 작성해나간다.

 

  1. normaltic' and '1'='1
  2. normaltic' and extractvalue('1', ':test') and '1'='1
  3. normaltic' and extractvalue('1', concat(0x3a,(select 'test'))) and '1'='1

1) normaltic' and '1'='1

 

  SQL Injection 하기 위한 기본적인 형태로서 공격대상의 쿼리문 형태에 맞춰 작성한다. 이때 해당 쿼리문의 결과값은 상관없이 SQL Injection이 정상 작동하는지 확인한다.

 

2) normaltic' and extractvalue('1',':test') and '1'='1

 

  공격대상이 사용하고 있는 DB에 맞춰 로직 에러를 유발하는 함수를 입력한다. 예시로는 MySQL의 extractvalue함수를 사용하였다.

* extractvalue('xml 글자', 'xml 표현식')

  extractvalue 함수는 xml로 표현된 문자 내에서 특정 문자를 나타낸다. 예를 들어 '<a>abc<b>kkk</b></a>'라는 xml 문자가 존재할 때 'abc'라는 문자열을 나타내고 싶다 하면 '/a' 으로 xml 문자 내 위치를 표현한다. 함수로 표현하면 다음과 같다.

- extractvalue('<a>abc<b>kkk</b></a>','/a') = abc
- extractvalue('<a>abc<b>kkk</b></a>','/a/b') = kkk

 

  extractvalue 함수는 로직 에러를 유발하는 함수로서 'xml 표현식' 인자에 쓰이는 특수문자(/,@ 등) 대신 다른 특수문자를 사용하게 되면 에러 메시지를 출력하게 된다. 이 방식으로 'xml 표현식' 인자에 '특수문자+select 쿼리문'을 입력하여 쿼리문이 실행되도록 한다.

 

유효한 특수문자(/) 사용 시 에러 메시지 출력 X
유효하지 않은 특수문자(:) 사용 시 에러 메시지 출력 O

 

3) normaltic' and extractvalue('1', concat(0x3a,(select 'test'))) and '1'='1

 

  SQL Injection 공격은 반복적인 작업이다. 그렇기에 Payload를 Format화 시켜 반복 작업에 들이는 수고를 덜어줘야 한다. Payload에서 계속해서 값이 바뀌는 부분은 extractvalue 함수의 'xml 표현식' 인자 위치이다. 해당 위치에서는 데이터 추출을 위한 select 쿼리문의 내용이 지속적으로 변경되기 때문에 concat 함수를 사용하여 특수문자(:)와 select 쿼리문의 위치를 구분 지어준다. 이때 특수문자는 8진수를 사용하여 표현한다. 이는 특수문자가 필터링되어 Payload가 작동하지 않음을 배제하기 위함이다.

 

완성된 Payload 적용

 

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

 

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

 

  1. SQL Injection 작동 여부
  2. 로직 에러 유발 함수 찾기
  3. 공격 Format 만들기
  4. DB 이름 찾기
  5. TABLE 이름 찾기
  6. COLUMN 이름 찾기
  7. DATA 추출

 

[1] SQL Injection 작동 여부

 

실습용 웹 어플리케이션

 

  Error Based SQL Injection 공격에 사용될 실습용 웹 어플리케이션으로서 ID 중복 검사 기능을 가진 프로그램이다. ID를 입력하면 해당 ID가 DB에 존재하는지 확인하여 존재여부에 대한 결과를 출력한다. 

 

  SQL Injection이 작동하는지 확인하기 위해 해당 기능에 쓰인 쿼리문에 맞춰 항등원의 역할을 하는 쿼리문을 입력한다.

 

 

  입력 결과 정상적으로 작동함으로써 SQL Injection 공격이 가능한 것을 확인하였다.

  

[2] 로직 에러 유발 함수 찾기

 

  로직 에러 유발 함수로는 MySQL의 extractvalue 함수를 사용하도록 한다.

 

[3] 공격 Format 만들기

 

  Error Based SQL Injection 공격에 쓰이는 Format을 만들어 반복 작업을 하기 쉽도록 한다. 

 

normaltic' and extractvalue('1', concat(0x3a,(__'입력할 쿼리문'__))) and '1'='1

 

  extractvalue 함수 뒤 문장은 주석으로 처리할 수도 있으나 DB마다 쓰이는 주석이 다르기 때문에 어떤 DB가 쓰여도 Format의 형태가 변하지 않도록 and '1'='1을 입력해 준다.

 

[4] DB 이름 찾기

 

  이 단계부터는 다른 SQL Injection 공격들과 같다. 만들어진 Format에 알맞은 쿼리문을 입력하여 데이터를 추출한다.

 

 

  DB의 이름을 찾는 쿼리문은 select database()로 Format에 넣어 삽입한 결과, 'errSqli'라는 DB를 찾아냈다.

 

[5] TABLE 이름 찾기

 

 

  Error Based SQL Injection 공격으로는 출력되는 데이터가 1개뿐이기에 limit 문법을 사용하여 데이터를 하나하나 출력해봐야 한다. 그 결과, 'flagTable, member'이라는 두 테이블 이름을 찾아냈다.

 

 

  테이블 데이터가 총 두 개였으므로 3행에 존재하는 데이터는 존재하지 않는다. 그래서 3행에 존재하는 데이터를 찾으려고 했을 때는 그 결과로 false를 반환한다.

 

[6] COLUMN 이름 찾기

 

  총 두 개의 테이블을 찾았으므로 각 테이블마다 컬럼을 찾아준다.

 

1. flagTable

 

  flagTable 테이블에서는 'idx, flag'라는 두 컬럼을 찾아냈다.

 

2. member

 

  member 테이블에서는 'id, pass, email, info'라는 네 컬럼을 찾아냈다.

 

[7] DATA 추출

 

  데이터 추출에 필요한 모든 정보를 찾아냈으니 이제 본격적으로 데이터를 추출해 보도록 하자.

 

1. flagTable

 

  flagTable 테이블 내에는 하나의 데이터만 존재하였다. 그 데이터는 문제의 플레그를 나타낸다.

 

2. member

 

  member 테이블에는 id 컬럼으로 데이터를 추출해 본 결과 'normaltic, dol'라는 두 데이터만 존재하였다.

 

Blind SQL Injection

 

  Blind SQL Injection 공격은 SQL Injection 공격 중 한 종류로서 쿼리문의 결과가 참 혹은 거짓으로 출력이 되는 경우에 사용 가능하다. 사실 Blind SQLI는 다른 SQLI 공격을 사용할 수 없는 상황일 때 최후의 방법으로 사용이 된다. 공격의 이름 대로 눈먼 장님같이 문자 하나하나 대조하면서 공격을 진행한다.

 

Blind SQL Injection Payload

 

  Blind SQL Injection Payload는 다음과 같은 순서로 작성해 나간다.

 

  1. normaltic' and '1'='1
  2. normaltic' and ('1'='1') and '1'='1
  3. normaltic' and ((select 'test')='test') and '1'='1
  4. normaltic' and (substr('test',1,1)='t') and '1'='1
  5. normaltic' and (ascii(substr('test',1,1)) > 0) and '1'='1

 

1) normaltic' and '1'='1

 

  SQL Injection 하기 위한 기본적인 형태로서 공격대상의 쿼리문 형태에 맞춰 작성한다. 이때 해당 형태에서의 결과값은 항상 참이어야 한다.

 

2) normaltic' and ('1'='1') and '1'='1

 

  쿼리문이 삽입될 위치에 조건문 하나를 삽입하여 정상 작동하는지 테스트한다. Payload의 결과값은 해당 위치에 삽입될 조건문의 결과에 따라 달라진다.

 

3) normaltic' and ((select 'test') = 'test') and '1'='1

 

  select 쿼리문이 정상 작동하는지 조건문에 삽입하여 테스트한다.

 

4) normaltic' and (substr('test',1,1)='t') and '1'='1

 

  substr 함수를 사용함으로써 반복 작업을 좀 더 편리하게 만들어준다. Payload는 빨간색 숫자를 계속 변경하여 'test' 해당 위치에 맞는 문자일 시 그 결과값으로 참을 반환한다.

 

* substr('대상 문자열', '시작 위치', '시작 위치에서부터 n번째 위치까지')

  
substr 함수는 인자로 입력되는 문자열에서 원하는 위치의 문자를 반환해 주는 함수다.

- substr('normaltic',1,1) = 'n' => 'normaltic' 문자열의 첫 번째 위치에서부터 하나의 문자를 반환
- substr('normaltic',3,2) = 'rm' => 'normaltic' 문자열의 세 번째 위치에서부터 문자를 반환

 

 

5) normaltic' and (ascii(substr('test',1,1)) > 0) and '1'='1

 

  Payload의 형태를 반복 작업의 피로를 덜어주기 위해 문자를 숫자 형태로 바꿔주는 작업을 진행한다. 이때 문자에 대응하는 숫자는 아스키코드로 표현이 가능하며 문자를 아스키 코드로 바꿔주는 함수인 ascii 함수를 사용한다.

 

* ascii('문자')

  ascii 함수는 인자로 입력되는 문자에 대응하는 아스키코드를 결과값으로 반환해 주는 함수다.

- ascii('a') = 97
- ascii('X') = 88

  

 

Blind SQL Injection을 이용한 DB 추출 공격

 

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

 

  1. SQL Injection 작동 여부
  2. SELECT 문구 사용 가능한지 확인
  3. 공격 Format 만들기
  4. DB 이름 찾기
  5. TABLE 이름 찾기
  6. COLUMN 이름 찾기
  7. DATA 추출

 

[1] SQL Injection 작동 여부

 

실습용 웹 어플리케이션

 

  Blind SQL Injection 공격에 사용될 실습용 웹 어플리케이션으로서 ID 중복 검사 기능을 가진 프로그램이다. ID를 입력하면 해당 ID가 DB에 존재하는지 확인하여 존재여부에 대한 결과를 출력한다. 

 

  SQL Injection이 작동하는지 확인하기 위해 해당 기능에 쓰인 쿼리문에 맞춰 항등원의 역할을 하는 쿼리문을 입력한다.

 

 

  입력 결과 정상적으로 작동함으로써 SQL Injection 공격이 가능한 것을 확인하였다.

 

[2] SELECT 문구 사용 가능한지 확인

 

 

  쿼리문 삽입 시 select 구문이 적용되는지 테스트한 결과 정상 작동됨을 확인하였다.

 

[3] 공격 Format 만들기

 

  Blind SQL Injection 공격에 쓰이는 Format을 만들어 반복 작업을 하기 쉽도록 한다. 

 

normaltic' and (ascii(substr((__'입력할 쿼리문'__),1,1)) > 0) and '1'='1

 

[4] DB 이름 찾기

 

 

  DB의 이름을 찾는 쿼리문은 select database()로 Format에 넣어 삽입한 결과, 'blindSqli'라는 DB를 찾아냈다.

 

[5] TABLE 이름 찾기

 

 

  테이블은 'flagTable, member' 총 두 테이블을 찾아냈으나 flagTable 테이블에 한해서만 공격을 진행한다.

  

[6] COLUMN 이름 찾기

 

 

  flagTable에서 'idx, flag' 총 두 컬럼을 찾아냈으나 flag 컬럼에 한해서만 공격을 진행한다.

  

[7] DATA 추출

 

 

  flagTable 테이블 내에는 하나의 데이터만 존재하였다. 그 데이터는 문제의 플레그를 나타낸다.