회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
Q&A
지식공유
공지사항
DX마켓
통계
로그인 회원가입
고객센터

DX Security — Path Traversal 보안 플러그인

D DX관리자
2026.09.03 01:46(수정됨) 7 0 1



DX Security — Path Traversal 방어 v1.0.0 안내서

DesignOneX CMS Path Traversal 기업 납품 수준 방어 플러그인
PHP 5.6+ · IIS / Apache / Nginx · 공유호스팅 완전 호환
코어·테마·플러그인 정상 동작 완전 보장
코어(functions.php / download.php 등) 수정 없음 — 훅으로만 동작



목차

  1. Path Traversal이란 무엇인가
  2. DXCMS 코어의 현재 방어 수준
  3. 코어가 막지 못하는 것 — 이 플러그인의 역할
  4. 설치 방법
  5. 방어층 상세 설명
    • PT1. 강화된 Canonical Path 검증 API
    • PT2. PHP Wrapper 차단
    • PT3. Double / Triple Encoding 우회 차단
    • PT4. NULL Byte 차단
    • PT5. Windows 경로 공격 차단
    • PT6. WAF — 요청 Path Traversal 패턴 탐지
    • PT7. 보안 감사 로그
  6. WAF 설계 원칙 — 왜 차단하지 않는가
  7. 보안 로그 읽는 법
  8. 보안 강점 요약 — 공격 테스트 결과
  9. 개발자 API 가이드
  10. 자주 묻는 질문


1. Path Traversal이란 무엇인가

사용자가 입력한 경로를 이용하여 서버가 허용된 디렉토리 밖의 파일에 접근하는 공격입니다.


공격 시나리오

취약한 코드:
  $file = $_GET['file'];
  readfile('/var/www/uploads/' . $file);

공격 URL:
  ?file=../../etc/passwd
  
실제 접근 경로:
  /var/www/uploads/../../etc/passwd
  → 정규화 후: /etc/passwd
  → 서버 비밀번호 파일 노출


다양한 우회 기법

기본:         ../../../etc/passwd
백슬래시:     ..\..\..\etc\passwd
URL 인코딩:   %2e%2e%2fetc%2fpasswd
Double 인코딩: %252e%252e%252fetc%252fpasswd
NULL Byte:    ../../etc/passwd%00.jpg
PHP Wrapper:  php://filter/read=string/resource=../../config.php
Phar:         phar://uploads/evil.zip/evil.php
UNC Path:     \\server\share\evil.php (Windows)
혼합:         ..%2f..%5c..%2fetc/passwd


Path Traversal → RCE 연계

Path Traversal
      ↓
PHP 파일 접근 (LFI)
      ↓
include('/uploads/evil.jpg')  ← evil.jpg 안에 PHP 코드
      ↓
원격 코드 실행 (RCE)


2. DXCMS 코어의 현재 방어 수준

코어 소스를 직접 분석한 결과입니다.


코어의 강점 — 이미 잘 구현된 것

dx_path_inside() 함수 (core/functions.php):

function dx_path_inside($path, $base)
{
    $path = dx_realpath($path);  // realpath() + 백슬래시 정규화
    $base = dx_realpath($base);
    if ($path === false || $base === false) return false;
    $base = rtrim($base, '/');
    // IIS/Windows: 대소문자 무시 비교
    if (DIRECTORY_SEPARATOR === '\\') {
        return stripos($path, $base . '/') === 0 || ...
    }
    return strpos($path, $base . '/') === 0 || $path === $base;
}

download.php:

// file_id(DB) 기반 → 사용자가 경로를 직접 입력 불가
// dx_path_inside() 검증 후 readfile()
if (!dx_path_inside($fullPath, DX_DATA.'/uploads') || !is_file($fullPath)) {
    http_response_code(404); exit('파일이 존재하지 않습니다.');
}


DxTheme 스킨 로딩:

// 스킨명을 알파벳/숫자만 허용
$skin = preg_replace('/[^a-z0-9_\-]/', '', $skin);


PluginRegistry, Dispatcher:

  • Registry 기반 로딩 — 외부 입력이 직접 include 경로로 사용되지 않음
  • 업로드 파일명 — CSPRNG 랜덤 파일명으로 저장

코어 자체 평가: 8/10 — 구조적으로 매우 안전



3. 코어가 막지 못하는 것 — 이 플러그인의 역할

❌ 미비점 1: PHP Wrapper 입력 탐지 없음

