Dreamhack/Dreamhack Wargame (Challenge)

[140] IT 비전공자 [dreamhack]Where-is-localhost문제 풀기

imaginefuture-1 2025. 1. 28. 21:34

localhost?
노....

소스코드를 보러가자 main.py 파일

 

from flask import Flask, render_template, request
import ipaddress
import urllib.parse
import urllib.request
import urllib.error

app = Flask(__name__)

try:
    with open('flag') as f:
        flag = f.read()
except FileNotFoundError:
    flag = 'flag{this_is_a_fake_flag}'

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

@app.route('/vuln', methods=['POST'])
def vuln():
    name = request.form.get('vulntest')
    try:
        address = ipaddress.ip_address(name)
        if address.version == 4:
            return "no..."
        url = urllib.parse.urlparse(f"http://[{address.exploded}]:5000/localonly")
        if url.netloc != f'[{address.exploded}]:5000':
            print(url.netloc, f'[{address.exploded}]')
            return "no..."
        req = urllib.request.Request(url.geturl())
        return urllib.request.urlopen(req).read().decode('utf-8')
    except ValueError:
        return "no..."
    except urllib.error.URLError:
        return "connection refused"

@app.route('/localonly', methods=['GET'])
def localonly():
    addr = ipaddress.ip_address(request.remote_addr)
    if addr.is_loopback and addr.version == 4:
        return flag
    else:
        return 'not loopback'

if __name__ == '__main__':
    app.run('0.0.0.0', 5000)

 

/vuln경로에서

IPv4는 no..반환

 

