UNION SQL Injection

gyub·2025년 5월 13일
0

모의해킹 스터디

목록 보기
12/31

SQL injection은 데이터를 사용하는 곳에서 작성된 SQL문에 다른 SQL문을 주입해 원하는 결과를 얻어내는 공격입니다

SQL injection에는 여러가지 방법이 있는데요,

이번엔 UNION을 활용한 SQL Injection을 알아보겠습니다

그럼 먼저 UNION이 무엇인지 알아보아야겠죠?

🔎 UNION

여러 개의 SELECT문을 합쳐서 하나의 결과 테이블을 보여주는 방법

UNION을 사용하는 방법은 아래와 같습니다

형태
SELECT [컬럼명1, 컬럼명 2 ...] FROM [table 명] WHERE [조건] UNION SELECT [컬럼명1, 컬럼명 2 ...] FROM [table 명] WHERE [조건]
ex) SELECT id FROM member UNION SELECT pass FROM member

그럼 실제로 union 쿼리를 실행해볼까요?

account라는 테이블의 username 컬럼과 1이라는 데이터를 합쳐서 보려고 하면 아래와 같이 sql 쿼리를 작성할 수 있습니다

이번엔 account 테이블의 username, name 컬럼과 'haechan', '이동혁' 이라는 데이터를 합쳐서 보는 query를 작성해보겠습니다

이렇게 union은 여러개의 select 쿼리 실행결과를 합쳐서 보여줍니다


그런데 UNION에서 꼭‼️ 지켜야 할 것이 있습니다

UNION은 여러 개의 SELECT 쿼리 결과를 한 테이블의 형태로 합쳐서 보는 것이기 때문에 각 SELECT 문의 컬럼 개수가 일치해야 합니다

예를 들어서 2개의 SELECT 문을 UNION으로 합친다면

(SELECT ~ FROM ~ WHERE ~) UNION (SELECT ~ FROM ~ WHERE ~) 의 UNION 앞 부분 SELECT 문의 컬럼 개수와 뒷 부분 컬럼 캐수가 일치해야 합니다

(SELECT [컬럼 1], [컬럼 2] FROM ~ WHERE ~) UNION (SELECT [컬럼 1], [컬럼 2] FROM ~ WHERE ~)

이렇게 말이에요

🔎 ORDER BY

UNION SQL Injection을 위해 알아야 하는 명령어가 한 가지 있습니다

바로 ORDER BY 인데요, 특정 column을 기준으로 정렬해주는 명령어입니다

ORDER BYSELECT 문의 맨 뒤에 작성합니다

SELECT [컬럼명 1], [컬럼명 2], ... FROM [테이블 명] WHERE [조건] ORDER BY [정렬 기준이 될 컬럼명]
ex) SELECT id, pass FROM account ORDER BY id;

ORDER BY [정렬 기준이 될 컬럼명] 형태에서 [정렬 기준이 될 컬럼명] 대신 인덱스 번호로도 정렬할 수 있습니다

예를 들어 SELECT 할 컬럼이 2개 있고 그 중 첫번째 컬럼으로 정렬하고 싶다면 ORDER BY 1 과 같이 작성할 수 있습니다

SELECT id, pass FROM account ORDER BY 1; 이렇게 작성하면 id 컬럼을 기준으로 정렬이 되는 것입니다

이제 정말 UNION SQL Injection에 대해 알아볼까요?

🔎 UNION SQL Injection

UNION SQL Injection은 왜 하는 걸까요?

서버에서 SELECT 문을 사용하는 곳의 쿼리문은 대체로 아래와 같은 형태일 것입니다

SELECT [컬럼] FROM [테이블] WHERE [조건]

그리고 우리가 SQL문을 주입할 수 있는 곳은 [조건] 부분입니다

즉, 우리는 이미 서버에 작성된 SQL문의 테이블을 벗어난 데이터를 조회할 수는 없습니다

그런데 UNION을 활용하면 SELECT 문을 뒷부분에 추가로 넣을 수 있게 되면서,

