feroxbuster 공격 차단 — 내 EC2 서버를 죽인 범인을 잡았다 (2026)

feroxbuster 공격 차단 — 내 EC2 서버를 죽인 범인을 잡았다 (2026)

feroxbuster 공격 차단 Apache 접속 로그에서 발견한 feroxbuster User-Agent

1부에서 OOM Kill로 서버가 뻗었을 때 Swap 추가하고 MySQL 튜닝해서 급한 불을 끈 이야기를 했습니다. 서버는 살아났는데, 한 가지 찜찜한 게 남아있었습니다. “도대체 왜 메모리가 갑자기 부족해진 거지?”

Cloudflare 기준 Unique Visitors가 400명대였습니다. t3.small(2GB)에서 감당 못 할 수준이 아닙니다. 그런데 서버가 하루에 2~3번씩 죽는다? 뭔가 이상해서 Apache 접속 로그를 열어봤습니다. 거기서 범인을 찾았습니다. feroxbuster라는 놈이었습니다.

Apache 로그를 열었더니 범인이 보였다

OOM Kill이 발생한 시간대의 접속 로그를 분석했습니다. “이 시간에 누가 들어왔나?” 확인하는 명령어입니다.

grep "13/Feb/2026:00:0\|13/Feb/2026:00:1[01]" /var/log/apache2/access.log.1 | awk '{print $1}' | sort | uniq -c | sort -rn | head -5

결과가 이랬습니다.

199 44.251.91.146
  3 ::1

나머지 3건은 Apache 내부 요청(::1)이니까, 사실상 44.251.91.146이라는 IP 하나가 서버를 죽인 겁니다. 그래서 이 IP가 뭘 했는지 찾아봤습니다.

grep "44.251.91.146" /var/log/apache2/access.log.1 | head -10
44.251.91.146 - "GET / HTTP/1.1" 200 198291 "-" "feroxbuster/2.13.0"
44.251.91.146 - "GET /wp-admin HTTP/1.1" 301 528 "-" "feroxbuster/2.13.0"
44.251.91.146 - "GET /wp-admin/.htaccess... HTTP/1.1" 403 439 "-" "feroxbuster/2.13.0"
44.251.91.146 - "GET /wp-admin/Pipfile HTTP/1.1" 404 144409 "-" "feroxbuster/2.13.0"
44.251.91.146 - "GET /wp-admin/PMA HTTP/1.1" 404 144409 "-" "feroxbuster/2.13.0"
44.251.91.146 - "GET /wp-admin/phpMyAdmin HTTP/1.1" 404 144409 "-" "feroxbuster/2.13.0"

User-Agent에 당당하게 feroxbuster/2.13.0이라고 적혀있었습니다. 본인이 범인이라고 이름표를 달고 다니는 셈입니다.

feroxbuster가 뭔데 서버를 죽이나

feroxbuster는 Rust로 만든 오픈소스 웹 디렉토리/파일 탐색 도구입니다. feroxbuster 공격이 위험한 이유는 보안 전문가들이 취약점 점검 용도로 쓰는 건데, 이걸 악의적으로 남의 서버에 들이미는 사람들이 있습니다.

작동 방식은 단순합니다. 사전에 준비된 파일명/디렉토리명 리스트를 가지고 서버에 “이거 있어? 이거 있어? 이거는?” 하면서 대량의 GET 요청을 쏟아붓습니다. phpMyAdmin, .env, config.php, Pipfile 같은 민감한 파일을 찾아내려는 겁니다.

이번 공격이 서버를 죽인 이유

feroxbuster가 보낸 요청은 총 576건이었습니다. 576건이면 별거 아닌 것 같은데, 문제는 WordPress의 404 페이지에 있었습니다.

존재하지 않는 경로에 접속하면 WordPress가 PHP로 404 페이지를 동적으로 렌더링합니다. 이 404 페이지의 크기가 144KB였습니다. 576건 × 144KB = 약 80MB를 PHP가 동적으로 처리해야 했습니다. 여기에 Apache 프로세스가 요청마다 하나씩 떠서 메모리를 잡아먹으니, 2GB RAM이 순식간에 바닥나고 Linux 커널이 MySQL을 OOM Kill 한 겁니다.

576건의 요청이 2GB 서버를 통째로 죽였습니다. 대형 서비스에서는 티도 안 날 트래픽인데, 소규모 서버에서는 치명적이었습니다.

