페이로드를 외우지 말고 무엇이 막혔는지부터 나누기
SQL Injection Bypass는 입력값을 막는 필터가 걸린 환경에서 차단되는 요소와 아직 쓸 수 있는 SQL 문법을 분석해 우회 가능성을 확인하는 과정이다.
반드시 허가된 실습 환경에서만 테스트한다.
무엇이 우회 방법을 결정하는가
DBMS 종류
DBMS마다 지원하는 문법과 함수가 다르다. MySQL, MariaDB, PostgreSQL, MSSQL, Oracle 중 무엇인지에 따라 다음이 달라진다.
- 주석 문법
- 문자열 연결 방식
- 사용 가능한 함수
- 형 변환 방식
- 공백이 필요한 위치
입력값이 들어가는 위치
사용자 입력이 쿼리의 어디에 삽입되는지 확인해야 한다. 문자열 영역, 숫자 영역, 조건식, 정렬문, 테이블·컬럼명 중 어디냐에 따라 접근이 완전히 달라진다.
문자열 영역이라면 따옴표를 닫아야 하지만, 숫자 영역이면 따옴표 없이 조건식을 쓸 수 있다.
WHERE id = '사용자 입력'
WHERE id = 사용자 입력
이 둘을 구분하는 게 첫 갈림길이다.
필터가 막는 것들
문자 — 공백, 작은따옴표 ', 큰따옴표 ", 등호 =, 괄호 (), 쉼표 ,, 주석 문자, 세미콜론 ;
키워드 — OR, AND, SELECT, UNION, FROM, WHERE, information_schema, 그리고 LENGTH·SUBSTRING 같은 함수명
분석 관점 두 가지
무작정 페이로드를 여러 개 넣지 말고 두 가지를 중심으로 본다.
어떤 요소가 차단되는가
입력값을 한 번에 많이 바꾸지 말고, 문자나 키워드를 하나씩 추가하며 확인한다.
- 정상적인 값 입력
- 작은따옴표 추가
- 공백 추가
- 주석 추가
- 논리 연산자 추가
이렇게 해야 정확히 어느 부분에서 필터가 동작했는지 알 수 있다.
어떤 문법이 여전히 살아 있는가
특정 문자가 막혀도 다른 문법이나 연산자는 살아 있을 수 있다. 대소문자 구분 여부, 공백 대체 가능 여부, 주석 사용 가능 여부, 비교 연산자 사용 가능 여부, 대체 함수 사용 가능 여부, 인코딩된 값 사용 가능 여부를 확인한다.
응답을 비교하는 법
Burp Suite의 Repeater를 쓰면 입력값에 따른 응답 차이를 비교하기 쉽다. 볼 것은 이렇다.
- 로그인 성공 또는 실패
- 화면에 표시되는 메시지
- HTTP 상태 코드
- 응답 본문의 길이
- 페이지 내용의 변화
- 리다이렉트 여부
- 데이터베이스 오류 메시지
- 응답 시간
내용이 비슷해 보여도 길이나 상태 코드가 다르면 내부 처리 결과가 달라졌을 가능성이 있다.
우회 개념들
주석
주석은 문장 뒷부분을 무시시키거나, 일부 환경에서 공백 역할을 하게 쓸 수 있다.
--
#
/* 주석 */
DBMS마다 지원 문법이 다르다. MySQL에서 -- 주석은 뒤에 공백이나 제어 문자가 필요하고, # 은 주로 MySQL 계열에서 쓰인다. /* */ 는 여러 DBMS에서 블록 주석으로 통한다.
서버가 입력값 뒤에 따옴표나 추가 조건을 붙이는 경우, 주석으로 이후 문장을 무시시킬 수 있다.
인라인 주석으로 공백 대체
공백이 차단된 경우 일부 위치에서는 블록 주석을 공백처럼 쓸 수 있다.
UNION/**/SELECT
다만 키워드를 중간에서 쪼개는 방식은 항상 되는 게 아니다.
UN/**/ION
주석이 키워드 사이의 공백으로 처리되면 UN ION 이라는 별개의 토큰이 되어 문법 오류가 난다. 실제 DBMS의 파싱 방식과 필터의 정규화 방식을 확인해야 한다.
작은따옴표 차단
먼저 현재 입력 위치가 숫자형인지 확인한다. 숫자형이면 따옴표 자체가 필요 없다.
그 외에는 문자 코드를 반환하는 함수, DBMS가 지원하는 문자열 생성 함수, 16진수 형태의 문자열 표현, 형 변환 기능을 검토한다.
Base64는 인코딩일 뿐이다. 데이터베이스에서 다시 디코딩하는 함수나 로직이 존재해야 의미가 있다. 단순히 Base64로 바꾼다고 자동으로 필터가 우회되지 않는다.
공백 차단
블록 주석 /**/, 탭, 줄바꿈, 괄호, DBMS가 공백으로 인식하는 다른 제어 문자를 확인한다.
UNION/**/SELECT
URL 요청에서는 공백이나 제어 문자가 URL 인코딩된 형태로 전달되므로, 브라우저와 서버가 값을 어떻게 디코딩하는지도 봐야 한다.
논리 연산자 차단
필터가 대소문자를 구분한다면 OR / or / oR 의 반응이 다를 수 있다.
일부 DBMS에서는 || 나 && 가 논리 연산자로 해석된다. 하지만 의미가 설정에 따라 달라진다 — || 는 어떤 DBMS에서는 논리 OR이지만 다른 DBMS에서는 문자열 연결 연산자다.
키워드 내부에 주석을 넣는 O/**/R 같은 방법은 일반적으로 문법 오류가 난다. 단순 암기보다 실제 DBMS에서 유효한 구문인지 확인하는 게 중요하다.
문자열 기반 필터
필터가 특정 문자열을 단순 검색해서 차단한다면 대소문자 변형, 문자열 연결, 문자 코드 함수, 부분 문자열 조합, DBMS별 대체 메타데이터 조회 방식을 확인한다.
information_schema 가 차단돼 있어도 DBMS 종류와 권한에 따라 다른 메타데이터 조회 방법이 있을 수 있다. 단, 대소문자 변형은 필터가 대소문자를 구분할 때만 효과가 있다.
함수 차단
같은 목적을 수행하는 다른 함수를 찾는다.
| 목적 | 대표 함수 예시 |
|---|---|
| 문자열 길이 확인 | LENGTH, CHAR_LENGTH, LEN |
| 문자열 일부 추출 | SUBSTRING, SUBSTR, MID |
| 문자 코드 확인 | ASCII, ORD |
| 문자열 연결 | CONCAT, || |
함수명이 문자열로 검색돼 차단된다면 대소문자 변형, 동등한 다른 함수, 스키마·네임스페이스 지정, 연산자나 형 변환 문법으로의 대체를 검토한다. 함수명 중간에 주석을 넣는 방법은 함수명이 분리되어 문법 오류가 날 수 있다.
등호 차단
= 가 막히면 다른 비교 문법을 쓴다.
LIKE IN BETWEEN IS NULL IS NOT NULL
LIKE 의 와일드카드는 %(0개 이상의 문자)와 _(정확히 한 개의 문자)다.
name LIKE 'adm%'
실습 진행 순서
- 정상 요청 확보 — 아무 변조 없는 요청과 응답을 저장해둔다
- 입력 위치 파악 — 문자열인지 숫자인지, 어느 SQL 구문에 삽입되는지 추측
- 특수문자 반응 확인 — 따옴표, 공백, 괄호, 주석, 등호를 하나씩 넣으며 응답 비교
- 키워드 반응 확인 —
OR,AND,SELECT,UNION을 개별 테스트 - 필터 방식 추측 — 정확한 문자열 일치 / 대소문자 무시 일치 / 정규표현식 / 특정 문자 제거 / 서버 측 문법 검사 / WAF 중 어느 쪽인지
- 우회 문법 검증 — 상태 코드, 응답 길이, 성공·실패 메시지, 화면 내용, 처리 시간을 비교
핵심
SQL Injection Bypass의 핵심은 우회 문자열을 많이 외우는 게 아니다.
- 어떤 DBMS를 쓰는지 파악한다
- 입력값이 SQL 문의 어디에 들어가는지 확인한다
- 어떤 문자와 키워드가 차단되는지 하나씩 테스트한다
- 차단되지 않은 유효한 SQL 문법을 찾는다
- 요청과 응답의 차이를 근거로 가설을 검증한다
- 그 문법이 실제 DBMS에서도 유효한지 확인한다
즉 무엇이 막혔는지와 무엇이 아직 동작하는지를 분리해서 분석하는 것이 가장 중요하다.