Technote

보안 실무

업로드 디렉터리의 PHP 실행 차단 — 마지막 관문

업로드 취약점은 파일을 올리는 데서 끝나지 않습니다. 올라간 파일이 실행될 때 원격 코드 실행이 됩니다. uploads 에서 PHP 를 못 돌게 하면 그 승격이 끊깁니다.

플러그인의 업로드 검증이 뚫려 PHP 파일이 wp-content/uploads/ 에 올라갔다고 합시다. 여기서 두 갈래로 갈립니다. 서버가 그 파일을 실행해 주면 원격 코드 실행(RCE)이고, 실행을 거부하면 그냥 파일 하나입니다. 이 차단 규칙 한 줄이 그 갈림길입니다.

차단 규칙이 있으면 침투가 승격되지 않는다

nginx 설정

location ~* /wp-content/uploads/.*.php$ {
    deny all;
}

순서가 중요합니다. 이 블록은 PHP 를 fastcgi 로 넘기는 location ~ .php$ 보다 먼저 매칭돼야 합니다. nginx 는 정규식 location 을 선언 순서로 평가하므로, 차단 블록을 PHP 처리 블록 위에 둡니다.

왜 업로드 검증만으로는 부족한가

  • 업로드 검증은 플러그인마다 다시 구현됩니다 — 하나만 실수해도 뚫립니다.
  • 이 차단은 서버에서 한 번 선언하면 모든 플러그인에 적용됩니다.
  • 확장자 위장(shell.php.jpg) · 이중 확장자 같은 우회 시도도, 실행 계층에서 .php 로 끝나는 요청 자체를 거부하면 의미가 없어집니다.

검증

# 아무 텍스트나 담은 php 파일을 uploads 에 두고
curl -s -o /dev/null -w '%{http_code}' https://example.com/wp-content/uploads/probe.php
# 403 이어야 한다 — 200 이면 지금 이 글의 규칙이 없는 것

비슷한 원리로 코드 계층에서 닫아야 할 문이 DISALLOW_FILE_EDIT 입니다. 방어는 서버와 애플리케이션 양쪽에 겹으로 있어야 한 겹이 빠져도 뚫리지 않습니다 — 저희 보안 취약점 해결 작업이 항상 두 계층을 함께 손보는 이유입니다.

이 주제의 다른 글

노하우 목록으로

보안 입문

DISALLOW_FILE_EDIT 하나로 막히는 공격 경로

관리자 비밀번호가 한 번 새면, 내장 테마 편집기는 웹셸 설치 화면이 됩니다. 상수 한 줄이 그 최단 경로를 지웁니다.

개발자 · 운영 · 관리자 2분 읽기

₩270,000 · 신청하기