[Incident Report] devuser SSH 계정 탈취 & 크립토마이너 제거 기록 (Rocky Linux 9)

2025. 12. 10. 16:40·보안

서버를 운영하다 보면 "설마 잠깐인데 괜찮겠지" 하는 순간이 가장 위험하다는 것을 뼈저리게 느낀 사건이 발생했습니다. 평소 SSH Key 인증만 사용하다가, 내부 설정 이슈로 단 이틀간 Password Authentication을 활성화해두었는데,

그 틈을 타 devuser 계정이 탈취당했습니다.

심지어 기본적인 방어책인 Fail2ban이 동작 중이었음에도, 공격자는 IP를 분산시키는 방식으로 차단을 우회하여 침투에 성공했습니다.

 

즉, 이번 사고는

“원래는 키 로그인만 쓰던 서버에서,
 짧은 시간이라도 패스워드 로그인을 열어두면
인터넷에 노출된 SSH 포트는 곧바로 공격을 맞을 수 있다.”

 

라는 사실을 몸으로 확인한 케이스입니다.

이번 글에서는 침해 사고의 탐지, 로그 분석(IP 추적), 악성코드 제거 및 보안 강화 과정을 정리합니다.

 

목차

  • 1. 사건 개요 (Summary)
  • 2. 이상 징후 포착 (Detection)
  • 3. 공격 로그 분석 (Forensics)
  • 4. 대응 및 조치 (Remediation)
  • 5. 재발 방지를 위한 보안 하드닝 (Hardening)
  • 6. Lessons Learned (회고)

1. 사건 개요 (Summary)

  • 발생 기간: 2025-12-04 ~ 2025-12-05 (약 24시간 내외)
  • 대상 환경: 개인 미니PC 서버 (Rocky Linux 9)
  • 타겟 계정: devuser (일반 사용자 계정)
  • 사고 원인:
    1. 서버 설정 변경을 위해 임시로 SSH Password Login 허용.
    2. 공격자가 Fail2ban 임계치를 교묘히 우회하는 분산 브루트포스(Distributed Brute-force) 공격 감행.
    3. 취약한 비밀번호가 설정된 devuser 계정 탈취.

피해증상

  • CPU 사용률 700% 폭주 (크립토마이닝), 지속적인 악성 프로세스 재생성.
  • devuser 계정으로 실행된 /usr/sbin/httpd -DFOREGROUND 프로세스 다수
  • 프로세스를 kill 해도 몇 초 뒤 다시 살아남

2. 이상 징후 포착 (Detection)

서버 팬 소음이 심해지고 반응 속도가 느려져 확인해보니, 비정상적인 자원 사용이 목격되었습니다.

2.1 CPU 및 프로세스 이상

top 명령어로 모니터링한 결과입니다.

  • 증상: devuser 계정으로 실행된 /usr/sbin/httpd -DFOREGROUND 프로세스가 CPU를 700% 이상 점유.
  • 특이점:
    • 웹 서버(Apache)처럼 위장했으나, 실제 웹 서비스와 무관한 로컬 프로세스.
    • kill -9로 강제 종료해도 즉시 다시 살아남 (Persistence).
    • K3s(Kubernetes) 파드나 컨테이너가 아닌 OS 레벨의 프로세스임이 확인됨.

2.2 끈질긴 생존력 & 지능형 방어 기제 (Persistence & Defense)

단순히 프로세스를 종료하는 것으로는 해결되지 않았습니다. crontab과 숨김 파일을 이용해 지속성을 확보하고 있었으며, 심지어 관리자의 분석을 방해하고 시스템을 마비시키는 로직까지 포함되어 있었습니다.

# devuser 계정의 crontab 확인
$ crontab -l
@reboot /home/devuser/.TmJgu5XDAMLXXX ( 예시 )

확인 결과 @reboot 구문으로 재부팅 시에도 악성 스크립트가 자동 실행되도록 설정되어 있었습니다. 이를 수정하기 위해 crontab -e를 실행했으나, 두 가지 현상이 분석을 방해했습니다.

 

1) 에디터 강제 종료 (Watchdog)

에디터 화면에 진입하여 수정(Insert)을 시도하는 순간, 프로세스가 즉시 강제 종료되었습니다.

위 캡처 화면과 같이 /usr/bin/vi killed; signal 9 메시지가 뜨며 튕겨져 나갔습니다.

 

2) 쉘 명령어 응답 지연 (Resource Exhaustion)

더 심각한 것은 터미널 상태였습니다. 키보드 입력(Echo)과 줄 바꿈은 되는데, 명령어를 입력하고 엔터를 치면 실행이 되지 않거나 한참 뒤에 반응하는 '좀비 상태'가 지속되었습니다.

⚠️ 기술 분석: 왜 이런 현상이 발생했는가?

