Post

TFC CTF 2023 - BABY DUCKY NOTES

Description

  • Category: Web
  • Difficulty: WARMUP
  • Points: 50050

Quack quack! Try and huack me!

Download:

Resolution

After some research in the web app source, we found some interesting info:

  • in src/database/database.py, we can see that the flag is inside a post created by the user with an id of 1 which can only be the admin (the first user) and most importantly the post is not hidden:
    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
    
    def db_init():
      con = sqlite3.connect('database/data.db')
      # Create users database
      query(con, '''
      CREATE TABLE IF NOT EXISTS users (
          id integer PRIMARY KEY,
          username text NOT NULL,
          password text NOT NULL
      );
      ''')
                
      query(con, f'''
      INSERT INTO users (
          username,
          password
          ) VALUES (
              'admin',
              '{os.environ.get("ADMIN_PASSWD")}'
            
      );
      ''')
        
      # Create posts database
     
      query(con, ''' 
      CREATE TABLE IF NOT EXISTS posts (
          id integer PRIMARY KEY,
          user_id integer NOT NULL,
          title text,
          content text NOT NULL,
          hidden boolean NOT NULL,
          FOREIGN KEY (user_id) REFERENCES users (id)
      );
      ''')
    
    
      query(con, f''' 
      INSERT INTO posts (
          user_id,
          title,
          content,
          hidden
          ) VALUES (
              1,
              'Here is a ducky flag!',
              '{os.environ.get("FLAG")}',
              0
            
      );
      ''')
    
      con.commit()
    
  • in src/routes.py, there is a route where we can retrieve all posts from any user:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @web.route('/posts/view/<user>', methods=['GET'])
    @auth_required
    def posts_view(username, user):
        try:
            posts = db_get_user_posts(user, username == user)
        except:
            raise Exception(username)
    
        return render_template('posts.html', posts=posts)
    

Knowing those information, we go to http://challs.tfcctf.com:{CONTAINER_PORT}/posts/view/admin to see all the posts from admin.

And we get the flag: TFCCTF{Adm1n_l0St_h1s_m1nd!}.

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