파이썬 문제를 받으면 app.py부터 찾는다. 그런데 자바 웹 문제엔 그런 단일 진입 파일이 없다. 스택이 여러 겹으로 나뉘어 있어서 WAR·JSP·tomcat-users.xml 같은 파일이 흩어져 보이기 때문이다. 이 글은 그 조각들이 각각 뭐고 어떻게 맞물리는지 정리해두었다.

자바는 컴파일 언어다: 서버엔 소스가 없다

파이썬은 소스(.py)를 그대로 실행하지만, 자바는 한 단계를 더 거친다. .javajavac로 컴파일하면 .class 바이트코드가 나오고, 이걸 JVM이 실행한다. 소스가 아니라 바이트코드를 돌리기 때문에 OS를 안 가리는 것이고(“write once, run anywhere”), 동시에 서버에는 소스가 아니라 컴파일된 .class·.jar가 올라간다.

그래서 자바 문제의 첫 질문은 늘 “소스가 있느냐"다. 문제에서 소스나 WAR를 통째로 주면 그건 선물이고, 없으면 디컴파일러(jd-gui, CFR)로 .class를 소스로 되돌려 읽어야 한다.

웹앱을 통째로 담는 상자: WAR

웹앱은 파일 하나가 아니다. 화면을 그리는 JSP, 컴파일된 서블릿 클래스, 갖다 쓰는 라이브러리, 설정 파일이 다 필요하다. 이걸 하나로 묶어 배포하려고 만든 게 WAR(Web Application Archive)이고, 실체는 그냥 zip이다. 그래서 unzip -l로 열면 속이 다 보인다.

1
unzip ROOT.war -d extracted
1
2
3
4
5
6
7
ROOT.war
├─ *.jsp          화면(JSP 페이지)
├─ resources/     정적 파일(이미지 등)
└─ WEB-INF/       ← 웹에서 직접 접근 불가
   ├─ web.xml     URL ↔ 서블릿 매핑(라우팅 지도)
   ├─ classes/    컴파일된 서블릿 .class
   └─ lib/        의존 .jar

여기서 핵심은 WEB-INF다. 이 폴더는 URL로 직접 못 여는 게 정상인데, 바로 그래서 민감한 게 다 여기 들어 있다 — 소스, 설정, 자격증명. 즉 어딘가에 파일 읽기(경로 조작·LFI) 취약점이 있으면, WEB-INF 안을 긁는 순간 앱 내부가 통째로 열린다.

WAR만으론 안 돈다: 실행해줄 놈, 서블릿 컨테이너

WAR는 상자일 뿐이라 스스로 실행되지 않는다. 이 상자를 받아 메모리에 올리고, 들어온 요청을 알맞은 서블릿으로 넘겨주는 런타임이 따로 있어야 하는데 그게 서블릿 컨테이너(Tomcat, Jetty)다. 파이썬으로 치면 Flask 앱을 실제로 띄워주는 WSGI 서버 자리와 같다. 서블릿은 요청을 받아 응답을 만드는 자바 클래스, 즉 Flask의 라우트 핸들러에 대응한다.

톰캣이 CTF에서 특히 뜨거운 이유는 Manager라는 관리앱을 기본으로 품고 있어서다. WAR를 웹으로 업로드해 배포하는 기능인데, 계정만 손에 넣으면 명령이 실행되는 JSP를 담은 악성 WAR를 올려 RCE로 직행할 수 있다. 그래서 tomcat-users.xml(Manager 계정·권한이 적힌 파일)이 보이면 눈이 번쩍 뜨여야 한다.

JSP와 web.xml: 코드와 지도

JSP는 HTML 안에 자바 코드(<% ... %>)를 박아 서버에서 실행시켜 HTML을 만드는 방식으로, PHP와 구조가 거의 같다. web.xml은 이 앱의 라우팅 지도라서, 어떤 URL이 어떤 서블릿으로 가는지를 정의한다. 그래서 서블릿 소스를 파헤치기 전에 web.xml부터 펴서 엔드포인트 전체를 먼저 파악하는 게 순서다.

그래서 어떻게 접근하냐: 설정 파일부터 읽는다

자바 문제에서 헤매지 않으려면 소스보다 배포·설정 파일을 확인한다. 이것들이 웹루트·엔드포인트·자격증명·라이브러리 버전을 대놓고 알려주기 때문이다.

  • Dockerfile: 파일이 어디에 놓이는지, flag 위치와 권한, 웹루트 경로
  • web.xml: URL ↔ 서블릿 매핑
  • tomcat-users.xml: Manager 계정·권한
  • pom.xml / build.gradle: 의존성과 버전 → 알려진 CVE 탐색의 출발점

이 파일들을 먼저 읽으면 “뭐부터 봐야 하지"가 사라진다. 지도를 먼저 펴는 셈이다.

Spring과의 연결

요즘은 WAR를 외부 톰캣에 얹는 대신, Spring Boot가 톰캣을 안에 내장(embedded)해 실행 가능한 JAR 하나로 뜬다. 서블릿·컨테이너라는 개념은 그대로고 배포 방식만 자기완결적으로 바뀐 것뿐이다. Spring은 이 스택을 없앤 게 아니라 그 위에 얹힌 프레임워크라고 보면 된다.

자바 특유의 공격 벡터

일반적인 웹 취약점(SQLi, XSS 등)은 web-vuln 노트로 넘기고, 여기선 자바에서 유독 자주 나오는 것만 남긴다.

  • Tomcat Manager 인증 획득 → 악성 WAR 배포 → RCE
  • 경로 조작 / LFI → WEB-INF의 소스·설정·자격증명 유출
  • 자바 역직렬화(deserialization) → 자바 특유의 RCE 벡터 (개념만)
  • 디컴파일 → .class·.jar를 소스로 되돌려 로직 분석