Linux 기초 — 파일·로그·인코딩에서 흔적 찾기
오늘은 CTF 문제를 여러 개 풀어봤다.

아직 모든 교육생이 회원가입을 완료한 것은 아니라 현재 순위표에는 9명만 보이지만, 전체 인원은 14명이다.
문제를 빠르게 해결할수록 더 높은 점수를 받을 수 있고, 각 문제에는 풀이 방향을 알려주는 힌트도 제공된다.
챕터 1
문제를 풀기 전에 기본적인 리눅스 명령어를 배웠다.
주로 사용한 명령어는 다음과 같다.
pwd
ls -la
cat
grep
find
기본 명령어를 배운 뒤 바로 6개의 문제가 공개됐다.
1번
미로 안에서 flag를 찾아보세요
먼저 현재 위치와 파일 목록을 확인했다.
pwd
ls -la
파일과 디렉터리를 하나씩 확인하다가 flag.txt를 발견했고, cat 명령어로 내용을 읽었다.
cat flag.txt
첫 문제는 기본적인 파일 탐색 명령어 사용법을 익히는 문제였다.
끝!
2번
엄청나게 큰 파일이 있어요. 그 안에서 flag를 찾아보세요!
1번 문제와 마찬가지로 먼저 현재 디렉터리의 파일 목록을 확인했다.

목록을 확인하니 수상한 로그 파일이 하나 보였다.

파일을 열어보니 의미를 파악하기 어려운 로그가 매우 많이 출력됐다.
이런 경우 모든 줄을 직접 읽는 것보다, 플래그와 관련된 문자열을 검색하는 편이 훨씬 효율적이다.
grep -n "FLAG" audit-stream.log
grep: 파일에서 특정 문자열 검색-n: 검색된 줄의 줄 번호 출력"FLAG": 찾을 문자열audit-stream.log: 검색 대상 파일

FLAG가 포함된 로그를 찾아 플래그를 확인할 수 있었다.
끝!
3번
디코딩… 디코딩… 디코딩…
먼저 ls -la로 파일 목록을 확인한 뒤 텍스트 파일을 열어봤다.

내용을 확인해보니 영문 대소문자와 숫자로 이루어진 긴 문자열이 반복되고 있었다.
문자열의 형태를 보고 Base64로 인코딩된 데이터라고 추측했다.
먼저 한 번 디코딩해봤다.
echo "인코딩된_문자열" | base64 -d
그런데 디코딩 결과도 다시 Base64 문자열처럼 보였다.
따라서 한 번 더 디코딩했다.
echo "인코딩된_문자열" | base64 -d | base64 -d
두 번째 디코딩 결과에서 사람이 읽을 수 있는 문자열과 플래그를 확인할 수 있었다.
처음부터 두 번 인코딩됐다고 알 수 있었던 것은 아니고, 한 번 디코딩한 결과가 다시 Base64 형식처럼 보여서 추가 디코딩을 시도한 것이다.
끝!
4번
하나하나씩 알을 깨보세요
힌트의 의미는 압축 파일 안에 또 다른 압축 파일이 들어 있는 중첩 압축 문제였다.
먼저 파일 목록을 확인하니 ZIP 파일이 보였다.

현재 홈 디렉터리는 쓰기 권한이 제한될 수 있기 때문에, 쓰기가 가능한 /tmp 디렉터리에서 작업했다.
cd /tmp
mkdir ctf4
cd ctf4
그다음 첫 번째 ZIP 파일을 압축 해제했다.
unzip /home/ctf/starter.zip
압축 해제 후 파일 목록과 형식을 확인했다.
ls -la
file *

새롭게 casefile.7z 파일이 나타났다.
7z 파일이므로 다음 명령어로 압축을 해제했다.
7z x casefile.7z

이번에는 evidence.tar.gz 파일이 나타났다.
tar -xzf evidence.tar.gz
압축을 모두 해제하자 최종적으로 flag.txt 파일을 확인할 수 있었다.
이 문제의 핵심은 매 단계마다 다음 과정을 반복하는 것이었다.
파일 확인 → 실제 형식 확인 → 형식에 맞게 압축 해제
끝!
5번
John the Ripper 사용법을 아시나요?
힌트를 통해 암호가 걸린 SSH 개인키의 패스프레이즈를 찾아야 하는 문제라고 판단했다.
먼저 제공된 파일을 확인했다.

