본문 바로가기

Dreamhack/웹해킹

[LEVEL 1] proxy-1

웹 서비스 접속 시, 프로젝트 현황을 한눈에 확인할 수 있는 'My Projects' 대시보드 화면이 나타납니다.

Raw Socket Sender (Done)를 누르게 되면 아래와 같은 화면이 나오게 됩니다.

Raw Socket Sender에다가 '127.0.0.1' 주소의 8000번 포트로 데이터 'hi'를 보내면 타임아웃(Timeout) 오류가 발생하는 것을 확인할 수 있습니다.

 

발생한 문제를 더 자세히 확인하기 위해, 이제 문제 파일을 살펴보겠습니다. 파일을 분석하면 왜 타임아웃이 발생했는지 그 원인을 더 명확하게 파악할 수 있을 것입니다. 

 

app.py

#!/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)

1. 소켓 통신 기능 (/socket)

이 기능은 웹 인터페이스를 통해 서버가 사용자를 대신해 소켓 통신을 수행하는 부분입니다. 마치 원격 조종 리모컨처럼, 사용자는 웹페이지에 접속할 서버의 주소(Host), 포트(Port), 그리고 보낼 데이터(Data)를 입력하기만 하면 됩니다.

  • 동작 방식: 사용자의 입력이 서버로 전달되면, 서버는 해당 정보로 소켓을 생성하고 연결을 시도합니다.
  • 시간 제한: 통신 과정에서 s.settimeout(3) 코드가 있어, 3초 안에 응답이 없으면 자동으로 연결을 끊습니다. 이는 불필요한 대기를 방지합니다.
  • 결과 표시: 통신이 성공하면 받은 데이터를, 실패하면 오류 메시지를 웹페이지에 보여줍니다.

이 기능은 외부 또는 내부 서버에 대한 요청을 웹 브라우저를 통해 실행할 수 있게 해주는 도구라고 할 수 있습니다.

2. 관리자 페이지 (/admin) 접근 제어

/admin 페이지는 매우 까다로운 보안 검사를 통과해야만 접근할 수 있습니다. GET 요청은 허용되지 않고, 오직 POST 요청으로만 접근이 가능하며, 아래의 5가지 조건을 모두 만족해야만 최종적으로 FLAG 값을 반환합니다.

  1. IP 주소: 접속 IP가 127.0.0.1 (로컬호스트)여야 합니다. 외부에서는 접근이 불가능합니다.
  2. User-Agent: HTTP 헤더의 User-Agent 값이 Admin Browser여야 합니다.
  3. 사용자 헤더: HTTP 헤더에 DreamhackUser 키가 존재하고, 그 값이 admin이어야 합니다.
  4. 쿠키: admin이라는 이름의 쿠키 값이 true여야 합니다.
  5. 폼 데이터: POST 요청 본문(Form Data)에 포함된 userid 값이 admin이어야 합니다.

/admin 페이지에 접속하면 'Method Not Allowed' 오류가 발생합니다. 이는 /admin 페이지가 GET 요청을 허용하지 않고, POST 요청만 받는다는 것을 의미합니다. 그런데 /socket 기능은 서버가 사용자를 대신해 원하는 곳으로 데이터를 보내주는 역할을 합니다. 우리는 이 점을 이용해 /socket에 서버 자기 자신의 주소(127.0.0.1)와 함께 /admin 페이지로 가기 위한 모든 정보가 담긴 HTTP 요청을 넣으면 풀리는 문제입니다.

 

이제 Data 필드에 통신에 필요한 특정 값을 삽입하겠습니다. 이 값을 설정함으로써 서버의 응답을 조작하거나, 특정 동작을 유도할 수 있는지 확인해 볼 수 있습니다.

POST /admin HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Admin Browser
DreamhackUser: admin
Cookie: admin=true
Content-Type: application/x-www-form-urlencoded
Content-Length: 12

userid=admin

🤔 POST 요청의 필수 조건: Content-Type과 Content-Length

두 헤더는 POST 요청의 본문 데이터를 서버가 정확하게 이해하도록 돕는 역할을 합니다.

  • Content-Type: 데이터의 종류를 알려줍니다. application/x-www-form-urlencoded는 웹 폼(form)을 통해 보내는 데이터라는 것을 의미합니다.
  • Content-Length: 데이터의 크기를 알려줍니다. 서버는 이 길이를 참고해 본문을 읽습니다. 여기서는 userid=admin이라는 데이터를 보내기 때문에, 총 12개의 문자로 구성되어 Content-Length: 12가 되는 것입니다.

이 두 정보가 있어야 서버는 보낸 데이터를 올바르게 해석하고 처리할 수 있습니다.

 

그 결과 플래그를 성공적으로 획득하였습니다. 이번 실습은 서버 사이드 요청 위조(SSRF)를 통해 IP 주소 및 메서드 제한과 같은 웹 서비스의 취약점을 직접 우회하는 과정을 보여주었습니다.

'Dreamhack > 웹해킹' 카테고리의 다른 글

[LEVEL 1] csrf-1  (0) 2025.09.03
[LEVEL 1] simple_sqli  (0) 2025.09.02
[LEVEL 1] Disgusting Ads  (0) 2025.08.28
[🌱Beginner] php7cmp4re  (0) 2025.08.27
[🌱Beginner] phpreg  (0) 2025.08.27