
urllib.parse와 requests 간의 URL 파서 차이를 통한 SSRF 악용을 시연하며, 취약한 서비스와 PoC 익스플로잇 스크립트를 포함합니다.
# vulnerable_service.py - Validates URL with urllib.parse, fetches with requests
from flask import Flask, request
import requests
import urllib.parse
app = Flask(__name__)
def is_allowed_url(url):
parsed = urllib.parse.urlparse(url)
# Only allow http://localhost and http://127.0.0.1
return parsed.hostname in ('localhost', '127.0.0.1')
@app.route('/fetch')
def fetch():
url = request.args.get('url')
if not is_allowed_url(url):
return "Blocked", 403
# Fetch with requests (different parser)
r = requests.get(url, timeout=5)
return r.text
if __name__ == '__main__':
app.run(port=5000)
한 서비스가 urllib.parse.urlparse를 사용하여 URL을 검증하지만, 이후 requests 라이브러리로 해당 URL을 가져옵니다. 두 파서가 특수 문자(예: @)를 처리하는 방식의 차이로 인해 공격자가 화이트리스트를 우회하고 내부 리소스에 접근할 수 있습니다.
urlparse는 [email protected]을 호스트 이름이 localhost인 것으로 처리하는 반면(@ 앞부분은 사용자 이름), requests는 호스트를 evil.com으로 해석합니다.pip install flask requests
python vulnerable_service.py
python exploit_ssrf_parser_diff.py