
자체 포함형 SSH 허니팟으로, 공격자의 상호작용을 포착하여 구조화된 보안 인텔리전스로 전환합니다.
SSHintel은 Python과 Paramiko로 구축된 경량 SSH 허니팟입니다. 가짜 Linux 셸을 시뮬레이션하여 무단 접근 시도를 기록하고, 자격 증명을 캡처하며, 통제된 환경에서 공격자 행동을 분석합니다.
ls, cd, pwd, cat, echo, grep, find, tree, head, tail, wc, stat, ps, df, free, env, id, whoami 등)--tarpit 모드SSHintel은 완전한 Bash/Linux 셸이 아닙니다. 공격자 텔레메트리를 수집하기 위해 일반적인 명령의 그럴듯한 하위 집합을 시뮬레이션합니다. 명령은 경량 레지스트리를 통해 디스패치되며, 명령을 추가한다는 것은 작은 핸들러 함수를 추가하는 것을 의미합니다.
pip install -r requirements.txt
참고: SSH 호스트 키는 첫 실행 시 자동으로 생성됩니다. 수동으로 키를 생성할 필요가 없습니다.
특정 포트, 사용자 이름, 비밀번호로 허니팟을 실행합니다:
python3 run.py serve --port 2222 --username user1 --password pass123
기본 포트는
2222이고 호스트는0.0.0.0입니다.
허니팟은 첫 실행 시 SSH 호스트 키가 존재하지 않으면 static/server.key에 자동으로 생성합니다. 수동으로 키를 생성할 필요가 없습니다.
tarpit 모드를 활성화하려면:
python3 run.py serve --port 2222 --username user1 --password pass123 --tarpit
SQLite 텔레메트리를 비활성화하려면(JSONL만 사용):
python3 run.py serve --port 2222 --username user1 --password pass123 --no-db
센서 설정은 CLI > 환경 변수 > 구성 파일 > 기본값 순서를 따릅니다.
명시적으로 제공된 CLI 플래그만 다른 소스를 재정의합니다. 이는
serve에 적용되며, 대시보드/쿼리 명령은 자체 CLI 설정을 유지합니다.
Python 3.11 이상에서:
cp sshintel.toml.example sshintel.toml
chmod 600 sshintel.toml
python3 run.py serve
Python 3.8/3.10에서는 의존성이 없는 JSON 등가물을 사용하세요:
cp sshintel.json.example sshintel.json
chmod 600 sshintel.json
python3 run.py serve
배포 전에 복사한 파일을 편집하세요. TOML은 Python 3.11+를 요구하며, 이전
버전에서는 JSON을 사용하라는 명확한 안내와 함께 실패합니다. 명시적인 파일이
없으면 SSHIntel은 현재 디렉터리에서 sshintel.toml, 그다음 sshintel.json을
찾습니다. 다른 파일을 선택하려면 serve --config /path/to/settings.json 또는
HONEYPOT_CONFIG를 사용하세요(--config가 우선). 명시적으로 지정한 파일이
없거나, 파일 형식이 잘못되었거나, 알 수 없는 키가 있거나, 값이 유효하지 않으면
서버나 데이터베이스가 시작되기 전에 실패합니다. 구성 내부의 파일 경로는 구성
파일이 아니라 프로세스 작업 디렉터리를 기준으로 합니다.
| 파일 키 | 환경 변수 | 기본값 |
|---|---|---|
host | HONEYPOT_HOST | 0.0.0.0 |
port | HONEYPOT_PORT (레거시 별칭: PORT) | 2222 |
username | HONEYPOT_USERNAME | user1 |
password | HONEYPOT_PASSWORD | pass123 |
tarpit | HONEYPOT_TARPIT | false |
tarpit_max_seconds | HONEYPOT_TARPIT_MAX_SECONDS | 120 |
max_connections | HONEYPOT_MAX_CONNECTIONS | 50 |
auth_timeout | HONEYPOT_AUTH_TIMEOUT | 60 |
session_idle_timeout | HONEYPOT_SESSION_IDLE_TIMEOUT | 300 |
sensor_id | HONEYPOT_SENSOR_ID | 설정 안 됨 |
db_path | HONEYPOT_DB_PATH | data/sshintel.db |
no_db | HONEYPOT_NO_DB | false |
fetch_payloads | HONEYPOT_FETCH_PAYLOADS | false (예약됨) |
환경 변수 불리언은 true/false, 1/0, yes/no, on/off를 허용합니다.
HONEYPOT_PORT가 PORT보다 우선합니다. 포트는 1–65535여야 하며, 제한과
타임아웃은 양의 정수여야 합니다. 우선순위가 낮은 true 설정을 재정의하려면
--no-tarpit, --db-enabled, --no-fetch-payloads를 사용하세요. 데이터베이스
경로는 기존 --db CLI 플래그를 사용합니다. 페이로드 가져오기는 구현되지
않았습니다. fetch_payloads를 활성화하면 조용히 무시되지 않고 거부됩니다.
로컬 sshintel.toml/sshintel.json 파일은 자격 증명을 포함할 수 있으므로
Git에서 무시되고 Docker 빌드에서 제외됩니다. 대신 구성 파일을 컨테이너에
읽기 전용으로 마운트하세요. Docker는 환경 변수를 직접 사용하며(자격 증명을
셸로 보간하지 않음), 기존 ENV 기본값이 마운트된 파일보다 우선합니다. 필요에
따라 해당 변수를 재정의하거나 명시적인 CLI 플래그를 사용하세요.
SSHintel은 다수의 동시 연결이나 무기한 유지되는 연결로 인한 리소스 고갈을 방지합니다. 이는 CLI를 통해 구성할 수 있습니다:
| 플래그 | 기본값 | 목적 |
|---|---|---|
--max-connections | 50 | 최대 동시 활성 연결 수; 초과 연결은 거부되고 connection_rejected 이벤트로 기록됨 |
--auth-timeout | 60 (초) | SSH 핸드셰이크/인증을 완료하는 데 허용되는 시간; 지연되는 클라이언트는 연결이 끊김 |
--session-idle-timeout | 300 (초) | 인증된 셸의 비활성 타임아웃; 유휴 세션은 종료되지만, 활발히 타이핑 중인 공격자는 절대 종료되지 않음 |
예시:
python3 run.py serve --port 2222 --username user1 --password pass123 \
--max-connections 25 --auth-timeout 30 --session-idle-timeout 300
연결이 너무 많이 열려 있으면 초과 연결은 즉시 닫히고, connection_rejected 보안 이벤트(reason: connection_limit)가 JSONL 로그에 기록됩니다. 지연된 인증은 reason: auth_timeout과 함께 연결 끊김으로 기록되며, 유휴 셸은 reason: idle_timeout으로 종료됩니다.
Tarpit 모드는 공격자의 참여를 유지하기 위해 의도적으로 출력을 느리게 전송하므로, tarpit 배너 루프에는 비활성 타임아웃이 적용되지 않습니다. 그러나 tarpit 세션은 연결 한도에 포함됩니다.
SSHintel에는 SQLite에 저장된 보안 텔레메트리를 시각화하는 로컬 웹 대시보드가 포함되어 있습니다.
python3 run.py dashboard
그런 다음 브라우저에서 http://localhost:5000을 엽니다.
대시보드는 기본적으로
data/sshintel.db에 있는 SQLite 데이터베이스에서 데이터를 읽습니다. 텔레메트리가 수집되도록 허니팟을 먼저 시작한 다음, 대시보드를 실행하여 데이터가 채워지는 모습을 확인하세요.
세션 ID를 클릭하거나 /session/<session_id>로 이동하면 세션 조사 뷰가 열리며, 단일 공격을 시간순으로 재구성합니다:
$ command 형식으로 간결하게 표시# Terminal 1: start the honeypot
python3 run.py serve --port 2222 --username user1 --password pass123
# Terminal 2: start the dashboard
python3 run.py dashboard
# Terminal 3: simulate an attacker
ssh user1@localhost -p 2222
# (run some commands, then exit)
그런 다음 http://localhost:5000을 열어 캡처된 활동을 확인합니다.
대시보드는 실시간 텔레메트리를 지원합니다. 2초마다 허니팟을 폴링하여 자동으로 업데이트됩니다. 새 세션, 명령 및 이벤트가 페이지를 새로고침하지 않고도 실시간으로 표시됩니다. 실시간 표시기(● Live)가 연결 상태를 보여줍니다.
두 번째 터미널을 열고 연결을 시도해 보세요:
ssh user1@localhost -p 2222
자격 증명이 일치하면 에뮬레이션된 셸로 진입합니다.
오래된 SSH 지문을 제거하려면:
notepad "%USERPROFILE%\.ssh\known_hosts"
localhost또는 허니팟의 IP가 포함된 해당 줄을 삭제하세요.
creds_logger에 기록됩니다funnel_logger를 통해 기록됩니다log_files/events.jsonl에 기록됩니다 — 한 줄에 하나의 유효한 JSON 객체각 JSONL 이벤트에는 UTC ISO-8601 timestamp, event_type, 고유한 session_id, 그리고 source_ip가 포함됩니다. 연결, 인증 시도/결과, 명령 실행, tarpit 활성화, 연결 해제가 모두 구조화된 이벤트로 기록됩니다.
들어오는 각 SSH 연결은 고유한 session_id를 가진 독립적인 세션으로 추적됩니다. 세션은 소스 IP, 연결/해제 시각, 인증 결과, 연결 지속 시간을 기록하며, 해당 연결 내에서 생성된 모든 이벤트는 동일한 session_id를 지닙니다(따라서 인증 시도, 명령, 연결 해제를 단일 연결로 다시 연결할 수 있습니다). 세션은 연결별로 격리됩니다 — 동시 접속 클라이언트 간에 공유되는 상태는 없습니다.
또한 각 세션은 자체적으로 격리된 인메모리 가짜 파일시스템을 부여받습니다 — 시뮬레이션된 파일시스템은 각 연결마다 새로 생성되고 연결이 종료되면 정리됩니다. 한 공격자가 생성하거나 변경한 파일, 디렉터리, 작업 디렉터리는 동시에 연결된 다른 공격자에게 절대 보이지 않습니다. 전체 파일시스템은 Python 메모리에서 시뮬레이션되며 실제 호스트 파일시스템에는 절대 접근하지 않습니다.
현재 event_type 값: connect, auth_attempt, auth_success, auth_failure, command, disconnect, connection_rejected, tarpit.