dreamhack

[Dreamhack] proxy-1

부산영롱 2024. 2. 2. 16:15

 RAW 소켓이란?

어느 특정한 프로토콜 용의 전송 계층 포맷팅 없이 인터넷 프로토콜 패킷을 직접적으로 주고 받게 해주는 소켓

 

RAW 소켓의 정의를 읽어봐도 무슨 소리인지 이해가 가지 않는다. RAW 소켓은 헤더 정보를 프로그래머가 직접 제어할 수 있게 해준다고 하는데 아래 그림을 보고 나니 어떤 느낌인지 알 것 같다.

< 일반 소켓 흐름도 >
< RAW 소켓 흐름도 >

#!/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을 이용해서 서버의 /admin 페이지로 POST 통신을 해야한다.

자기자신에게 통신을 해야하기때문에 host에는 'localhost' 나 루프백 주소인 '127.0.0.1'을 입력해도 되고 소스코드에서 설정한 '0.0.0.0'을 입력해도 된다.(127.0.0.0/8 대역 모두 루프백 주소이기에 대역 내 아무 IP나 입력해도 되긴 한다.)

'0.0.0.0'은 외부를 포함한 모든 네트워크에서부터 패킷을 받을 수 있고, '127.0.0.1'은 로컬에서 오는 패킷만 허용한다.

port는 소스코드에 적힌대로 8000을 입력하고 data에는 /admin 으로 보낼 POST 헤더를 작성하면 된다.

문제를 풀면서 최소한으로 갖춰야하는 POST 헤더 구문을 알 수 있었다.

최소한 HTTP 메소드, URI, HTTP 프로토콜과 Body까지는 적어줘야 응답이 왔다.

소스코드 조건식을 만족하는 코드를 한줄씩 추가하면서 조건이 참이 되는지 확인해보았다.

헤더부분의 키:값에는 대소문자 구분을 해야했으며, 키와 ':' 사이에 공백이 있으면 에러가 발생했다.

또 Body의 '키=값'이 전달되려면 Content-Length, Content-Type 헤더를 꼭 적어줘야했다.

(Body에 들어가는 문자열 길이와 Content-Length이 달라도 제대로 전달이 되지 않았다.

최종적으로 위와 같이 보내면 모든 조건식을 통과하여 플래그를 얻을 수 있었다.

'dreamhack' 카테고리의 다른 글

[Dreamhack] Mongoboard  (0) 2024.02.08
[Dreamhack] amocafe  (0) 2024.02.07
[Dreamhack] Command Injection Advanced  (0) 2024.02.02
[Dreamhack] sql injection bypass WAF  (0) 2024.02.01
[Dreamhack] error based sql injection  (0) 2024.02.01