같은 공격자 IP를 HTTP와 SSH 두 갈래로 추적하기

🛡️ 강사 제공 인가된 실습 환경에서 수행

앞선 실습이 “패킷을 만드는 쪽”이었다면 이번은 주어진 pcap을 해석하는 쪽이다. 역할이 정반대다.

pcap이 두 개 주어졌는데 공격자 IP가 같았다. 그래서 두 파일을 따로 보는 대신 한 사람의 행적으로 이어 붙일 수 있었다. 그리고 이 둘은 분석 방법이 완전히 달랐다 — 한쪽은 내용이 다 보이고, 한쪽은 아무것도 안 보인다.

HTTPSSH
분석 파일week01-blue-team-http.pcapngweek01-blue-team-ssh.pcapng
공격자192.168.56.10192.168.56.10 (동일)
피해 대상192.168.56.20192.168.56.20:22
서버Apache/2.4.49 (Ubuntu) ← 취약 버전OpenSSH 8.2p1 (Ubuntu) — 정상

도구는 양쪽 다 tshark(CLI) + Wireshark(GUI)를 썼다.

HTTP — 내용이 다 보이는 쪽

전체 흐름부터 훑기

수천 개 패킷을 하나씩 클릭할 수는 없다. tshark로 HTTP 요청과 연결 시작(SYN)만 뽑아서 뼈대를 먼저 본다.

tshark -r week01-blue-team-http.pcapng \
  -Y 'http.request || tcp.flags.syn == 1' \
  -T fields -e frame.number -e frame.time_relative \
  -e ip.src -e ip.dst -e _ws.col.Protocol -e _ws.col.Info | head -80
  • -Y — 디스플레이 필터
  • -T fields -e ... — 원하는 필드만 추출

tshark로 뽑은 HTTP 요청·SYN 흐름

여기서 요청 URL 패턴만 봐도 의심 패킷이 눈에 띈다. 그 다음에 Wireshark로 넘어가 http.request 필터를 걸고, 의심 패킷을 클릭해 Hypertext Transfer Protocol 을 펼쳐 User-Agent와 요청 URI를 확인한다. [Response in frame: N] 을 클릭하면 그 요청에 대한 서버 응답으로 바로 점프한다.

복원된 공격 시퀀스

순서요청User-Agent응답공격 유형결과
1GET /server-statusnmap NSE-서버 정보 정찰정보 수집
2GET /.envcurl/8.0404민감 파일 탈취실패
3GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwdexploit-checker403Path Traversal실패
4GET /icons/.%2e/.%2e/.%2e/.%2e/etc/passwdexploit-checker막힘Path Traversal (경로 우회)실패
5POST /login (admin/admin)없음401자격증명 공격실패

1. 서버 정찰 — /server-status

Apache 서버 상태 페이지를 요청해 서버 정보를 수집하려는 시도다. User-Agent가 nmap NSE 라 자동화 스캐닝 도구를 쓴 게 그대로 드러난다. 정상 사용자는 이 경로를 절대 요청하지 않는다.

User-Agent에 nmap NSE가 그대로 찍혀 있다

2. 민감 파일 탈취 — /.env

.env 에는 DB 비밀번호와 API 키 같은 게 들어간다. User-Agent가 curl/8.0 이니 명령줄 도구로 직접 던진 요청이다. 응답은 404, 파일이 없어 실패했다.

다만 응답 헤더에서 Server: Apache/2.4.49 (Ubuntu) 가 노출됐다. 공격은 실패했지만 공격자는 버전 정보를 얻어갔다.

404지만 응답 헤더가 서버 버전을 흘렸다

3. Path Traversal — CVE-2021-41773

.%2e. 의 URL 인코딩이다. 그래서 .%2e/../ 를 인코딩으로 우회한 형태고, 실제 의도는 ../../../../etc/passwd 다.

/cgi-bin/ 은 Apache 기본 Alias 디렉터리(CGI 실행 폴더)라 이 취약점의 표준 진입점이다. User-Agent는 exploit-checker — 취약점 점검 도구다. 응답은 403 Forbidden, 접근이 거부됐다.

.%2e/ 로 ../ 를 인코딩 우회한 요청

4. 같은 공격, 다른 입구

3번이 막히자 곧바로 /icons/ 로 같은 공격을 재시도했다. /icons/ 역시 Apache 기본 Alias 디렉터리라 통할 가능성을 노린 것이다. 자동화 도구가 경로 목록을 순회하는 전형적인 패턴이고, 이것도 막혔다.

