[Dreamhack Web - Lv 1] proxy-1

문제 정보

Raw Socket Sender가 구현된 서비스입니다.
요구하는 조건을 맞춰 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다.

풀이 힌트

1. 소스코드 분석

2. HTTP Packet

3. Proxy Tool

문제 풀이

더보기
더보기

문제의 설명에 요구 조건을 맞추라는 말이 있는데, 이게 어떤 걸을 말하는지 잘 모르겠다.
그래서 일단 기능을 보고 추측을 해보겠다.

 

해당 문제의 기능은 Raw Socket Sender 기능이 있다. 메뉴바의 Socket도 Raw Socket Sender와 같은 것이다.

 

해당 페이지는 위 사진과 같다.
여기까지 살펴본 결과 아마 해더와 관련이 있지 않을까? 라는 생각이 들었다.

 

그 이유는 host, port, data이 세 개를 던져주고 요구 조건을 맞추라는데, 화이트리스트로 통제되는 IP 주소와 Port를 맞추라는 것은 아니라고 생각이 든다. 아마 이 문제는 코드를 봐야할 듯 싶었다.

 

#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for
import socket

app = Flask(__name__)

try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/socket', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('socket.html')
    elif request.method == 'POST':
        host = request.form.get('host')
        port = request.form.get('port', type=int)
        data = request.form.get('data')

        retData = ""
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.settimeout(3)
                s.connect((host, port))
                s.sendall(data.encode())
                while True:
                    tmpData = s.recv(1024)
                    retData += tmpData.decode()
                    if not tmpData: break
            
        except Exception as e:
            return render_template('socket_result.html', data=e)
        
        return render_template('socket_result.html', data=retData)

@app.route('/admin', methods=['POST'])
def admin():
    if request.remote_addr != '127.0.0.1':
        return 'Only localhost'

    if request.headers.get('User-Agent') != 'Admin Browser':
        return 'Only Admin Browser'

    if request.headers.get('DreamhackUser') != 'admin':
        return 'Only Admin'

    if request.cookies.get('admin') != 'true':
        return 'Admin Cookie'

    if request.form.get('userid') != 'admin':
        return 'Admin id'

    return FLAG

app.run(host='0.0.0.0', port=8000)

코드를 까본 결과 socket 페이지는 Post 메소드로 넘겨진 host, port, data를 가지고 Socket 연결을 하는 기능이다.
하지만 Socket이 연결된다고 해도, 데이터를 넘겨 받아서 페이지에 출력되는 기능을 가지고 있다.

 

물론 template에 넘겨 받은 데이터를 전달하지만, 이를 통해 SSTI 공격을 시도하면 될지도 모르겠다는 생각이 들었다.

 

admin 페이지의 코드를 보면 여러 조건이 있고 조건을 통과하면 Flag를 반환하는 것을 알 수 있다. 이를 만족해서 Flag를 얻도록 하겠다.

 

@app.route('/admin', methods=['POST'])
def admin():
    if request.remote_addr != '127.0.0.1':
        return 'Only localhost'

    if request.headers.get('User-Agent') != 'Admin Browser':
        return 'Only Admin Browser'

    if request.headers.get('DreamhackUser') != 'admin':
        return 'Only Admin'

    if request.cookies.get('admin') != 'true':
        return 'Admin Cookie'

    if request.form.get('userid') != 'admin':
        return 'Admin id'

    return FLAG

일단 첫번째 조건이 자기 자신이 아니면 안된다는 조건임으로 Socket 페이지를 이용하여 admin 페이지에 HTTP 패킷을 전달하겠다. 해당 서버는 8000으로 열려있다.

 

이와 같이 값을 넣어주고, 다른 조건을 살펴보겠다.

  • 두번째 조건은 HTTP 해더의 User-Agent가 Admin Browser이어야 한다는 것
  • 세번째 조건은 커스텀 해더인 DreamhackUser가 admin이어야 한다는 것

 

두가지 조건을 만족시키기 위해 해더를 추가하였다.

 

그 다음 조건인 Cookie 설정과 userid 값 전달을 위해 Cookie 해더, Content-Length, Content-Type, Body에 값을 넣어서 전송하였다.

 

그 결과 손쉽게 Flag를 얻을 수 있었다.

'Wargame > Dreamhack' 카테고리의 다른 글

[OverTheWire System - Bandit] Level 2 >> Level 3  (0) 2021.10.26
[Dreamhack Web - Lv 1] csrf-1  (0) 2021.10.25
[Dreamhack Web - Lv 1] file-download-1  (0) 2021.10.25
[Dreamhack Web - Lv 1] xss-1  (0) 2021.10.23
[Dreamhack Web - Lv 1] welcome  (0) 2021.10.15