워드프레스 보안
워드프레스 500 에러의 원인이 해킹이었던 경우: .htaccess의 Order 한 줄
Apache 2.4에서 2.2 문법 Order 구문이 500을 내는 것을 재현하고, 그 .htaccess가 SEO 스팸 해킹이 남긴 흔적이었던 사례와 500을 고치기 전에 확인할 것들을 정리했습니다.
가족 블로그로 쓰던 워드프레스가 어느 날부터 HTTP 500만 돌려줬습니다. 모니터링 도구에는 하루 894번 다운으로 찍혔습니다. 보통 500이면 플러그인 충돌이나 PHP 버전 문제를 먼저 떠올리는데, 이번엔 해킹이 남긴 부작용이었습니다.
그리고 더 곤란한 점이 있었습니다. 500을 고치는 순간 감염된 사이트가 다시 인터넷에 공개됩니다. 그래서 500부터 고치면 안 됐습니다.
500의 직접 원인은 .htaccess 한 줄이었습니다
웹 루트의 .htaccess에 이런 구문이 들어 있었습니다.
Order deny,allow
Deny from all
이건 Apache 2.2 시절 접근 제어 문법입니다. Apache 2.4에서는 Require로 바뀌었고, 옛 문법은 mod_access_compat 모듈이 있어야 읽힙니다. 이 NAS의 Apache 2.4에는 그 모듈이 로드돼 있지 않아서, 파일을 읽다가 모르는 명령이라며 500을 냅니다.
정말 그런지 같은 서버에서 다시 재현해 봤습니다. 빈 테스트 폴더를 만들고 .htaccess만 바꿔 가며 요청했습니다.
| .htaccess 내용 | index.html | t.php |
|---|---|---|
Order deny,allow + Deny from all | 500 | 500 |
Require all denied | 403 | 403 |
같은 의미("모두 막기")인데 옛 문법이면 403이 아니라 500이 납니다. 테스트 폴더는 확인하고 바로 지웠습니다.
그런데 그 .htaccess는 제가 쓴 게 아니었습니다
이 파일이 언제 바뀌었는지 보니 2026년 7월 21일 오후 12시 59분이었습니다. 같은 시각에 바뀐 파일들을 모아 보니 SEO 스팸 공격 한 번에 심긴 것들이었습니다.
index.php가 21KB짜리 난독화 코드(goto로 뒤섞인)로 바뀌어 있었고, 외부 서버(hwb253v11.agentt.best)에서 스팸 콘텐츠를 받아 오게 돼 있었습니다.- 가짜 플러그인 4개:
galex_13c3697f,security-headers-manager-a49be6,wordpress-cache-optimizer,wp-content-filter - 가짜 테마
flavor_f697306b - 진짜 폴더 이름을 흉내 낸 곳에 숨긴 드로퍼:
wp-admin/css/colors/ectoplasm/ectoplasm/,google-site-kit/…/monolog/src/src/처럼 같은 이름을 한 번 더 겹친 폴더
공격자가 자기 파일을 보호하려고 .htaccess를 썼는데, 2.2 문법을 쓰는 바람에 사이트 전체가 500이 된 겁니다. 스팸 페이지를 띄우려던 공격이 오히려 사이트를 멈춰 세운 셈입니다.
파 보니 감염은 세 번이었습니다
| 시기 | 흔적 |
|---|---|
| 2020년 10월 | uploads 안에 파일 업로더와 DB 관리 도구(phpMiniAdmin), 이름이 무작위 8글자인 빈 PHP 파일 |
| 2026년 2월 | uploads/class-wp-cache-9a8e2a14.php — POST 값으로 서버 명령을 실행하는 웹셸 |
| 2026년 7월 | 위의 SEO 스팸 공격. 가짜 관리자 계정 wpenginebot, wphiddenbot와 mu-plugins 안의 로더도 함께 |
어느 경로로 다시 들어왔는지는 확인하지 못했지만, 2020년에 심긴 백도어가 6년 동안 그대로 남아 있었다는 것부터가 문제였습니다. 게다가 이 NAS의 사이트들은 전부 같은 사용자로 PHP를 실행하고 웹 루트 권한도 넓게 열려 있어서, 웹셸 하나로 다른 사이트 파일까지 쓸 수 있는 상태였습니다.
500을 고치기 전에 먼저 볼 것
워드프레스가 갑자기 500이 나는데 최근에 아무것도 바꾼 게 없다면, .htaccess를 고치기 전에 아래부터 확인하는 게 좋습니다.
# uploads 안에 PHP 파일이 있으면 거의 확실히 악성
find wp-content/uploads -name "*.php"
# 자동으로 켜지는 mu-plugins에 모르는 파일이 있는지
ls -la wp-content/mu-plugins/
# 최근 7일 안에 바뀐 PHP 파일
find . -name "*.php" -mtime -7
# 코어 파일이 원본과 같은지: wordpress.org 체크섬과 비교
curl -s "https://api.wordpress.org/core/checksums/1.0/?version=6.9.1&locale=ko_KR"
관리자 계정도 DB에서 직접 봅니다. 화면에 안 보이게 숨긴 계정이 있을 수 있어서입니다.
SELECT u.user_login, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities'
AND m.meta_value LIKE '%administrator%';
저는 이 확인을 마친 뒤, 전체 백업을 떠 두고 악성 파일을 격리했습니다. 그다음 코어와 플러그인을 wordpress.org 원본으로 통째로 바꾸고, 가짜 관리자와 mu-plugins 로더를 지우고, 모든 로그인 세션을 끊고, 보안 키(솔트)를 새로 만들었습니다. .htaccess는 그 뒤에 2.4 문법으로 다시 썼습니다. 글 79개와 첨부 파일 2,443개는 손상 없이 살렸습니다.
500이 사라진 걸 확인한 건 맨 마지막입니다. 순서가 반대였다면 감염된 사이트를 며칠 동안 다시 공개했을 겁니다.
확인한 공식 자료
구현 과정에서 판단 기준을 교차 확인한 공식 문서입니다. 글의 사례와 결론은 운영자가 직접 겪은 작업을 바탕으로 작성했습니다.