5. 자격증명 공격 — POST /login

본문은 username=admin&password=admin. HTTP라서 비밀번호가 평문으로 노출된다(HTTPS였다면 암호화됐을 것이다). 기본 계정으로 로그인을 시도했고 응답은 401이다.

여기서 눈에 띄는 건 User-Agent 헤더가 아예 없다는 점이다. 정상 브라우저는 항상 보내므로, 없다는 것 자체가 자동화 스크립트라는 신호다.

POST 본문에 비밀번호가 평문으로 보인다

판단에 쓴 기준들

HTTP 응답 코드

  • 200 OK — 요청 성공. 공격이라면 침해 성공
  • 401 Unauthorized — 인증 실패
  • 403 Forbidden — 접근 거부(파일은 있으나 권한 없음)
  • 404 Not Found — 경로/파일 없음

403과 404를 구분하는 게 중요하다. 404는 “없다”, 403은 “있는데 못 준다”에 가깝다.

User-Agent로 도구 식별

  • 정상: Mozilla/5.0 ... (브라우저)
  • 의심: nmap, curl, sqlmap, nikto, exploit-checker
  • 없음: 자동화 스크립트

정상 로그인과 공격을 가르는 기준

하나만 보고 단정하면 안 되고 정황을 종합해야 한다.

  1. 선행 행위 — 같은 IP가 직전에 공격했는가
  2. 자격증명 — 기본 비밀번호(admin/admin)를 썼는가
  3. User-Agent — 도구 이름이거나 헤더가 없는가
  4. 빈도와 타이밍 — 짧은 시간에 다수 시도했는가

이번 건은 네 가지가 전부 맞아떨어져서 공격으로 판단할 수 있었다.

Path Traversal 과 Shellshock 비교

Path Traversal (CVE-2021-41773)Shellshock (CVE-2014-6271)
취약점 위치Apache 경로 처리Bash 환경변수 파싱
페이로드 위치URL 경로User-Agent 등 HTTP 헤더
방식.%2e/ 인코딩으로 경로 우회() { :; }; 함수 트릭으로 명령 실행
Apache 역할취약점 당사자환경변수 전달 통로 (죄 없음)

같은 HTTP 요청처럼 보여도 어디를 노리는지가 다르다. Shellshock에서 Apache는 피해자가 아니라 전달자일 뿐이다.

SSH — 내용이 하나도 안 보이는 쪽

무엇을 봐야 하나

SSH는 키 교환 이후 모든 패킷이 암호화된다. 비밀번호도 명령어도 볼 수 없다. 그래서 연결 패턴과 메타데이터로 판단해야 한다.

먼저 연결 시도부터 센다.

tshark -r week01-blue-team-ssh.pcapng \
  -Y 'tcp.flags.syn == 1' \
  -T fields -e frame.number -e frame.time_relative \
  -e ip.src -e ip.dst -e tcp.dstport -e _ws.col.Info | head -80

그 다음 SSH 프로토콜 레벨을 본다.

tshark -r week01-blue-team-ssh.pcapng \
  -Y 'ssh' \
  -T fields -e frame.number -e frame.time_relative \
  -e ip.src -e ip.dst -e _ws.col.Info | head -80

암호화돼 있어도 버전 교환은 평문으로 보인다

Wireshark에서는 ssh 필터를 걸고 Info 컬럼의 Client: / Server: 로 방향을 구분한다. Statistics → Conversations → TCP 탭에서 연결 횟수를 세는 게 핵심이다.

Conversations 탭에서 센 연결 횟수와 간격

관찰된 것

시간방향내용
0초Server → ClientServer: SSH-2.0-OpenSSH_8.2p1 Ubuntu
0초Client → ServerClient: SSH-2.0-libssh_0.6
3초(반복)연결 재시도
6초(반복)연결 재시도
9초(반복)연결 재시도

4회 연결, 정확히 3초 간격이다. 매번 연결하고 끊고 다시 연결한다.

왜 의심스러운가

암호화된 트래픽에서 건진 근거는 두 개뿐인데, 둘 다 강하다.

클라이언트가 libssh다. 정상 사용자는 OpenSSH 클라이언트(터미널 ssh 명령)나 PuTTY를 쓴다. 이 트래픽은 libssh_0.6프로그램 제작용 라이브러리다. 사람이 직접 접속한 게 아니라 코드로 자동 접속했다는 신호이고, 브루트포스 도구들이 주로 libssh 기반으로 만들어진다.