dx_path_inside('php://filter/read=convert.base64-encode/resource=../../config.php', $base)

→ realpath('php://filter/...') = false
→ dx_path_inside 반환값 = false
→ 차단은 되지만 로그 기록 없음
→ 탐지 안 됨 — 공격 시도 인식 불가


❌ 미비점 2: Double Encoding 우회 탐지 없음

?file=%252e%252e%252fconfig.php
→ 서버 URL decode: %2e%2e%2fconfig.php
→ 코어 처리: realpath(%2e%2e%2fconfig.php) = false (차단됨)
→ 그러나 탐지 로그 없음
→ 공격 패턴 모니터링 불가


❌ 미비점 3: NULL Byte 탐지 없음

?file=../../config.php%00.jpg
→ 코어: realpath 처리 중 %00 포함으로 false 반환 (차단됨)
→ 탐지 로그 없음


❌ 미비점 4: 새 파일 생성 경로 검증 불가

realpath()는 존재하는 파일만 처리 가능
새 파일 경로 (/uploads/new/file.jpg) → realpath() = false → 검증 실패
→ 플러그인 개발자가 새 파일 경로를 안전하게 검증할 표준 함수 없음


4. 설치 방법

(DXCMS 루트)/
└── plugins/
    └── dx-security-path/
        ├── manifest.php
        └── plugin.php
관리자 → 플러그인 → dx-security-path → 활성화


5. 방어층 상세 설명


PT1. 강화된 Canonical Path 검증 API

코어 dx_path_inside()의 기능을 확장한 dx_pt_safe_path() 함수를 제공합니다.


코어 dx_path_inside()와의 차이

기능 코어 이 플러그인
realpath() 검증
Root boundary 확인
Windows 대소문자 처리
PHP Wrapper 사전 차단
Double Encoding 탐지
NULL Byte 차단
Windows 절대경로 차단
UNC Path 차단
파일 미존재 시 부모 디렉토리 검증
보안 로그 자동 기록


PT2. PHP Wrapper 차단

LFI와 결합 시 RCE로 발전하는 가장 위험한 우회 기법입니다.

차단 Wrapper:
  php://      php://filter/read=.../resource=../../config.php
  phar://     phar://uploads/evil.zip/webshell.php
  zip://      zip://uploads/evil.zip#webshell.php
  rar://      rar://uploads/evil.rar#webshell.php
  data://     data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
  file://     file:///etc/passwd
  glob://     glob://uploads/*.php
  expect://   expect://id (RCE 직접 가능)

탐지 방식: 입력값에서 대소문자 무관하게 패턴 검사 (strtolower() 후 비교).



PT3. Double / Triple Encoding 우회 차단

1차 Encoding:  ../       → %2e%2e%2f
2차 Encoding:  %2e%2e%2f → %252e%252e%252f
3차 Encoding:  ...       → %25252e...

탐지 방식:
  1. rawurldecode() 1회 → 결과에서 .. 또는 Wrapper 검사
  2. rawurldecode() 2회 → 결과에서 .. 또는 Wrapper 검사
  → 탐지 시 차단 + 로그


PT4. NULL Byte 차단

공격: config.php%00.jpg
효과: C 라이브러리가 \0에서 문자열 절단
      → config.php만 인식 → PHP 파일 처리

탐지:
  \x00 (바이너리 NULL)
  %00  (URL 인코딩된 NULL)


PT5. Windows 경로 공격 차단

IIS/Windows 환경의 DXCMS에서 특히 중요합니다.

차단 패턴:
  C:\Windows\System32\   Windows 드라이브 절대경로
  C:/Windows/            슬래시 혼합
  \\server\share         UNC Path
  //server/share         슬래시 UNC

Windows Device 이름 차단:
  CON PRN AUX NUL
  COM1~COM9 LPT1~LPT9
  (이 이름들은 파일명으로 사용 시 OS 오동작 유발)


PT6. WAF — 요청 Path Traversal 패턴 탐지

모든 요청의 파일 관련 파라미터를 검사합니다.


검사 파라미터 목록

file, path, dir, folder, document, page, template,
theme, skin, layout, view, include, module, plugin,
load, read, src, source, filename, filepath, name,
target, location


탐지 패턴 (17가지)