입력받은 ipv6 주소를 기반으로 url을 만들고 (urllib.parse.urlparse), address.exploded로 ipv6 주소를 문자열 형식으로 변환한 후 url.netloc과 비교하여 다르면 no, 맞으면 request를 보내는 듯 하다.
만약 성공적으로 url 요청이 보내지면 -> 응답 반환 ( return urllib.request.urlopen(req).read().decode('utf-8')
※ url.netloc
url.netloc는 url의 네트워크 위치값(호스트, 포트) 반환 
출처ㅣhttps://melonbbang-ruffy.tistory.com/26

 

@app.route('/localonly', methods=['GET'])
def localonly():
    addr = ipaddress.ip_address(request.remote_addr)
    if addr.is_loopback and addr.version == 4:
        return flag
    else:
        return 'not loopback'

 

/localonly경로에

flag가 있다

IPv4 루프백 주소로 127.0.0.1에서 요청이 오면 플래그가 나오는데

위에서는 ipv6만 입력 받는데(?)

 

IPv4 127.0.0.1 == IPv6 0:0:0:0:0:0:0:0:1

IPv4 루프백 주소를 IPv6 루프백 주소로 인식되게해야한다

하지만 외부 ip나 ipv6는 not loopback인걸?

 

 

 

IPv6 루프백 주소는 0:0:0:0:0:0:0:0:1이며 ::1/128로 표기할 수 있습니다.

 

 

이 Flask 애플리케이션에서 localhost 접근을 제한하는 보안 메커니즘이 있지만, 이를 우회하기 위해 IPv6 주소와 관련된 취약점을 악용할 수 있습니다. 애플리케이션의 동작을 분석하고 이를 우회하는 방법을 설명하겠습니다.


분석

  1. 취약점이 존재하는 /vuln 라우트:
    • 사용자 입력 name을 받아 IP 주소로 변환하고 검증합니다.
    • 검증 후 해당 IP 주소를 기반으로 http://[IPv6_address]:5000/localonly에 요청을 보냅니다.
    • 요청하는 URL은 url.netloc과 f'[{address.exploded}]:5000'을 비교하여 악의적인 조작을 방지하려고 합니다.
    • 하지만 URL 파싱 및 IP 주소 처리 과정에서 일부 우회가 가능합니다.
  2. /localonly 라우트:
    • 요청의 원격 주소 (request.remote_addr)가 loopback(127.0.0.1)이며 IPv4인지 확인합니다.
    • 조건을 만족하면 flag를 반환합니다.
    • 외부 IP나 IPv6 주소에서 요청 시 not loopback이 반환됩니다.
  3. 우회 가능성:
    • ipaddress.ip_address와 urllib.parse를 사용하는 과정에서 IPv6 특수 주소나 변형된 loopback 주소(::1)를 활용하면 접근 가능성이 있습니다.
    • 예를 들어, IPv6의 loopback 주소 ::1은 localhost를 의미하지만, 변형된 표현(::0:1 등)도 동일하게 해석됩니다.
    • URL 파싱 시 제대로 비교하지 못하는 경우 이를 악용할 수 있습니다.

공격 방법

  1. IPv6 Loopback 주소 활용:
    • IPv6 loopback 주소는 ::1이며, http://[::1]:5000/localonly는 localhost에 요청하는 것과 동일합니다.
    • 변형된 IPv6 표현을 사용하여 우회를 시도합니다. 예:
      • ::1
      • ::0:1
      • 0:0:0:0:0:0:0:1
  2. 특수 URL 인코딩 사용:
    • urllib.parse.urlparse가 URL 검증에 사용되므로 특수 인코딩을 통해 URL을 조작할 수 있습니다. 예:
      • %5b::1%5d는 [::1]과 동일하게 해석됩니다.

공격 시나리오

  1. 요청 흐름:
    • /vuln에 POST 요청을 보내며 vulntest 필드에 변형된 IPv6 loopback 주소를 입력합니다.
    • 서버는 이를 검증하고, /localonly로 요청을 전송합니다.
    • 요청의 원격 주소가 ::1로 확인되면 flag를 반환합니다.
  2. 예제 요청:
  3. curl -X POST http://<서버 IP>:5000/vuln -d "vulntest=::1"
  4. 결과:
    • 서버가 /localonly에 요청을 보내 request.remote_addr를 확인하고, 127.0.0.1 또는 ::1인 경우 flag를 반환합니다.

코드 수정이 필요할 경우 보안 강화

  1. IPv6 변형 표현 처리:
    • 모든 loopback 변형 표현(::1, ::0:1, 0:0:0:0:0:0:0:1 등)을 검사해야 합니다.
    • 이를 방지하려면 ipaddress.ip_address를 사용해 직접 확인해야 합니다.
  2. URL 검증 강화:
    • urllib.parse.urlparse를 사용하는 대신, URL 문자열을 엄격히 검증합니다.
  3. 헤더 추가 검증:
    • 요청 헤더(Host 또는 X-Forwarded-For)를 추가로 확인하여 신뢰할 수 있는 요청인지 검증합니다.

위의 방법을 통해 플래그를 획득하거나 보안을 강화할 수 있습니다. 😊

 

 

 

히잉..
노....

 

 

노...노..!!! localhost..는 어디있나요..? 어떻게 접근하나요..? 우회 해줘..

 

 

https://melonbbang-ruffy.tistory.com/26

 

[Dreamhack] Where-is-localhost

https://dreamhack.io/wargame/challenges/1560 Where-is-localhostlocalhost... 과연 어떻게 접근할까? Edit (10/22/2024 7:49): fix error in codedreamhack.io오랜만에 웹 해킹 문제문제명만 보면 localhost를 접근해서 플래그를 알아

melonbbang-ruffy.tistory.com

 

https://notes.networklessons.com/ipv6-ipv4-mapped-ipv6-address

 

IPv6 - IPv4-mapped IPv6 address

IPv4-mapped IPv6 addresses are a special type of IPv6 addresses used to represent an IPv4 address in an IPv6 format. This can be particularly useful in a

notes.networklessons.com

 

The syntax for an IPv4-mapped IPv6 address is ::FFFF:w.x.y.z, where w.x.y.z is the decimal representation of the IPv4 address.
For example, the IPv4-mapped IPv6 address of 
192.0.2.128 is 
::FFFF:192.0.2.128

출처 : https://notes.networklessons.com/ipv6-ipv4-mapped-ipv6-address

 

 

ㅇㅎ192.168.10.13을 IPv6에서는 ::FFFF:192.168.10.13으로 나타내기 가능하다한다 그러면

127.0.0.1은 ::FFFF:172.0.0.1로 나타내기 가능하다는 소리

 

::ffff:127.0.0.1

시도해보자

 

 

짜자잔~

DH{L0C4L_En0ugh_IPv4_mapped_v6-a44dc189}