Read The Rules
Inspect trang https://ctf.nahamcon.com/rules
và tìm được flag:
<!-- Main CTF - Read The Rules: flag{90bc54705794a62015369fd8e86e557b} -->
The Oddyssey
Cứ gõ thật nhiều ký tự cho đến khi hết sách. Dùng khả năng tìm kiếm của terminal để tìm flag.
Press enter to continue...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
one piece with the seat itself; and it was covered with a thick fleece: on this she now sat, and the maids came from the women's room to join her. They set about removing the tables at which the wicked suitors had been dining, and took away the bread that was left, with the cups from which they had drunk. They emptied the embers out of the braziers, and heaped much wood upon them to give both light and heat; but Melantho began to rail at Ulysses a second time and said, "Stranger, do you mean to plague us by
Press enter to continue...
hanging about the house all night and spying upon the women? Be off, you wretch, outside, and eat your supper there, or you shall be driven out with a firebrand." Ulysses scowled at her and answered, "flag{0b51aae6b09b85d1bb13b0b8c3003a6a}". Penelope remarked "that's kind of a weird thing to say in this context." To which Ulysses responded "yeah I don't know, it kinda just came to me ¯\_(ツ)_/¯" Then Ulysses said "My good woman, why should you be so angry with me? Is it because I am not clean, and my clothes are all in rags, and because I am obliged to go
Quartet
➜ Downloads cat quartet.z0* > quartet.zip
➜ Downloads l
total 4.1M
drwxrwxrwx 1 aleister aleister 512 May 24 08:40 .
drwxrwxrwx 1 aleister aleister 512 May 24 08:37 ..
-rwxrwxrwx 1 aleister aleister 117K May 24 08:38 free_flags.txt
-rwxrwxrwx 1 aleister aleister 68 May 18 13:21 FWJJVZPE24.txt
-rwxrwxrwx 1 aleister aleister 497K May 24 08:36 quartet.z01
-rwxrwxrwx 1 aleister aleister 497K May 24 08:21 quartet.z02
-rwxrwxrwx 1 aleister aleister 497K May 24 08:21 quartet.z03
-rwxrwxrwx 1 aleister aleister 493K May 24 08:22 quartet.z04
-rwxrwxrwx 1 aleister aleister 2.0M May 24 08:40 quartet.zip
➜ Downloads unzip quartet.zip warning [quartet.zip]: 1526784 extra bytes at beginning or within zipfile
(attempting to process anyway)
quartet.jpeg
Archive: quartet.zip
warning [quartet.zip]: zipfile claims to be last disk of a multi-part archive;
attempting to process anyway, assuming all parts have been concatenated
together in order. Expect "errors" and warnings...true multi-part support
doesn't exist yet (coming soon).
warning [quartet.zip]: 1526784 extra bytes at beginning or within zipfile
(attempting to process anyway)
file #1: bad zipfile offset (local header sig): 1526788
(attempting to re-compensate)
inflating: quartet.jpeg
➜ Downloads l
total 6.0M
drwxrwxrwx 1 aleister aleister 512 May 24 08:40 .
drwxrwxrwx 1 aleister aleister 512 May 24 08:37 ..
-rwxrwxrwx 1 aleister aleister 117K May 24 08:38 free_flags.txt
-rwxrwxrwx 1 aleister aleister 68 May 18 13:21 FWJJVZPE24.txt
-rwxrwxrwx 1 aleister aleister 2.0M May 10 15:28 quartet.jpeg
-rwxrwxrwx 1 aleister aleister 497K May 24 08:36 quartet.z01
-rwxrwxrwx 1 aleister aleister 497K May 24 08:21 quartet.z02
-rwxrwxrwx 1 aleister aleister 497K May 24 08:21 quartet.z03
-rwxrwxrwx 1 aleister aleister 493K May 24 08:22 quartet.z04
-rwxrwxrwx 1 aleister aleister 2.0M May 24 08:40 quartet.zip
➜ Downloads strings quartet.jpeg | grep flag
flag{8f667b09d0e821f4e14d59a8037eb376}
Naham-Commencement 2025
Inspect trang thì thấy có đoạn code JavaScript được dùng để validate client-side:
const x1 = "dqxqcius";
const x2 = "YeaTtgUnzezBqiwa2025";
const x3 = "ZHF4cWNpdXM=";
const k = "nahamcon";
const f = document.getElementById('loginForm');
const u = document.getElementById('username');
const p = document.getElementById('password');
const s = document.getElementById('spinner');
const d = document.getElementById('result');
f.addEventListener('submit', function (e) {
e.preventDefault();
const q = u.value;
const w = p.value;
const q1 = a(q);
const w1 = b(w, k);
if (q1 !== x1 || w1 !== x2) {
d.textContent = "Access denied. Client-side validation failed. Try again.";
d.className = "error";
d.style.display = "block";
return;
}
Hàm a
và b
function a(t) {
let r = '';
for (let i = 0; i < t.length; i++) {
const c = t[i];
if (/[a-zA-Z]/.test(c)) {
const d = c.charCodeAt(0);
const o = (d >= 97) ? 97 : 65;
const x = (d - o + 16) % 26 + o;
r += String.fromCharCode(x);
} else {
r += c;
}
}
return r;
}
function b(t, k) {
let r = '';
let j = 0;
for (let i = 0; i < t.length; i++) {
const c = t[i];
if (/[a-zA-Z]/.test(c)) {
const u = c === c.toUpperCase();
const l = c.toLowerCase();
const d = l.charCodeAt(0) - 97;
const m = k[j % k.length].toLowerCase();
const n = m.charCodeAt(0) - 97;
const e = (d + n) % 26;
let f = String.fromCharCode(e + 97);
if (u) {
f = f.toUpperCase();
}
r += f;
j++;
} else {
r += c;
}
}
return r;
}
Reverse 2 hàm này sử dụng Gemini:
function decodeA(encodedString) {
let decodedResult = '';
for (let i = 0; i < encodedString.length; i++) {
const char = encodedString[i];
// Check if the character is a letter
if (/[a-zA-Z]/.test(char)) {
const charCode = char.charCodeAt(0);
// Determine if it's lowercase or uppercase to set the base
const base = (charCode >= 97) ? 97 : 65;
// Reverse the shift: subtract 16 (or add 10) and handle wrap-around
const originalCharCode = (charCode - base - 16 + 26) % 26 + base;
decodedResult += String.fromCharCode(originalCharCode);
} else {
// If it's not a letter, keep it as is
decodedResult += char;
}
}
return decodedResult;
}
Gọi hàm này với input là "dqxqcius"
ta được "nahamsec"
function decodeB(encodedString, key) {
let decodedResult = '';
let keyIndex = 0;
for (let i = 0; i < encodedString.length; i++) {
const char = encodedString[i];
// Check if the character is an alphabet letter
if (/[a-zA-Z]/.test(char)) {
// Preserve the original case (uppercase or lowercase)
const isUpperCase = char === char.toUpperCase();
const lowerChar = char.toLowerCase();
// 1. Get the 0-25 position of the ENCODED character
const encodedCharPos = lowerChar.charCodeAt(0) - 97;
// 2. Get the 0-25 position of the current KEY character
// The key repeats, so we use the modulo operator
const lowerKeyChar = key[keyIndex % key.length].toLowerCase();
const keyCharPos = lowerKeyChar.charCodeAt(0) - 97;
// 3. REVERSE the encryption: subtract the key's position from the
// encoded character's position to find the original position.
// We add 26 to prevent the result from being negative.
const originalCharPos = (encodedCharPos - keyCharPos + 26) % 26;
// 4. Convert the original position back to a letter
let originalChar = String.fromCharCode(originalCharPos + 97);
// 5. Restore the original case
if (isUpperCase) {
originalChar = originalChar.toUpperCase();
}
decodedResult += originalChar;
// IMPORTANT: Increment the key index only for letters,
// matching the logic of the original function.
keyIndex++;
} else {
// If it's not a letter, keep it as is
decodedResult += char;
}
}
return decodedResult;
}
Gọi hàm này với input là "YeaTtgUnzezBqiwa2025", "nahamcon"
ta được "LetTheGamesBegin2025"
,
Đăng nhập và nhận được flag: flag{c419dfe3a0a621edc0150a133bb7a34c}
.
Free Flags!
Theo rule thì flag là các hexadecimal characters không viết hoa:
Cite
Flags for this competition will follow the format:
flag\{[0-9a-f]{32}\}
. That means aflag{}
wrapper with a 32-character lowercase hex string inside