워게임 Cookie 문제 해설

웹사이트가 로그인 상태나 권한(guest/admin)을 브라우저의 쿠키(Cookie)에 그대로 저장할 때, 사용자가 이를 임의로 수정하여 관리자 권한을 획득하는 취약점 문제입니다.

① 개발자 도구에서 쿠키 확인하기 브라우저에서 문제 페이지를 엽니다.
키보드의 F12를 눌러 개발자 도구를 실행합니다.
Application(애플리케이션) 탭 ➔ 좌측 메뉴의 Cookies ➔ 문제 사이트 주소를 선택합니다.
서버가 발급한 쿠키 목록에서 권한을 나타내는 값을 찾습니다.

② 쿠키 값 변조하기
만약 쿠키 값이 Base64 등으로 인코딩되어 있다면 디코딩을 거쳐 원본을 확인합니다.
권한을 나타내는 값을 관리자용으로 변경합니다.
guest ➔ admin
개발자 도구의 쿠키 창에서 해당 값을 더블클릭하여 직접 수정합니다.
③ 새로고침 및 플래그 획득
쿠키를 수정한 상태로 페이지를 새로고침(F5) 합니다.
웹 서버가 변조된 쿠키를 그대로 신뢰하여 관리자 페이지로 접근하게 되며, 화면에 출력되는 Flag를 획득합니다.
워게임 XSS -1

1. 문제
페이지 구성:
/vuln: 사용자가 전달한 param 파라미터의 값을 화면에 그대로(필터링 없이) 출력하는 취약한 페이지
/memo: 입력한 텍스트를 기록하고 보여주는 페이지
/flag: URL을 입력받아 관리자 봇(selenium)이 해당 URL에 접속하도록 요청하는 페이지
목표: /flag 페이지에서 관리자 봇에게 XSS 페이로드가 포함된 /vuln 페이지 주소를 방문하게 만들어, 관리자의 쿠키(document.cookie)나 플래그 정보를 /memo 페이지에 남기도록 유도하RL

2. 문제 풀이 과정
① 취약점 확인 (/vuln)
- /vuln 페이지에 접속하여 ?param= 파라미터에 간단한 HTML 태그를 입력해 봅니다.
-
Plaintext
/vuln?param=<h1>test</h1> - 글씨가 커지는 등 HTML 태그가 그대로 렌더링되는 것을 확인합니다.
② 스크립트 실행 테스트 (XSS)
- 자바스크립트가 정상적으로 실행되는지 확인하기 위해 script 태그를 입력합니다.
-
Plaintext
/vuln?param=<script>alert(document.domain)</script> - 알림창이 뜨면 XSS 취약점이 확실히 존재하는 것입니다.
③ 쿠키(플래그) 탈취 페이로드 작성
- 이 문제의 플래그는 보통 관리자 봇의 세션 쿠키 안에 있거나, 관리자 권한으로만 볼 수 있는 페이지에 존재합니다. 따라서 관리자가 접속했을 때 자신의 쿠키를 /memo 페이지에 자동으로 기록하도록 페이로드를 구성합니다.
- 사용할 페이로드
-
HTML
<script>location.href = "/memo?memo=" + document.cookie;</script>
④ 관리자 봇에게 전송하기 (/flag)
- /flag 페이지로 이동합니다.
- 입력창에 위 페이로드가 포함된 전체 URL 주소를 적어 제출합니다.
- 입력 예시: [http://127.0.0.1](http://127.0.0.1):포트번호/vuln?param=<script>location.href="/memo?memo="+document.cookie;</script>
- 관리자 봇이 해당 링크를 누르면, 봇의 권한으로 스크립트가 실행되면서 관리자의 쿠키 값이 /memo 페이지에 전송됩니다.
⑤ 플래그 확인
- /memo 페이지로 이동합니다.
- 봇에 의해 작성된 메모 내용에서 Flag 값을 확인합니다.

XSS-2 워게임 문제풀이

<script> 태그가 막힌 환경에서 이미지 태그의 onerror 속성을 이용해 필터링을 우회하고 관리자의 쿠키를 탈취하는 XSS 취약점 실습 문제입니다

<script> 태그가 필터링될 때, 이미지 태그의 onerror 속성을 이용하면 우회해서 스크립트를 실행하고 쿠키를 탈취할 수 있습니다

추가 코딩 문제 릿코드

LeetCode 문자열 문제 풀이 - Roman to Integer
워게임 문제 풀이와 함께 기본적인 코딩 실력을 키우기 위해 LeetCode 문제 풀이도 병행했다.
워게임에서는 문자열을 읽거나 입력값을 분석하는 과정이 자주 등장하기 때문에, 이번에는 문자열(String)을 다루는 문제를 선택했다.
이번에 풀이한 문제는 LeetCode의 13. Roman to Integer이다.
문제 설명
주어진 로마 숫자 문자열을 정수로 변환하는 문제이다.
로마 숫자의 각 문자는 다음과 같은 값을 가진다.
I = 1
V = 5
X = 10
L = 50
C = 100
D = 500
M = 1000
일반적으로 로마 숫자는 왼쪽에서 오른쪽으로 값을 더하면 된다.
예를 들어,
LVIII
의 경우
L = 50
V = 5
I = 1
I = 1
I = 1
이므로
50 + 5 + 1 + 1 + 1 = 58
이 된다.
하지만 작은 값의 문자가 큰 값의 문자 앞에 있는 경우에는 작은 값을 빼야 한다.
IV = 4
IX = 9
XL = 40
XC = 90
CD = 400
CM = 900
예를 들어 IV의 경우 I = 1, V = 5이지만, 작은 값인 I가 V 앞에 있으므로
5 - 1 = 4
로 계산한다.
풀이 방법
문자열을 처음부터 한 글자씩 확인하면서 현재 문자의 값과 다음 문자의 값을 비교한다.
현재 값 < 다음 값
→ 현재 값을 뺀다.
현재 값 >= 다음 값
→ 현재 값을 더한다.
예를 들어 IV라면
I = 1
V = 5
1 < 5
이므로 1을 빼고, 그다음 5를 더한다.
-1 + 5 = 4
C 코드
int value(char c) {
switch (c) {
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
default: return 0;
}
}
int romanToInt(char* s) {
int result = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (value(s[i]) < value(s[i + 1]))
result -= value(s[i]);
else
result += value(s[i]);
}
return result;
}
코드 설명
value() 함수는 로마 숫자 문자를 실제 정수 값으로 변환한다.
case 'I': return 1;
case 'V': return 5;
와 같이 각 문자에 해당하는 숫자를 반환하도록 만들었다.
이후 romanToInt() 함수에서는 문자열을 처음부터 끝까지 반복한다.
for (int i = 0; s[i] != '\0'; i++)
C 문자열의 마지막에는 '\0'이 들어가기 때문에, '\0'이 나올 때까지 한 글자씩 확인한다.
가장 중요한 부분은 다음 조건문이다.
if (value(s[i]) < value(s[i + 1]))
현재 로마 숫자의 값이 다음 숫자보다 작다면 현재 값을 빼고,
result -= value(s[i]);
그렇지 않다면 현재 값을 더한다.
result += value(s[i]);
예를 들어 MCMXCIV를 처리하면 다음과 같다.
M = +1000
C = -100
M = +1000
X = -10
C = +100
I = -1
V = +5
따라서
1000 - 100 + 1000 - 10 + 100 - 1 + 5
= 1994
가 된다.