제공된 파일은 다음과 같았다.
id_rsa.locked
ssh2john.py
wordlist.txt
홈 디렉터리에 쓰기 권한이 없을 수 있으므로 /tmp에서 작업했다.
cd /tmp
먼저 암호화된 SSH 개인키를 John the Ripper가 읽을 수 있는 형식으로 변환했다.
python3 /home/ctf/ssh2john.py /home/ctf/id_rsa.locked > hash.txt
이 명령은 비밀번호를 바로 찾는 명령이 아니다.
ssh2john.py를 이용해 SSH 개인키에서 암호 검증에 필요한 정보를 추출하고, 그 결과를 hash.txt에 저장하는 과정이다.
그다음 제공된 워드리스트를 이용해 패스프레이즈 후보를 대입했다.
john --wordlist=/home/ctf/wordlist.txt hash.txt

크랙 결과는 다음 명령어로 확인했다.
john --show hash.txt
결과에서 SSH 개인키의 패스프레이즈가 sundown12인 것을 확인할 수 있었다.
끝!
6번
접속 기록 안에 단서가 있는 것 같아요
먼저 파일 목록을 확인하니 access.log라는 파일이 보였다.
이름 그대로 웹 서버의 접속 기록이 저장된 로그 파일로 보였다.
파일의 크기가 크고 정상 요청이 반복될 가능성이 높았기 때문에, 모든 내용을 직접 읽는 대신 수상한 키워드를 먼저 검색했다.
주요 키워드 검색
grep -niE 'flag|cjctf|secret|token|password|passwd|admin|debug|backup|hidden|shell|cmd|key' access.log
옵션의 의미는 다음과 같다.
-n: 줄 번호 출력-i: 대소문자 구분 없이 검색-E: 확장 정규표현식 사용
검색만으로 결과가 충분하지 않아 반복되는 정상 요청 패턴을 제외했다.
정상 요청 패턴 제외
grep -nvE '"(GET /healthz|GET /dashboard|GET /robots\.txt|GET /report/[0-9]+|HEAD /static/logo\.png|GET /api/events\?page=[0-9]+|GET /assets/app\.[0-9]+\.js|POST /api/login) HTTP/1\.1"' access.log
-v: 지정한 패턴과 일치하지 않는 줄만 출력-n: 줄 번호 출력-E: 여러 패턴을 정규표현식으로 사용
정상 요청을 제외하자 다음과 같은 이상 로그를 발견할 수 있었다.
19192:203.0.113.92 - - [12/Jul/2026:19:19:02 +0900]
“GET http://<TARGET_IP>:19192/flag.txt HTTP/1.1”
200 64 ”-” “curl/8.0” upstream=<TARGET_IP>:19192
이 로그에서 확인할 수 있는 정보는 다음과 같다.
URL: http://<TARGET_IP>:19192/flag.txt
HTTP 상태 코드: 200
응답 크기: 64바이트
User-Agent: curl/8.0
HTTP 상태 코드가 200이라는 것은 요청이 정상적으로 처리됐다는 뜻이다.
따라서 로그에 기록된 URL로 요청을 보내 flag.txt의 내용을 확인했다.
curl http://<TARGET_IP>:19192/flag.txt
결과:
CJCTF{4e9b2c7d1a8f3e5c0d6a9b1f2c7e4d8a}
끝!
마무리

이번 챕터에서는 기본적인 리눅스 명령어를 이용해 파일과 로그를 탐색하고, 압축 파일과 인코딩 데이터를 처리하는 방법을 배웠다.
특히 다음 명령어를 실제 문제에 적용해볼 수 있었다.
pwd
ls -la
cat
grep
file
unzip
7z
tar
base64
john
아직 명령어가 익숙하지 않아 시행착오도 있었지만, 문제를 하나씩 풀면서 어떤 상황에서 어떤 명령어를 사용해야 하는지 조금씩 감을 잡을 수 있었다.
다음화는 git 커밋 히스토리를 이용한 문제들이 나온다 .
원본 · velog.io