서버에 이미 작성된 테이블에서 벗어나 우리가 원하는 테이블의 데이터를 조회할 수 있게 됩니다


이번에는 웹 페이지에 데이터가 출력되는 경우(ex. 게시판)에 원하는 데이터를 출력하는 SQL Injection에 대해 알아보도록 하겠습니다

UNION SQL Injection에는 절차가 있습니다

이 절차에 따라 UNION SQL Injection을 시도해보도록 하겠습니다

1. SQL Injection 포인트 찾기

먼저 SQL Injection이 통하는 곳인지 알아야 합니다

입력창이 데이터베이스를 활용하지 않는 곳이라면 당연히 SQL Injection도 진행할 수 없습니다

내가 공격할 위치가 SQL 쿼리를 사용해야만 하는 곳일지 생각해 본 후, SQL Injection을 시도해야 합니다

SQL Injection을 사용할 수 있다면, 서버의 SQL 쿼리가 어떻게 작성되어 있을 지 형태를 구상해보아야 합니다

만약 검색창이라면, 여러가지 단어들을 검색하고 그 결과를 관찰하며 어떤 입력에서 어떤 결과가 나오는 지 확인하고

이를 바탕으로 쿼리문이 어떻게 구성되어 있을 지 추측합니다

예를 들어, 검색한 단어가 들어간 게임을 출력하는 게임 검색 창이 있다고 합시다

그렇다면 SQL 쿼리문이 아래와 같을 것으로 예상할 수 있습니다

SELECT [게임 이름 컬럼], [기타 게임 관련 데이터 컬럼 등 ...] FROM [게임 정보 테이블] WHERE [게임이름컬럼] LIKE '%[입력받은 검색어]%'

이제 이 추측한 쿼리문을 바탕으로 본격적인 UNION SQL Injection을 진행합니다

2. ORDER BY로 column 개수 찾기

앞에서 UNION은 각 SELECT 문끼리 추출되는 컬럼의 개수를 일치시키는 것이 중요하다고 하였습니다

우리는 UNION을 사용해 SQL Injection을 진행하기 때문에 서버에 작성되어 있는 쿼리문의 컬럼이 몇 개 인지 알아야 합니다

추측한 쿼리문을 다시 한번 살펴볼까요

SELECT [게임 이름 컬럼], [기타 게임 관련 데이터 컬럼 등 ...] FROM [게임 정보 테이블] WHERE [게임이름컬럼] LIKE '%[입력받은 검색어]%'

우리는 여기서 [게임 이름 컬럼], [기타 게임 관련 데이터 컬럼 등 ...] 이 부분에 정확히 몇 개의 컬럼이 있는 것인지 알아야 합니다

이 컬럼의 개수를 알아내기 위해 ORDER BY를 활용할 수 있습니다

SELECT [게임 이름 컬럼], [기타 게임 관련 데이터 컬럼 등 ...] FROM [게임 정보 테이블] WHERE [게임이름컬럼] LIKE '%[입력받은 검색어]%'

위 쿼리문에서 컬럼 이름도, 컬럼이 몇 개 있는 지도 모르지만 ORDER BY 인덱스 방법으로 정렬시킬 수 있습니다

검색어에 %' ORDER BY [인덱스]# 을 입력해,

SELECT [게임 이름 컬럼], [기타 게임 관련 데이터 컬럼 등 ...] FROM [게임 정보 테이블] WHERE [게임이름컬럼] LIKE '%%' ORDER BY [인덱스]#%'

형태가 되도록 만드는 것입니다

만약 컬럼이 4개 였다고 한다면, ORDER BY 1 부터 ORDER BY 4 까지는 정상 작동하지만 ORDER BY 5 를 입력하는 순간부터 에러가 날 것 입니다

왜냐면 컬럼이 4개밖에 없으니 5번째 컬럼으로 정렬하라는 명령은 실행될 수 없기 때문입니다

이렇게 인덱스를 1부터 하나씩 늘려나가며 에러가 발생하는 인덱스를 찾아 컬럼의 개수를 알아냅니다

