Technote

Security Practical

업로드 디렉터리의 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 입니다. 방어는 서버와 애플리케이션 양쪽에 겹으로 있어야 한 겹이 빠져도 뚫리지 않습니다 — 저희 보안 취약점 해결 작업이 항상 두 계층을 함께 손보는 이유입니다.

More on this topic

All technotes

Security Intro

Hardening starts by counting your administrators

However many doors you close in configuration, eight people holding keys means eight things to protect. A role audit comes before every other hardening step.

Site operators 7 min read

Security Practical

Consent and tracking — the tag that fires first

Collect the minimum, say that you collect it, and honour a refusal. Three lines of principle, and nearly all the failures happen in one place: a tag that…

Marketers 9 min read

₩270,000 · Join the program