공격 IP를 whois로 조회해봤더니 44.251.x.x 대역은 AWS IP였습니다. 누군가 본인의 AWS EC2 인스턴스에서 feroxbuster를 돌려서 남의 서버를 스캔한 겁니다.

feroxbuster 공격 차단 1단계 — 공격 IP 차단

범인을 찾았으니 가장 먼저 할 일은 문을 잠그는 겁니다. iptables로 해당 IP를 완전 차단했습니다.

sudo iptables -A INPUT -s 44.251.91.146 -j DROP

차단 확인:

sudo iptables -L -n | grep 44.251
DROP  all  --  44.251.91.146  0.0.0.0/0

이제 이 IP에서 오는 모든 패킷은 서버에 도달하기도 전에 버려집니다.

중요 — iptables 영구 저장

여기서 많은 분들이 실수하는 부분입니다. iptables 규칙은 서버 재부팅하면 초기화됩니다. 재부팅 후에도 차단이 유지되려면 반드시 영구 저장해야 합니다.

sudo apt install iptables-persistent -y
sudo netfilter-persistent save

이걸 빠뜨리면 서버 재시작할 때마다 차단이 풀려서, 같은 IP가 다시 들어옵니다. 저도 처음에 이걸 몰라서 재부팅 후 또 당했습니다.

feroxbuster 공격 차단 2단계 — 스캐너 User-Agent 일괄 차단

IP를 하나 차단했다고 끝이 아닙니다. 같은 도구를 다른 IP에서 실행하면 동일한 공격이 반복됩니다. IP는 무한하지만, 도구의 User-Agent는 정해져 있습니다. 그래서 feroxbuster뿐 아니라 유명한 취약점 스캐너들의 User-Agent를 한꺼번에 차단했습니다.

sudo tee -a /var/www/html/.htaccess << 'EOF'

# Block vulnerability scanners
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (feroxbuster|nikto|sqlmap|dirbuster|gobuster|wfuzz|nuclei) [NC]
RewriteRule .* - [F,L]
EOF

이 한 줄로 차단되는 스캐너 7종

스캐너 정체
feroxbuster 이번에 서버를 죽인 주범. Rust 기반 디렉토리 탐색 도구
nikto 웹 서버 취약점 스캐너의 고전. 아직도 많이 쓰임
sqlmap SQL 인젝션 자동화 도구. DB 털릴 수 있음
dirbuster OWASP 디렉토리 브루트포스 도구
gobuster Go 기반 디렉토리/DNS 탐색. feroxbuster의 선배 격
wfuzz 웹 애플리케이션 퍼징 도구. 파라미터 변조에 특화
nuclei 템플릿 기반 취약점 스캐너. 최근 가장 인기 많은 도구

이 설정의 핵심은 PHP 렌더링 없이 Apache 레벨에서 바로 403을 반환한다는 것입니다. 144KB짜리 404 페이지를 매번 PHP로 렌더링하던 게 원인이었으니, Apache가 직접 차단하면 서버 부하가 거의 0입니다.

Apache 재시작까지 해줘야 적용됩니다.

sudo systemctl restart apache2

feroxbuster 공격 차단 htaccess 스캐너 User-Agent 차단 설정

보너스 — xmlrpc.php도 차단하자

feroxbuster 공격 차단 작업을 하면서 로그를 더 뒤져보니, xmlrpc.php에 접근하는 봇도 꽤 많았습니다. WordPress의 xmlrpc.php는 외부 서비스 연동 용도인데, 실제로는 브루트포스 공격이나 DDoS 증폭 공격에 가장 많이 악용되는 경로입니다.

쓸 일이 없으면 막아두는 게 맞습니다.

sudo tee -a /var/www/html/.htaccess << 'EOF'

# Block xmlrpc (frequently exploited attack vector)
<Files xmlrpc.php>
    Require all denied
</Files>
EOF

빠진 SSL 인증서 적용하기

서버 보안 점검을 하다 보니, amlife 서브도메인에 SSL 인증서가 빠져있는 걸 발견했습니다. HTTPS가 안 되면 브라우저에 "안전하지 않음" 경고가 뜨고, 구글 SEO 점수에도 불이익이 있습니다. Let's Encrypt로 무료 SSL을 바로 적용했습니다.