3. 출력되는 column 위치 찾기

이제 우리는 실제 서버의 SELECT 쿼리문에 몇 개의 컬럼이 선택되고 있는 지 알고 있습니다

그런데 쿼리문에서 선택된 컬럼이 모두 웹페이지에 출력되는 것은 아닙니다

만약 4개의 컬럼이 SELECT 되고 있다고 해도 그 중 몇 개만 실제 페이지에 출력하고 있을 수도 있습니다

그렇다면 UNION을 통해 다른 테이블에서 원하는 데이터를 4개 추출하더라도 페이지에 출력되지 않아 추출한 데이터를 확인하지 못하는 상황이 생깁니다

따라서 4개의 컬럼 중 몇 개의 컬럼이 실제로 출력되고 있는지,

그리고 출력되는 컬럼은 4개의 컬럼 중 몇번째 컬럼들인지 확인해야 합니다


위의 게임 검색 창을 다시 예시로 들어보겠습니다

게임을 검색했더니 게임 이름, 제작사, 평점 3가지 정보가 출력된다고 합시다

그럼 4개의 컬럼 중 3개만 출력이 되고 있는 상황이네요

4개의 컬럼 중 몇 번째 컬럼이 출력되고 있는 지 알아내기 위해 검색창에 %' UNION SELECT 1,2,3,4 를 주입합니다

그럼 SQL의 실행 결과에는 컬럼이 4개인 결과 테이블의 마지막 행 각 컬럼에 1, 2, 3, 4가 추가되어 있을 것입니다

이런 형식으로요

그런데 이 중 웹페이지에 출력된 데이터는 2, 3, 4 밖에 없다고 합시다

그럼 1번째 컬럼은 SELECT 쿼리를 통해 추출되긴 했지만, 실제 페이지에는 출력되지 않는 컬럼입니다

이제 실제 서버의 SQL 문은 4개의 컬럼을 SELECT 하고, 이 4개의 컬럼 중 1번째 컬럼은 웹 페이지에 출력되지 않는다는 것까지 알아냈습니다

4. DB 이름 확인

UNION을 이용해 DB의 다른 중요한 정보를 추출하려면 우선 DB의 이름을 알아야 합니다

DB의 이름은 select database() 를 통해 알 수 있습니다

그렇다면 이 쿼리를 어떻게 주입하면 될까요?

마찬가지로 UNION을 활용해 %' UNION SELECT 1, database(), 3, 4# 를 검색하면 아래와 같은 쿼리가 완성됩니다

SELECT [컬럼1], [컬럼2], [컬럼3], [컬럼4] FROM [테이블] WHERE [게임이름컬럼] LIKE '%%' UNION SELECT 1, database(), 3, 4#%'

1번째 컬럼은 출력되지 않는다고 했으니, 이 쿼리의 결과 테이블 마지막 행에는 데이터베이스 이름과 3, 4가 출력되겠네요

이렇게 DB 이름을 알아냈습니다

5. table 이름 확인

DB 이름을 알아냈으니 이제 해당 DB 안에 어떤 테이블이 있는지 알 차례입니다

어떻게 알 수 있을까요?

mysql에는 INFORMATION_SCHEMA 라는 DB의 메타 데이터(table, column 등의 정보)를 저장하는 시스템 DB가 존재합니다

INFORMATION_SCHEMA 에 DB 안의 table 명을 저장하는 table인 INFORMATION_SCHEMA.TABLES 가 존재합니다

INFORMATION_SCHEMA.TABLES 에는 여러 컬럼이 있는데,

그 중 테이블의 이름을 저장하는 컬럼 이름은 TABLE_NAME , 각 테이블이 속한 DB 명이 저장되는 컬럼 이름은 TABLE_SCHEMA 입니다

자 그렇다면 어떤 DB 안에 어떤 테이블이 있는 지 조회하는 SQL 쿼리는 어떻게 작성하면 될까요?

SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='[해당 DB명]'

