[VAPT Report] 2차 SQL Injection을 통한 전체 계정 정보 유출 및 변조
1. Executive Summary
본 보고서는 PHP 기반 회원 시스템에서 발견된 2차 SQL Injection(Second-order SQLi) 취약점을 정리합니다. 회원가입 단계에서 악의적인 SQL 구문이 포함된 username이 저장되고, 이후 mypage.php와 mypage_update.php에서 해당 값이 Prepared Statement 없이 쿼리에 직접 삽입 및 실행되어 전체 계정 정보가 유출 및 변경되는 취약점이 확인되었습니다.
주요 발견사항
- 취약점 유형: 2차 SQL Injection
- 심각도: HIGH
- 영향 대상: 마이페이지, 회원정보 수정 기능
- 주요 파라미터:
username
2. 취약점 상세 분석
2.1 취약점 개요
회원가입 시 입력된 username에 SQL 구문이 포함된 값을 그대로 DB에 저장합니다. 이후 저장된 값이 세션을 통해 불러와서 mypage.php와 mypage_update.php에서 SQL 쿼리에 직접 삽입되면, 2차 SQL Injection이 발생합니다.
이 취약점의 핵심은 다음과 같습니다.
- 첫 번째 단계: 악의적인 문자열을 회원가입에서 저장
- 두 번째 단계: 저장된 문자열이 SQL 구문의 일부로 재사용됨
- 결과: 쿼리가 항상 참(True)이 되어 전체 레코드를 조회 또는 수정
2.2 취약 위치
| 위치 | 파라미터 | 영향 | 비고 |
|---|---|---|---|
mypage.php | 세션 username | 사용자 정보 조회 시 SQL Injection | Prepared Statement 미사용 |
mypage_update.php | 세션 username | 회원정보 수정 시 SQL Injection | WHERE 절이 항상 참이 됨 |
2.3 취약 쿼리 예시
- 회원 정보 조회
1
SELECT * FROM logindata WHERE username=''admin' or '1' = '1'
- 회원 정보 수정
1
UPDATE logindata SET password_hash='$password_hash', address='$address' WHERE username=''admin' or '1' = '1'
이 쿼리들은 username 필드에 삽입된 악의적 문자열 때문에 조건절이 항상 참이 되며, 결과적으로 전체 테이블이 대상이 됩니다.
3. Proof of Concept (PoC)
3.1 Step 1: 악의적인 username 계정 생성
회원가입 페이지에서 아래와 같이 SQL 구문이 포함된 username으로 계정을 생성합니다.
- 입력값:
'admin' or '1' = '1
회원가입 페이지. 입력값 이스케이프만 하고 있으므로 특수문자 있는 상태 그대로 DB에 저장됩니다.
이 값은 DB에 문자열로 저장되어, 이후 조회 및 수정 시 재사용됩니다.
3.2 Step 2: 마이페이지 접속
생성한 계정으로 로그인 후 mypage.php에 접속하면, 서버는 세션에 저장된 username 값을 이용하여 사용자 정보를 조회합니다. 이때 다음과 같은 쿼리가 실행됩니다.
- 실행 쿼리:
SELECT * FROM logindata WHERE username=''admin' or '1' = '1'
이 쿼리는 조건절이 항상 참이므로, 테이블의 첫 번째 레코드를 반환하게 됩니다. 그 결과 실제 로그인 계정과 다른 정보가 화면에 표시되며, SQL Injection이 확인됩니다.
3.3 Step 3: 전체 계정 정보 일괄 변경
mypage_update.php에서 비밀번호 또는 주소를 변경하면 아래와 같은 취약 쿼리가 실행됩니다.
- 실행 쿼리:
UPDATE logindata SET password_hash='$password_hash', address='$address' WHERE username=''admin' or '1' = '1'
이 쿼리는 WHERE 조건이 항상 참이 되어 logindata 테이블의 모든 계정이 업데이트됩니다. 공격자는 모든 계정의 비밀번호와 주소를 일괄 변경할 수 있습니다.
4. 영향도 분석
4.1 심각도 평가
- Confidentiality: High
- Integrity: High
- Availability: Medium
이번 취약점은 전체 회원 데이터베이스에 영향을 주며, 모든 계정 정보의 무단 변경이 가능하므로 심각도가 높습니다.
4.2 예상 피해 시나리오
- 공격자가 악의적인
username으로 계정 생성 mypage.php에서 전체 사용자 정보 조회 또는 다른 계정 정보 노출mypage_update.php를 통해 모든 계정의 비밀번호 및 주소 일괄 변경- 결과적으로 서비스 인증 기능이 무력화되어 전체 계정 접근이 가능해짐
4.3 영향 범위
| 영향 영역 | 설명 |
|---|---|
| 전체 회원 정보 | logindata 테이블의 모든 레코드가 대상 |
| 계정 무력화 | 전체 계정 비밀번호 및 주소 일괄 수정 가능 |
| 서비스 신뢰도 | 인증 기능 붕괴로 인해 서비스 신뢰도 저하 |
5. 보안 대응 (Remediation)
5.1 즉시 조치
mypage.php,mypage_update.php에 Prepared Statement 적용register_process.php에도 Prepared Statement 적용을 권고username입력값에 대한 서버 사이드 검증 추가- 세션에서 가져온 값도 쿼리에 직접 삽입하지 않도록 수정
WHERE username = ? LIMIT 1형태로 단일 레코드만 조회/수정
5.2 권장 개선사항
- SQL 메타문자를 제거하는 대신 파라미터 바인딩 사용
- 회원정보 수정 시 세션 기반 사용자 검증 강화
- 쿼리 오류 발생 시 민감 정보 노출 방지를 위한 에러 처리 개선
- DB 연결 시
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)및mysqli_set_charset($conn, 'utf8mb4')적용
5.3 우선순위
| 우선순위 | 조치 | 난이도 |
|---|---|---|
| Critical | Prepared Statement 적용 | 낮음 |
| High | 입력값 검증 강화 | 중간 |
| High | 단일 레코드 조회/수정 제한 | 낮음 |
| Medium | 에러 처리 및 문자셋 설정 | 낮음 |
6. 결론
이번 분석에서는 회원가입 시 악의적인 username이 저장되어 후속 쿼리에서 재사용될 때 2차 SQL Injection이 발생하는 위험을 확인했습니다. 외부 입력값뿐 아니라 DB에서 불러오는 값도 모두 Prepared Statement로 안전하게 처리해야 하며, 입력값 검증과 단일 레코드 제한을 통해 동일한 취약점이 재발하지 않도록 해야 합니다.