sudo certbot --apache -d amlife.pearsoninsight.com
Successfully received certificate.
Congratulations! You have successfully enabled HTTPS on https://amlife.pearsoninsight.com

certbot이 Apache 설정까지 자동으로 잡아주기 때문에 명령어 한 줄이면 끝입니다. 인증서는 90일마다 갱신이 필요하지만 certbot이 자동 갱신 스케줄을 등록해주니 신경 쓸 필요 없습니다.

Google Analytics 4 연동 — 이제 누가 들어오는지 제대로 보자

이번 장애를 겪으면서 느낀 건, Apache 로그와 Cloudflare Analytics만으로는 부족하다는 것입니다. "누가, 어디서, 어떻게 들어와서, 뭘 하다가 나갔는지"를 알아야 공격과 일반 트래픽을 구분할 수 있습니다.

Google Analytics 4(GA4)를 연동하면 이런 것들을 볼 수 있습니다.

  • 사용자의 연령대, 성별, 관심사
  • 국가/도시별 접속 현황
  • 모바일/PC 비율
  • 유입 경로 (검색, SNS, 직접 접속)
  • 페이지별 체류 시간
  • 실시간 접속자 수

GA4 측정 ID 발급

Google Analytics에 접속해서 계정과 속성을 만들고, 웹 스트림을 추가하면 측정 ID(G-XXXXXXXXXX)를 발급받을 수 있습니다.

HTML 앱에 추적 코드 삽입

월급 계산기 같은 독립 HTML 앱은 WordPress가 아니라서 플러그인을 쓸 수 없습니다. 각 앱의 index.html <head> 태그 바로 뒤에 이 코드를 넣으면 됩니다.

<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>

서버에서 sed 명령어로 한 번에 삽입할 수도 있습니다.

sudo sed -i '/<head>/r /dev/stdin' /var/www/html/tools/salary/index.html << 'EOF'
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
EOF

WordPress 블로그는 플러그인으로

워드프레스 블로그는 Site Kit by Google 플러그인을 설치하면 코드 수정 없이 GA4가 연동됩니다. 관리자 → 플러그인 → 새로 추가 → "Site Kit by Google" 검색 → 설치 → Google 계정 연동하면 끝입니다.

GA4 데이터는 적용 후 24~48시간부터 수집되기 시작합니다.

1부 + 2부 전체 대응 과정 요약

1부 — 긴급 대응

순서 조치 목적
1 AWS 콘솔에서 인스턴스 중지 후 시작 먹통 서버 복구
2 Swap 2GB 추가 OOM Kill 방지
3 MySQL 메모리 제한 (128MB) 메모리 사용량 절감

2부 — 원인 분석 및 보안 강화

순서 조치 목적
4 Apache 로그 분석으로 공격 IP 식별 장애 원인 파악
5 iptables로 공격 IP 차단 + 영구 저장 동일 IP 재공격 방지
6 .htaccess로 스캐너 UA 7종 차단 도구 기반 공격 일괄 차단
7 xmlrpc.php 접근 차단 WordPress 공격 벡터 제거
8 SSL 인증서 적용 HTTPS 보안 및 SEO
9 GA4 추적 코드 삽입 사용자 분석 환경 구축

마무리 — 576건의 요청이 서버를 죽이는 세상

이번 일로 배운 게 있습니다. 작은 서버라고 아무도 공격하지 않을 거라고 생각하면 오산입니다. 봇은 IP 대역을 무차별로 스캔합니다. 내 서버가 작든 크든, 인터넷에 노출된 순간 공격 대상이 됩니다.

대형 서비스에는 WAF, Auto Scaling, 전담 보안팀이 있어서 feroxbuster 576건 정도는 티도 안 납니다. 하지만 t3.small 2GB 서버에서는 스캐너 봇 하나가 서버를 통째로 죽일 수 있습니다.

소규모 서버를 운영하고 있다면 세 가지만 기억하세요.

  • Swap은 필수 — 메모리가 부족할 때 서버가 죽지 않고 버틸 수 있는 마지막 안전망입니다
  • 접속 로그를 보세요 — 누가 어떤 목적으로 들어오는지 파악해야 대응할 수 있습니다
  • 알려진 스캐너는 선제적으로 차단하세요 — feroxbuster 공격 차단은 .htaccess 한 줄이면 됩니다
  • feroxbuster 공격 차단은 어렵지 않습니다

관련 글도 참고하세요.

댓글 남기기