콘텐츠로 건너뛰기

[블로그운영] 코어 파일 검증, 있으면 안 되는 파일이 하나 나왔습니다

  • 기준

서버를 옮길 곳을 알아보다가 겸사겸사 코어 파일 검증을 돌려봤습니다. 딱 한 줄이 걸렸습니다.

Warning: File should not exist: wp-includes/theme-compat/header-shell.php

정리하는 개발자 워니즈입니다. 이 글에서는 이 한 줄을 확인하는 방법과, 나왔을 때 어떤 순서로 다뤄야 하는지를 다룹니다.

결론부터 말씀드리면 명령 한 줄이면 끝나고, 대부분은 이걸 한 번도 안 돌려봅니다. 파일이 나오면 지우기 전에 먼저 격리하세요.

워드프레스 코어 파일 검증 절차, 검증, 확인, 격리

왜 코어 파일 검증인가

워드프레스는 배포판마다 모든 코어 파일의 지문을 공개합니다. 이 값은 공식 체크섬 API로 누구나 받아볼 수 있습니다. 그래서 내 서버의 파일과 원본을 비교하면 바뀐 파일원래 없어야 할 파일을 바로 알 수 있습니다.

플러그인으로 하는 보안 검사와 성격이 다릅니다. 그쪽은 알려진 악성 코드 패턴을 찾지만, 코어 검증은 패턴을 몰라도 됩니다. 원본에 없으면 없는 겁니다. 새로 만들어진 파일도 잡힙니다.

정상 파일들 사이에 하나 끼워 넣는 방식은 오래된 수법입니다. 이름도 주변과 비슷하게 짓습니다. 눈으로 훑어서는 절대 못 찾습니다.

제가 걸린 파일도 주변이 전부 header-로 시작하는 디렉터리였습니다. 파일 목록만 봐서는 어색한 구석이 없었습니다. 코어 파일 검증이 아니었으면 앞으로도 못 찾았을 겁니다.

1. 검증 돌리기

WP-CLI가 있으면 한 줄입니다.

cd /경로/wordpress
wp core verify-checksums

정상이면 이렇게 끝납니다.

Success: WordPress installation verifies against checksums.

문제가 있으면 File doesn't verify against checksum(내용이 바뀜) 또는 File should not exist(원본에 없는 파일)가 함께 나옵니다.

참고: 코어만 검사합니다. 테마와 플러그인은 대상이 아닙니다. 그쪽은 뒤에서 따로 훑습니다.

2. 나온 파일을 열지 말고 확인하기

파일이 나왔다면 절대 브라우저로 열어보지 마세요. 주소를 눌러보는 순간 그게 실행입니다.

터미널에서 앞부분만 보고, 위험한 함수가 있는지 세는 정도면 판단이 됩니다.

F=/경로/wordpress/wp-includes/theme-compat/header-shell.php
sudo stat -c '%n size=%s mtime=%y' "$F"
sudo head -c 200 "$F"
sudo grep -c -E 'eval|base64_decode|system|exec|passthru|shell_exec|assert' "$F"

제 경우 파일 첫머리에 자기 이름을 붙인 암복호 루틴이 있었고, 위험 함수가 세 종류 걸렸습니다. 수정 시각은 3년 전이었습니다. 다만 이 시각은 얼마든지 위조할 수 있어서 그대로 믿으면 안 됩니다.

3. 실제로 쓰였는지 로그에서 확인

파일이 있다는 것과 쓰였다는 것은 다릅니다. 웹서버 로그에서 파일명을 세어봅니다.

sudo grep -c 'header-shell' /경로/apache/logs/access_log

제 경우 0건이었습니다. 심어놓고 쓰지 않은 상태였다는 뜻입니다. 다만 로그가 보관된 기간 밖의 호출은 알 수 없으니 “안전했다”가 아니라 “최근 기록에는 없다” 정도로 읽는 게 맞습니다.

4. 지우지 말고 격리

바로 지우고 싶어지는데, 격리를 권합니다. 나중에 어떻게 들어왔는지 따져볼 때 파일 자체가 유일한 단서입니다.

sudo mkdir -p /root/quarantine-$(date +%F)
sudo mv "$F" /root/quarantine-$(date +%F)/header-shell.php.malware
sudo chmod 000 /root/quarantine-$(date +%F)/header-shell.php.malware

웹에서 접근할 수 없는 곳으로 옮기고 권한을 모두 내립니다. 이러면 실행될 수 없으면서 증거는 남습니다.

옮긴 뒤에는 사이트가 멀쩡한지 확인합니다. 코어 파일이 아니었으니 정상이어야 합니다.

curl -s -o /dev/null -w '%{http_code}\n' https://example.com/

5. 같은 계열이 더 있는지 훑기

하나가 나왔다면 다른 곳도 봐야 합니다. 테마와 플러그인 디렉터리를 패턴으로 훑습니다.

sudo grep -rl --include='*.php' -E 'eval\(base64_decode|gzinflate\(base64_decode' \
  /경로/wordpress/wp-content
sudo find /경로/wordpress/wp-content/uploads -name '*.php' -type f

업로드 폴더에 PHP 파일이 있으면 그 자체로 의심 대상입니다. 이미지가 올라가는 곳에 실행 파일이 있을 이유가 없습니다. 저는 두 검사 모두 결과가 비어 있었습니다.

같이 봐야 할 것이 하나 더 있습니다. 계정입니다. 코어 파일이 깨끗해도 권한이 올라간 계정이 남아 있으면 언제든 다시 심을 수 있습니다. 저는 같은 날 가입자 수와 권한 분포를 함께 셌습니다.

코어 파일 검증에 관해 자주 묻는 것

Q. 파일이 나왔으면 이미 뚫린 건가요?<br>파일이 심어졌다는 것까지는 사실입니다. 다만 그게 언제, 어떤 경로였는지는 별개입니다. 서버를 이전하면서 예전 흔적이 그대로 따라온 경우도 있습니다. 로그 확인과 관리자 계정 점검을 함께 해보셔야 합니다.

Q. WP-CLI가 없으면 못 하나요?<br>관리자 화면에서 코어를 같은 버전으로 다시 설치하면 코어 파일은 원본으로 덮입니다. 다만 원본에 없는 파일은 그대로 남습니다. 그래서 검증 쪽이 더 정확합니다.

Q. 코어 파일이 바뀐 것으로 나오면 어떻게 하나요?<br>없어야 할 파일과 다릅니다. 내용이 바뀐 코어 파일은 같은 버전을 다시 설치하면 원본으로 되돌아갑니다. 다만 왜 바뀌었는지는 따로 확인해야 합니다.

Q. 얼마나 자주 돌려야 하나요?<br>저는 이번에 우연히 돌렸다가 발견했습니다. 그게 문제였습니다. 한 달에 한 번, 아니면 플러그인을 새로 설치한 뒤에 돌리는 정도면 충분합니다. 몇 초면 끝납니다.

정리

  • wp core verify-checksums 한 줄로 바뀐 파일과 없어야 할 파일을 함께 잡습니다.
  • 나온 파일은 브라우저로 열지 말고 터미널에서 앞부분만 확인합니다.
  • 로그에서 파일명을 세어 실제로 쓰였는지를 따로 봅니다.
  • 지우지 말고 웹 밖으로 옮긴 뒤 권한을 내립니다. 증거가 남습니다.
  • 하나가 나왔으면 업로드 폴더와 플러그인 쪽도 훑습니다.

오늘 하나만 하신다면, 검증 명령 한 줄만 돌려보세요. 몇 초 걸리고 대부분은 아무 일도 없습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다