../  ..\         기본 Path Traversal
..%2f  ..%5c     URL 인코딩
%2e%2e/          인코딩된 점
%252e            Double Encoding
\x00             NULL Byte
php://  phar://  PHP Wrapper
data://  expect://
./.*\.(php|phtml|phar)  경로탈출+PHP
/etc/passwd  /etc/shadow  Linux 파일
/proc/self               Linux proc
C:\  C:/  \\             Windows 경로


6. WAF 설계 원칙 — 왜 차단하지 않는가

이 플러그인의 WAF는 탐지·로그만 수행합니다. 요청을 차단하지 않습니다.


이유

게시물 내용에 "../" 문자열이 있을 수 있습니다.
  예: "설정파일은 ../config/ 폴더에 있습니다."WAF가 차단하면 정상 게시물 작성 불가

코드 예제 포함 게시물:
  예: "include('../lib/helper.php');"
  → 차단하면 개발 커뮤니티 사이트 운영 불가

URL 파라미터에 경로가 있을 수 있습니다:
  ?redirect=/board/free/../notice  (정상 URL)


실제 차단은 이미 코어가 합니다

코어 dx_path_inside():
  realpath() → root boundary 확인
  → 경로 탈출 시 false 반환 → 파일 접근 거부

이 플러그인의 역할:
  WAF → 탐지·로그 (공격 시도 모니터링)
  dx_pt_safe_path() → PHP Wrapper/Double Encoding 추가 차단
                      + 로그 기록


7. 보안 로그 읽는 법

이벤트 타입

타입 의미
PATH:WAF_PATTERN Path Traversal 패턴 탐지
PATH:WAF_WRAPPER PHP Wrapper 패턴 탐지
PATH:BLOCKED dx_pt_safe_path() 차단
PATH:VALIDATE_BLOCKED dx_pt_validate_only() 차단
PATH:FILENAME_BLOCKED 파일명 검증 차단
PATH:DOWNLOAD_BLOCKED 다운로드 경로 차단
PATH:UPLOAD_FILENAME_BLOCKED 업로드 파일명 차단
PATH:UNUSUAL_FILENAME 비정상 파일명 경고
PATH:BASE_DIR_INVALID 기준 디렉토리 오류
PATH:PARENT_DIR_INVALID 부모 디렉토리 오류


차단 이유 코드

이유 코드 의미
NULL_BYTE NULL 바이트 포함
PHP_WRAPPER:php:// PHP Wrapper 포함
ENCODED_TRAVERSAL URL 인코딩된 ..
DOUBLE_ENCODED_TRAVERSAL Double 인코딩된 ..
DOTDOT_SEGMENT .. 경로 세그먼트
WINDOWS_ABSOLUTE_PATH Windows 드라이브 경로
UNC_PATH UNC 네트워크 경로
WINDOWS_DEVICE_NAME:CON Windows Device 이름
OUTSIDE_ALLOWED_ROOT 허용 루트 밖 경로
PARENT_OUTSIDE_ROOT 부모 디렉토리가 루트 밖


로그 예시

# Path Traversal 시도 탐지
[2026-09-02 09:00:01][PATH:WAF_PATTERN][IP:45.33.x.x][...][UID:0][URI:/api/download]
param=file pattern=/\.\.[\\/]/ val=../../etc/passwd

# PHP Wrapper 시도
[2026-09-02 14:22:10][PATH:WAF_WRAPPER][IP:58.29.x.x][...][UID:5][URI:/api/download]
param=file wrapper=php:// val=php://filter/read=string/resource=../../config.php

# Double Encoding 차단
[2026-09-02 16:45:03][PATH:BLOCKED][IP:103.21.x.x][...][UID:0][URI:/api/upload]
context=file_upload reason=DOUBLE_ENCODED_TRAVERSAL input=%252e%252e%252fconfig.php

# Windows UNC Path 차단
[2026-09-02 20:11:44][PATH:BLOCKED][IP:121.131.x.x][...][UID:1][URI:/admin/file]
context=admin_file reason=UNC_PATH input=\\server\share\evil.php


8. 보안 강점 요약 — 공격 테스트 결과

