V0lk3n's Blog

Welcome to my personal blog, here you can find some of my work.

View on GitHub

Insomni’hack CTF 2024 - WriteUp

Written by V0lk3n

Scoreboard

At the time we leaved

There was a total of 109 Teams playing that CTF

Final Scoreboard (CTFTime Based)

There was a total of 92 Teams playing that CTF (Don’t know why there is less team than in place)

Author Notes

As alway this was an amazing two days event! The talk was so nice! And the CTF had a very good atmosphere as alway.

Insomni'hack is one of my best experiance in my LIFE!

About the CTF. This time we managed to solve three warmup challenge. Compared to the last year where we managed to solve only the welcome challenge, this is a great progress!

Thanks so much to the organizers for this event, i just can't wait next year to attend this again!

-V0lk3n

Table of Contents

Cryptography

Textbook

Challenge :

Attachments :

Solution

In this challenge, we go two files. A python script called TextbookRSA.py with the following content.

import binascii

def string_to_big_number(s):
    hex_string = s.encode("utf-8").hex()
    return int(hex_string, 16)

def big_number_to_string(n):
    hex_string = hex(int(n))[2:]  # Remove '0x' prefix
    if len(hex_string) % 2 != 0:
        hex_string = "0" + hex_string  # Ensure even length
    byte_string = binascii.unhexlify(hex_string)
    return byte_string.decode("utf-8")

# textbook RSA encryption
# e and n are the public key of the RSA encryption
# plaintext is a number representing a string, probably generated by the usage of `string_to_big_number(s)`
def encrypt(e, n, plaintext):
    cipher = pow(plaintext, e, n)
    return cipher

if __name__ == "__main__":
    n = 27079057133799412050574271437008052479608241223378451645921828586987123275384389661190553748448131519947241422660530887207052569407854395838748787042401384171004075065289693865326335229373180653322729951129863580393632355060254900268199341538759231436658420086612699118387712385798095800079241523407995250557541194616409131909211593714204924250020714684886257490233315018260104680317027639085285801307224595400670158526070066366240039167026375801898715172465640224571404900157050983353328416661007442709676702248323670028687937388451334051028292837462090344713796045666811858601266699076083800170158980716593299585259
    e = 3
    print("Public keys:", e, n)
  
    content = "???????????????????????????????????????????????????????????"
    flag = "INS{" + content + "}"
    assert(len(flag) == 64)

    # perform the encryption
    flag_num = string_to_big_number(flag)
    encrypted_msg = encrypt(e, n, string_to_big_number(flag))
    print("Encrypted message:", encrypted_msg)

And a text file called output.txt with the following content.

Public keys: 3 27079057133799412050574271437008052479608241223378451645921828586987123275384389661190553748448131519947241422660530887207052569407854395838748787042401384171004075065289693865326335229373180653322729951129863580393632355060254900268199341538759231436658420086612699118387712385798095800079241523407995250557541194616409131909211593714204924250020714684886257490233315018260104680317027639085285801307224595400670158526070066366240039167026375801898715172465640224571404900157050983353328416661007442709676702248323670028687937388451334051028292837462090344713796045666811858601266699076083800170158980716593299585259
Encrypted message: 56594121677997752220607276431829700482790934399952073873985673376275627839001844292485471807397871097275395609294585018857153433532241532955624760068010089737094396465889850992818015700654441456736195039510931432278419326554279365041295917253950911528145497289077466288304560003359935645326885952227561526993962879620894932357491692265941378691020322367234989484400147908675111983459941244440416401817013935255897074795208750963711463596125595936659690953487717

Reading at the python script we understand that the first line of the output is the exponent (e) followed by the modulus (n).

The second line contain the encrypted flag (c).

Our goal is to decrypt the flag, and to solve it i used the RSA Decoder from dcode and supplied the exponent, modulus and cipher (encrypted flag) to retrieve the flag.

Once decoded we retrieve the flag.

FLAG : INS{Ins3cur3-textb000k-RSA-47d1cbb3-f276-40e9-8ca7-2f7ce0d4fbb8}

Web

LetMeIn

Challenge :

Attachment :

Solution

In this challenge, we got a python source code called app.py of the web app running on https://letmein.insomnihack.ch:5000/.

Bellow is the source code :

from flask import Flask, render_template, request 
from flask_sqlalchemy import SQLAlchemy
from const import FLAG, CRENDENTIALS

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f'postgresql://{CRENDENTIALS}@db:5432/application'
db = SQLAlchemy(app)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login', methods=['GET','POST'])
def login():
    if request.method == 'GET':
        return render_template('index.html')

    username = request.form['username']
    password = request.form['password']

    if username != 'admin' or password[:5] != 'admin' or password[-5:] != 'admin':
        return 'Login failed. Please check your username and password.'


    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    user = db.session.execute(db.text(query)).fetchone()

    if user:
        return 'Hello admin ' + FLAG
    else:
        return 'Login failed. Please check your username and password.'

if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0')

So it’s a Flask app with a login form using SQLAlchemy. Looking at the web app, and trying to login with random credentials we can see that there is a restriction.

For a better request management, i used BurpSuite to solve this challenge.

Now let’s get back to the source code, and analyse it.

First, let’s see our goal.

    if user:
        return 'Hello admin ' + FLAG
    else:
        return 'Login failed. Please check your username and password.'

As we can see, we need to login as “admin” to retrieve the flag. And as we can see bellow, we should be able to exploit a SQL Injection on username and password field.

    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    user = db.session.execute(db.text(query)).fetchone()

But here is the real challenge. We need to respect the condition bellow while exploiting the SQL Injection.

    if username != 'admin' or password[:5] != 'admin' or password[-5:] != 'admin':
        return 'Login failed. Please check your username and password.'

So, our username should be admin. This mean that we can’t exploit an SQL injection in username field, because for example admin' is not equal to admin because of the quote.

Also, the first five letter of the password should be admin and the last five letter of the password should be admin.

After analyzing it, we understand that we can exploit our SQL Injection in the middle of the password. For example : admin'admin respect the condition, because the five first and last letter of the password is admin.

After trying few payload, we managed to exploit it with success using admin' or 1=1 --admin as password payload.

As i used burp, i needed to URL encode the payload to send the request. Thats why the password is admin'+or+1%4d1+--admin. (The space is converted with +, and the equal is converted to %3d)

And trying the SQL injection directly on the web.

FLAG : INS{SQL-1nj3ct1on-in-2o24-1e62fb02-d618-48a4-9e4b-6cffd4fc5856}

Credits

Special thanks to :

And of course…

Thanks to all my team Godzillhack!