1. Watchdog(감시견) 프로세스: 악성코드는 백그라운드에서 실행 중인 프로세스 목록을 감시하다가, 관리자가 vi나 crontab 등 분석 도구를 실행하면 즉시 SIGKILL(9) 시그널을 보내 프로세스를 죽이는 방어 로직을 가동 중이었습니다.

2. CPU Starvation(기아 상태): 크립토마이너가 CPU 자원을 700% 이상 독점(Monopoly)하고 있었기 때문에, OS가 새로운 명령어 프로세스(fork/exec)를 생성할 여유 자원이 없어 쉘 입력이 무시되거나 지연되는 현상이 발생한 것입니다.

  • 대응: 일반적인 쉘 환경에서는 수정이 불가능하다고 판단하여, sudo rm -f /var/spool/cron/devuser 명령어로 해당 사용자의 cron 스풀 파일을 직접 삭제하는 강제적인 방식으로 대응해야 했습니다.

3. 공격 로그 분석 (Forensics)

/var/log/secure 로그를 통해 공격자가 언제, 어디서 들어왔는지 역추적했습니다.

# 로그인 성공 로그 검색
grep "Accepted" /var/log/secure | grep devuser

# 로그인 실패 로그 검색
grep "Failed" /var/log/secure | grep devuser

3.1 침입 시점 및 IP

Fail2ban이 있었음에도 불구하고, 공격자는 다수의 IP를 이용해 차단 임계치를 넘지 않도록 조절하거나, 단발성으로 로그인에 성공했습니다.

fail2ban을 회피하기 위해 IP를 계속 바꾸는 봇넷 공격

 

이 캡처는 전체 로그 중 일부 시간대만 보여주는 예시에 불과합니다.

짧은 구간만 보더라도 여러 IP에서 연속적으로 SSH 로그인이 실패하는 것을 확인할 수 있으며,

같은 형태의 Failed password 기록이 하루 기준 수백 건 이상 누적되었습니다.

3.2 공격자 IP 인텔리전스 분석

IP 주소 국가 ISP / Org 분석 내용
8.213.212.xxx 태국(TH) Alibaba Cloud 봇넷 노드. AbuseIPDB 신고 1,200건 이상의 악성 호스팅 IP.
213.209.143.xxx 독일/네덜란드 Moon DC / Virtualine 데이터센터 대역. 공격용으로 자주 악용되는 호스팅 업체의 가상 서버.
45.135.232.xxx 러시아(RU) Proton66 LLC 데이터센터/호스팅 대역. 러시아 상트페테르부르크 기반. 고위험 봇넷 노드.
91.202.233.xxx 러시아(RU) PROSPERO OOO 데이터센터/호스팅 대역. 스팸 및 브루트포스 공격에 자주 사용되는 대역.
💡 분석 결론: 단일 해커가 아닌, 자동화된 글로벌 봇넷(Botnet)이 외부에 공개된 SSH 서비스를 스캔하고 있었으며, Fail2ban 설정을 우회하기 위해 여러 국가의 IP를 돌려가며(Rotating IPs) 무차별 대입 공격을 시도한 것으로 보입니다.

4. 대응 및 조치 (Remediation)

이미 계정이 탈취되었으므로, 해당 계정을 살려두는 것은 위험하다고 판단하여 완전 삭제 및 격리 조치를 수행했습니다.

4.1 프로세스 및 계정 제거

# 1. 악성 프로세스 일괄 종료
sudo pkill -u devuser

# 2. 계정 및 홈 디렉토리 강제 삭제 (가장 확실한 방법)
sudo userdel -rf devuser

# 3. 남아있을지 모를 cron 스풀 삭제
sudo rm -f /var/spool/cron/devuser

4.2 잔여 악성코드 스캔 (Clean-up)

계정 삭제 후에도 시스템 어딘가에 백도어가 심어졌을 가능성을 염두에 두고 전역 스캔을 진행했습니다.

# 이름 패턴으로 숨김 파일 검색 (예: .Tm..., .fbG...)
sudo find / -type f -name ".*Tm*" -o -name ".*fbG*" 2>/dev/null

# httpd 프로세스 상태 재확인
ps aux | grep httpd

확인 결과, 악성 httpd 프로세스는 모두 사라졌으며 시스템 부하도 정상화되었습니다.

5. 재발 방지를 위한 보안 하드닝 (Hardening)

이번 사고의 근본 원인(비밀번호 로그인 허용 + 미흡한 차단 정책)을 해결하기 위해 보안 레벨을 격상했습니다.

5.1 SSH 패스워드 로그인 영구 차단

타협은 없습니다. 설정 편의를 위해 열어두는 일은 이제 없습니다.
/etc/ssh/sshd_config

PermitRootLogin no
PasswordAuthentication no  # 핵심: 비밀번호 로그인 비활성화
PubkeyAuthentication yes

5.2 Fail2ban 정책 강화

기존 Fail2ban이 뚫린 이유는 '너무 관대한 임계치' 혹은 'IP 로테이션' 때문이었습니다. 정책을 더 타이트하게 조정합니다.