공격 코어 이 플러그인
../../../etc/passwd ✅ 차단 (realpath) ✅ + 로그
..\..\..\config.php ✅ 차단 ✅ + 로그
%2e%2e%2fpasswd ✅ 차단 ✅ + 탐지 로그
%252e%252e%252f (Double) ✅ 차단 ✅ + 탐지 로그
file%00.php (NULL Byte) ✅ 차단 ✅ + 탐지 로그
php://filter/resource=.. ✅ 차단 ✅ + 탐지 로그
phar://uploads/evil.zip ✅ 차단 ✅ + 탐지 로그
C:\Windows\System32 ✅ 차단 ✅ + 탐지 로그
\\server\share (UNC) ✅ 차단 ✅ + 탐지 로그
존재하지 않는 새 파일 경로 ❌ realpath=false ✅ 부모 디렉토리 검증
정상 이미지 업로드 ✅ 통과 ✅ 통과 (영향 없음)
정상 파일 다운로드 ✅ 통과 ✅ 통과 (영향 없음)


9. 개발자 API 가이드

파일 읽기 경로 검증

// 사용자가 제공한 파일명으로 파일을 읽을 때
$safePath = dx_pt_safe_path(
    DX_DATA . '/uploads',  // 허용 기준 디렉토리
    $_GET['filename'],     // 사용자 입력
    'my_plugin'            // 로그 컨텍스트
);

if ($safePath === false) {
    http_response_code(400);
    exit('허용되지 않는 파일 경로입니다.');
}

// 안전하게 파일 접근
readfile($safePath);


새 파일 생성 경로 검증

// 새 파일을 저장할 경로 검증 (파일이 아직 없음)
$filename = 'report_' . date('Ymd') . '.pdf';
$safePath = dx_pt_safe_path(
    DX_DATA . '/reports',
    $filename,
    'report_gen'
);

if ($safePath === false) {
    exit('잘못된 파일 경로입니다.');
}

file_put_contents($safePath, $pdfContent);


파일명만 검증 (경로 없이)

// 파일명만 빠르게 검증
if (!dx_pt_validate_only($_POST['filename'], 'form_input')) {
    exit('허용되지 않는 파일명입니다.');
}


안전한 파일명 추출

// 사용자 파일명에서 경로 구분자 제거 후 안전한 파일명 반환
$safeName = dx_pt_safe_filename($_FILES['upload']['name'], 'upload');
if ($safeName === false) {
    exit('허용되지 않는 파일명입니다.');
}
// $safeName: basename()만 남은 안전한 파일명


10. 자주 묻는 질문

Q. WAF가 요청을 차단하지 않으면 보안에 문제가 없나요?

코어의 dx_path_inside() + realpath()가 실제 파일 접근 시점에 경로 탈출을 차단합니다. WAF는 공격 시도를 모니터링하는 역할입니다. WAF에서 미리 차단하면 게시물 내용에 경로 문자열이 있을 때 정상 요청도 차단되는 오탐이 발생합니다.


Q. 플러그인을 설치하면 기존 파일 업로드/다운로드에 영향이 있나요?

없습니다. 이 플러그인은 코어 파일을 수정하지 않습니다. dx_pt_safe_path() API는 플러그인 개발자가 직접 호출할 때만 동작합니다. WAF는 탐지·로그만 수행하고 요청을 차단하지 않습니다.


Q. 코어 dx_path_inside()를 대체해야 하나요?

아닙니다. 코어 dx_path_inside()는 잘 설계되어 있습니다. 이 플러그인의 dx_pt_safe_path()는 새로 작성하는 플러그인 코드에서 사용하는 보강 API입니다. 코어 코드는 그대로 사용하면 됩니다.


DX Security — Path Traversal 방어 v1.0.0 — DesignOneX
https://designonex.com
 

라이선스

디자인원엑스 라이선스 참고
https://designonex.com/notice/view/1787577858493247

 

첨부파일 1개 회원전용

댓글1

안졸리니졸리 2026.09.03 11:21
저희같은 비개발자는 공개 게시판 있으면 그냥 쓰기 바쁜데 보안 관련하여 이렇게 영역이 많다니...
새삼 놀랍습니다
보안에 대해서 잘 모르지만 다 살이되고 피가되는 내용인듯 합니다
보안이 많아서 헷갈릴수 있는데 그냥 다운받아서 플러그인 폴더에 넣고 활성화만 시켜주면 알아서 작동하겠죠
이게 DXCMS의 강점이죠 ^^
^___________^
로그인 후 댓글을 작성할 수 있습니다.
Plugin 49
45
전체 회원
1,375
전체 게시글
2,737
전체 댓글
38
오늘 방문
53,476
전체 방문
0
현재 접속
인기글 7일 이내
최신글
최신댓글
내 플레이리스트
플레이리스트가 비어있습니다
스튜디오 게시판에서
플레이리스트에 담기 버튼을
눌러보세요
목록
목록