이렇게 작성하면 되겠네요

이 SQL문을 UNION을 활용해 게임 검색 쿼리에 잘 끼워넣어, 화면에 테이블 명을 출력해야 합니다

그럼 우리가 검색해야 할 것은 %' UNION SELECT 1, TABLE_NAME, 3, 4 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='[해당 DB명]'# 이 됩니다

이 쿼리를 게임 검색 창에 입력했을 때 서버 내부의 SQL 쿼리는 아래와 같을 것으로 예상할 수 있습니다

SELECT [컬럼1], [컬럼2], [컬럼3], [컬럼4] FROM [테이블] WHERE [게임이름컬럼] LIKE '%%' UNION SELECT 1, TABLE_NAME, 3, 4 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='[해당 DB명]'#%'

이 결과로 결과 테이블의 마지막 부분에 해당 DB에 있는 테이블명들이 쭉 출력될 것입니다

이제 우리는 테이블 명까지 알아냈습니다

6. column 이름 확인

DB 이름과 테이블 이름까지 알았으니 이제 컬럼 명만 알면 정말 SELECT 문을 완성시킬 수 있겠네요

테이블에 있는 컬럼 이름 역시 테이블 이름을 찾을 때처럼 시스템 데이터베이스인 INFORMATION_SCHEMA 에서 찾을 수 있습니다

INFORMATION_SCHEMA 에는 table 내 컬럼 정보들을 저장하는 table인 INFORMATION_SCHEMA.COLUMNS 라는 테이블이 존재합니다

INFORMATION_SCHEMA.COLUMNS 에서 DB의 컬럼 이름들을 저장하는 컬럼 명은 COLUMN_NAME , 각 컬럼이 속한 테이블 정보를 저장하는 컬럼 명은 TABLE_NAME 입니다

그럼 컬럼 이름을 조회하는 SQL문을 어떻게 작성하면 될까요?

SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'

이렇게 작성하면 되겠네요

우리는 이 SQL문을 UNION을 활용해 검색 공간에 잘 끼워 넣어, 웹페이지에서 컬럼 이름들이 출력되도록 만들어야 합니다

그럼 서버 내부의 SQL 쿼리가 아래와 같이 완성되도록 만들어야 겠네요

SELECT [컬럼1], [컬럼2], [컬럼3], [컬럼4] FROM [테이블] WHERE [게임이름컬럼] LIKE '%%' UNION SELECT 1, COLUMN_NAME, 3, 4 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'#%'

그러니까 우리가 검색 창에 입력해야 할 것은 %' UNION SELECT 1, COLUMN_NAME, 3, 4 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'# 입니다

7. 데이터 추출하기

이제 DB 이름, 테이블 이름, 컬럼 이름까지 알았으니 데이터를 추출할 차례입니다

지금까지 알아낸 정보로 SELECT문을 작성하면

SELECT [해당 컬럼 명] FROM [해당 테이블 명] 입니다

예를 들어 알아낸 테이블 명이 member, 알아낸 컬럼 명이 id와 pass라면,

SELECT id, pass FROM member 이렇게 쿼리를 작성할 수 있습니다

이제 이 쿼리를 UNION을 활용해 서버 내부의 쿼리에 잘 끼워넣으면 성공입니다

서버의 쿼리는 select 된 컬럼이 4개이고 그 중 첫번째 컬럼은 웹에 출력이 되지 않으니, 우리가 최종적으로 만들어야 할 쿼리문은 아래와 같습니다

SELECT [컬럼1], [컬럼2], [컬럼3], [컬럼4] FROM [테이블] WHERE [게임이름컬럼] LIKE '%%' UNION SELECT 1, id, pass, 4 FROM member#%'

그렇다면 우리가 원하는 데이터를 출력하기 위해서 검색해야 할 것은 %' UNION SELECT 1, id, pass, 4 FROM member# 가 됩니다


이렇게 웹에 SQL 쿼리의 결과가 출력되는 경우의 UNION SQL Injection에 대해 알아보았습니다

0개의 댓글