-
[Study] LINE CTF 2022 Memo Drive WriteupCTF/LINE CTF 2022 2022. 3. 28. 07:47
주어진 페이지에 접근해보자.
아래와 같이 메모를 작성하고 읽을 수 있는 기능이 구현되어 있다.
주어진 소스코드를 분석해보자.
우선 Dockerfile에 플래그 위치가 나타나있다. ${MEMO}/memo/flag 를 읽어 플래그를 획득 할 수 있다는 점을 기억하자.
FROM python:3.9.0 LABEL maintainer "t0rchwo0d_LINE" ENV SALT="ONLY_FOR_LOCAL_TEST" ENV MEMO /usr/local/opt/memo-drive RUN mkdir -p "${MEMO}" RUN apt-get -qq update && \ apt-get -qq -y upgrade && \ apt-get -qq -y install htop net-tools vim COPY ./memo-drive "${MEMO}" COPY start.sh "${MEMO}/start.sh" COPY flag "${MEMO}/memo/flag" RUN pip install -r "${MEMO}/requirements.txt" RUN chmod -R 705 "${MEMO}" RUN chmod 707 "${MEMO}/memo/" RUN chmod 704 "${MEMO}/memo/flag" RUN groupadd -g 1000 memo RUN useradd -g memo -s /bin/bash memo USER memo EXPOSE 11000 WORKDIR "${MEMO}" ENTRYPOINT ["./start.sh"]
처음에는 memo를 기록할 때 memo의 내용에 특정 구문을 입력하여 작성한 메모를 읽을 시 플래그 값이 노출되도록 하는 방식일 것이라고 생각했었는데 해당 시나리오로는 취약한 포인트를 찾지 못했다.
따라서 위 Dockerfile 에서 얻은 정보를 기반으로 직접 /memo/flag를 읽는 방식을 시도해보았다. 핵심은 메모를 읽는 로직일 것이라고 생각하여 view 메소드를 집중적으로 분석해보았다.
우선 일반적으로 작성한 메모를 읽을 때 아래와 같이 호출된다.
http://34.146.195.115/view?d46636bd5fec072a9d8aa2280f78ea9c=0_20220327220246
여기서 d46636bd5fec072a9d8aa2280f78ea9c 는
clientId = getClientID(request.client.host)
의 결과 값으로 사용자 IP와 salt를 더한 값에 md5를 한 값이다.
0_20220327220246 는
filename = str(idx) + '_' + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
로직을 통해 만들어진 실제 메모 파일의 이름이다.
이를 참고하여 소스를 분석해보자.
def view(request): context = {} try: context['request'] = request clientId = getClientID(request.client.host) if '&' in request.url.query or '.' in request.url.query or '.' in unquote(request.query_params[clientId]): ##### ............................................................................ (1) raise filename = request.query_params[clientId] path = './memo/' + "".join(request.query_params.keys()) + '/' + filename ##### ... (2) f = open(path, 'r') contents = f.readlines() f.close() context['filename'] = filename context['contents'] = contents except: pass return templates.TemplateResponse('/view/view.html', context)
(1) 을 분석해보면, url query에 &과 . 이 들어갈 수 없고, 특히 filename에는 unquote를 통해 url 디코딩 후에도 . 가 포함될 수 없다.
따라서
http://34.146.195.115/view?d46636bd5fec072a9d8aa2280f78ea9c=../flag
와 같은 구문은 사용 할 수 없다.
(2)의 파일 경로를 정의하는 부분을 분석해보자.
우리가 작성한 메모의 실제 경로는 /memo/d46636bd5fec072a9d8aa2280f78ea9c/0_20220327220246 인 듯 하다.
하지만 특이한점이 있는데,
/memo/ 하위 디렉토리를 지정 할 때 request.query_params.keys() 로 여러 파라미터의 key들이 더해진 값이 되도록 한다.
따라서, 비록 & 가 제한되어 있지만 request.query_params[clientId] 외에 파라미터를 추가 할 수 있고 그 값이 /.. 라면
/memo/d46636bd5fec072a9d8aa2280f78ea9c/../flag 처럼 플래그를 호출 할 수 있을 것이다.
혹시 URL Query String에서 & 외에 구분자를 지정 할 수 있는 방법이 있을까해서 공부해보았다.
https://en.wikipedia.org/wiki/Query_string
Query string - Wikipedia
From Wikipedia, the free encyclopedia Jump to navigation Jump to search Part of a URL that assigns values to specified parameters A query string is a part of a uniform resource locator (URL) that assigns values to specified parameters. A query string commo
en.wikipedia.org
위 레퍼런스에 의하면 & 대신 ; 를 사용 할 수 있다는 내용이 있었다.
* 22.04.02 수정 ----> 위 내용에서 ; 사용은 특이케이스에 대한 내용이고 아래 레퍼런스가 더 정확한 듯 하다.
https://bugs.python.org/issue42967
Issue 42967: [CVE-2021-23336] urllib.parse.parse_qsl(): Web cache poisoning - `; ` as a query args separator - Python tracker
Issue42967 Created on 2021-01-19 15:06 by AdamGold, last changed 2021-11-08 16:47 by vstinner. This issue is now closed. URL Status Linked Edit PR 24271 closed kj, 2021-01-20 15:20 PR 24297 merged AdamGold, 2021-01-22 12:34 PR 24528 merged orsenthil, 2021-
bugs.python.org
이를 활용하여 request.url.query에서의 필터링을
& 대신 ; 사용하고 "." 사용 제한을 URL 인코딩으로 우회하여
최종적으로 아래 payload로 플래그를 획득 할 수 있었다.
http://34.146.195.115/view?d46636bd5fec072a9d8aa2280f78ea9c=flag;/%2e%2e --> http://34.146.195.115/view?d46636bd5fec072a9d8aa2280f78ea9c=flag&/%2e%2e //request.query_params.keys() = ['d46636bd5fec072a9d8aa2280f78ea9c', '/..'] --> memo/d46636bd5fec072a9d8aa2280f78ea9c/../flag
FLAG = LINECTF{The_old_bug_on_urllib_parse_qsl_fixed}
----------------------------------------------------------------------------------------------------------------------
또 다른 풀이로, Host 헤더에 #을 추가하여 request.url.query의 필터링을 우회 할 수 있다고 한다.
반응형'CTF > LINE CTF 2022' 카테고리의 다른 글
[Study] LINE CTF 2022 bb Writeup (0) 2022.03.29 [Clear] LINE CTF 2022 gotm Writeup (0) 2022.03.28