간격이 너무 규칙적이다. 0초, 3초, 6초, 9초. 사람은 이렇게 일정한 간격으로 접속하지 않는다. 자동화 스크립트의 전형적인 패턴이다.

알아둔 것들

패킷 방향 — Source가 출발지, Destination이 목적지다. Source 192.168.56.10 이면 공격자가 보낸 것, 192.168.56.20 이면 서버가 응답한 것.

SSH 연결 순서 — TCP 레벨에서는 Client가 먼저 SYN을 보내지만, SSH 프로토콜 레벨에서는 Server가 먼저 버전 정보를 보낸다. ssh 필터를 걸면 Server 패킷이 먼저 보이는 게 이 때문이다(앞의 TCP handshake가 필터에 가려진다). 처음엔 이게 이상해 보였는데 프로토콜 규칙이었다.

성공·실패 추측 — 인증에 실패하면 연결이 금방 끊겨 패킷 수가 적고, 성공하면 이후 데이터 송수신으로 패킷 수가 많아진다. tcp.stream eq 0 필터로 개별 연결의 전체 패킷을 확인할 수 있다.

HTTP와 SSH는 보는 것이 다르다

이 실습의 핵심이 여기 있다.

HTTPSSH
암호화평문암호화됨
패킷 내용URL, 비밀번호까지 다 보임버전 교환 외 전부 Encrypted packet
분석 방법내용(payload) 으로 판단메타데이터(겉정보) 로 판단
판단 근거요청 URL, User-Agent, POST 데이터클라이언트 종류, 연결 빈도·간격·횟수, 지속 시간

HTTP 쪽에서는 .%2e/../etc/passwd 라는 페이로드를 직접 읽고 “Path Traversal 시도”라고 말할 수 있었다. SSH 쪽에서는 무엇을 시도했는지 영원히 알 수 없다. 대신 “libssh로 3초 간격 4회”라는 겉모습만으로 자동화 도구라고 판단했다.

암호화가 공격자를 보호해주는 것 같지만, 행위의 모양은 못 숨긴다. 앞서 정리한 “값은 위조돼도 행위는 드러난다”와 같은 이야기다.

결론과 권고

같은 공격자 192.168.56.10 이 두 갈래로 움직였다.

웹 쪽은 정찰 → 파일 탈취 → Path Traversal → 자격증명 공격 순으로 체계적이었고, 모든 공격이 실패했다. 서버가 403/404/401로 정상 방어했다.

SSH 쪽은 libssh 자동화 도구로 4회 접근을 시도했다. 규모가 작아 소규모 시도나 테스트로 보인다 — 대규모 브루트포스는 초당 수십에서 수백 회다. 암호화 때문에 인증 성공 여부는 확인할 수 없고, 연결 패턴으로 추정할 뿐이다.

SSH 쪽은 단정이 아니라 추정이다. 근거는 두 개다. ① libssh 클라이언트(비표준 자동화 접속) ② 3초 간격의 규칙적 재연결. 내용을 볼 수 없는 이상 이보다 강하게 말할 수 없다.

권고

  1. Apache 업그레이드 — 2.4.49는 CVE-2021-41773 취약 버전이다. 이번엔 막혔지만 버전 자체가 위험하다
  2. HTTPS 적용 — 로그인 시 평문 비밀번호 노출을 막는다
  3. WAF 도입 — User-Agent 기반 스캐너 차단, Path Traversal 패턴 탐지

SSH

  1. fail2ban 도입 — 반복 접속 시도 시 IP 자동 차단
  2. 키 기반 인증 전환 — 비밀번호 인증을 끄면 브루트포스가 무력해진다
  3. 포트 변경 — 기본 22번을 비표준 포트로 옮겨 자동 스캔을 피한다
  4. 접속 IP 화이트리스트 — 허용된 IP만 SSH 접근

공통

  1. 192.168.56.10 지속 모니터링 — 두 프로토콜에서 같은 IP가 잡혔다는 것 자체가 표적 공격의 신호다

공격이 다 실패했다고 “문제 없음”으로 끝내면 안 된다는 게 이 실습의 요지였다. 취약 버전이 떠 있다는 사실은 그대로 남아 있고, 같은 공격자가 두 경로를 두드렸다는 사실도 남는다.