# 설정 파일 생성 (기본 설정을 jail.local로 복사) Fail2ban은 원본(jail.conf)을 직접 수정하기보다, 
# .local 파일을 만들어 오버라이드하는 것이 정석입니다.

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vi /etc/fail2ban/jail.local
# [sshd] 섹션 수정 예시 jail.local 파일에서 [sshd] 섹션을 찾아 아래와 같이 값을 변경합니다.

[sshd]
enabled = true
# bantime: 차단 시간 (기본 10m -> 24h로 대폭 상향)
bantime  = 24h
# findtime: 실패 횟수를 카운트할 시간 범위 (10분 내에)
findtime = 10m
# maxretry: 허용 실패 횟수 (기본 5회 -> 3회로 축소)
maxretry = 3
# 서비스 재시작 및 적용 설정을 변경했다면 반드시 서비스를 재시작해야 적용됩니다.

sudo systemctl enable --now fail2ban
sudo systemctl restart fail2ban
bantime = -1로 설정하면 영구 차단(Permanent Ban)도 가능하지만, 관리자가 실수로 차단될 위험이 있으므로 24시간으로 설정했습니다.

5.3 방화벽(Firewall) 국가별 차단 (GeoIP) 적용

로그 분석 결과 공격의 99%가 해외 IP(태국, 독일, 러시아 등)에서 들어오고 있었습니다.

따라서 모든 IP를 허용하는 대신, "대한민국(KR) IP 대역에서만 SSH 접근을 허용"하고

해외 트래픽은 원천 차단하는 GeoIP 방식을 적용하여 편의성과 보안의 균형을 맞췄습니다.

# 1. ipset 설치 및 대한민국 IP 대역 추가
sudo dnf install ipset -y
# (korea.ipset 파일에 국내 IP 대역 리스트업 후 적용 과정 생략)

# 2. 방화벽 규칙: 대한민국(KR) 소스만 SSH 허용
sudo firewall-cmd --permanent \
  --add-rich-rule='rule family="ipv4" source ipset="korea" service name="ssh" accept'

# 3. 그 외 해외 IP의 SSH 접근은 Drop
sudo firewall-cmd --permanent \
  --add-rich-rule='rule family="ipv4" service name="ssh" drop'

6. Lessons Learned (회고)

단순한 해킹 사고였지만, 시스템 운영 측면에서 많은 시사점을 남겼습니다.

  • Security Misconfiguration: "작업 편의성"을 위해 보안 원칙(Password Login 비활성화)을 어긴 것이 사고의 시발점이었습니다. 인터넷에 노출된 퍼블릭 서버에서 비밀번호 인증은 언제 뚫려도 이상하지 않은 상태임을 인지해야 합니다.
  • Layered Security의 필요성: 단일 보안 솔루션(Fail2ban)에 의존하는 것은 위험합니다. 이번 사례처럼 Application 레벨(Fail2ban)을 우회하는 공격에 대비해 Network 레벨(Firewall)과 Auth 레벨(SSH Key)에서 중첩 방어가 필수적입니다.
  • Monitoring & Logging: CPU 스파이크 같은 하드웨어 지표뿐만 아니라, 보안 로그(/var/log/secure) 모니터링이 병행되어야 정확한 트러블슈팅이 가능합니다.

이번 일을 계기로 "Zero Trust" 관점에서 서버 접근 제어를 전면 재설계했습니다. 리눅스 서버를 운영하시는 분들께 좋은 반면교사가 되었으면 합니다.

 

저작자표시 (새창열림)

'보안' 카테고리의 다른 글

주통기 W-01, W-02, W-04, W-06을 점검하는 스크립트작성  (0) 2024.12.15
Hydra를 이용한 윈도우 서버 Password Guessing 공격 후 RDP 연결  (0) 2024.12.13
Privilege Escalation: Exploitation for Privilege (권한 상승 실습)  (2) 2024.10.17
DNS 스푸핑 공격 실습  (1) 2024.10.11
Password Cracking (john the ripper)  (0) 2024.09.24
'보안' 카테고리의 다른 글
  • 주통기 W-01, W-02, W-04, W-06을 점검하는 스크립트작성
  • Hydra를 이용한 윈도우 서버 Password Guessing 공격 후 RDP 연결
  • Privilege Escalation: Exploitation for Privilege (권한 상승 실습)
  • DNS 스푸핑 공격 실습
not cozy
not cozy
not cozy 님의 블로그 입니다.
  • not cozy
    준
    not cozy
  • 전체
    오늘
    어제
    • 분류 전체보기 (12)
      • 보안 (6)
      • 클라우드 (5)
        • CI CD 자동화 블로그 배포 서비스 (0)
        • AWS (2)
      • 인프라 (0)
      • 프로젝트 (1)
      • 일상 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
not cozy
[Incident Report] devuser SSH 계정 탈취 & 크립토마이너 제거 기록 (Rocky Linux 9)
상단으로

티스토리툴바