SwampCTF25 | Challenge Writeups

#CTF/Events#writeups

Writeups for some of the challenges I solved from SwampCTF25.

SwampCTF25 | Challenge Writeups

I participated in the SwampCTF 2025, with my team ZeroSolves. These are the writeups for some of the challenges I solved/attempted.

Beginner Web

#CTF/Web#deobfuscation#javascript#decryption

Challenge Description

Hey, my son Timmy made his first website. He said he hid a ‘secret’ message within different parts of the website… can you find them all? I wanna make sure he isn’t saying any swear words online. The flag is broken up into 3 parts. The parts of the flag should be concatenated in the order they are numbered and then surrounded by the standard wrapper. For example: ‘swampCTF{’ + part1 + part2 + part3 + ‘}’ http://chals.swampctf.com/

Solution

We get the first part of the flag by simply looking at the source of the website.

<!--Part 1 of the flag: w3b_"-->

deobfuscated main-34VY7I6V.js reveals the way to decrypt the remaining part of the flags.

import { Component, Inject } from '@angular/core';
import { CookieService } from 'ngx-cookie-service';
import * as CryptoJS from 'crypto-js';
@Component({
selector: 'app-root',
template: `
<p>Is it Tuesday?</p>
<p *ngIf="date.getDay() === 2">Yes</p>
<p *ngIf="date.getDay() !== 2">No</p>
`,
styles: [
`
p {
font-family: Comic Sans MS, cursive, sans-serif;
font-size: 24px;
color: #ff69b4;
text-shadow: 2px 2px 5px yellow;
background: repeating-linear-gradient(45deg, #0ff, #f0f 10%, #ff0 20%);
padding: 10px;
border: 5px dashed lime;
transform: rotate(-5deg);
animation: wiggle 0.1s infinite alternate;
}
@keyframes wiggle {
0% { transform: rotate(-5deg); }
100% { transform: rotate(5deg); }
}
`
]
})
export class AppComponent {
date = new Date();
constructor(private cookieService: CookieService) {
const key = 'flagPart2_3';
const encryptedFlagPart2 = 'U2FsdGVkX1/oCOrv2BF34XQbx7f34cYJ8aA71tr8cl8=';
const encryptedFlagPart3 = 'U2FsdGVkX197aFEtB5VUIBcswkWs4GiFPal6425rsTU=';
// Decrypt and set flagPart2 in a cookie
const decryptedFlagPart2 = CryptoJS.AES.decrypt(encryptedFlagPart2, key).toString(CryptoJS.enc.Utf8);
this.cookieService.set('flagPart2', decryptedFlagPart2, {
expires: 7,
path: '/',
secure: true,
sameSite: 'Strict'
});
// Decrypt flagPart3 and send it in a fetch request header
const decryptedFlagPart3 = CryptoJS.AES.decrypt(encryptedFlagPart3, key).toString(CryptoJS.enc.Utf8);
const headers = new Headers();
headers.set('flagPart3', decryptedFlagPart3);
fetch('/favicon.ico', { headers });
}
}

decrypt the flags

const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js';
script.onload = function() {
const key = 'flagPart2_3';
const encryptedFlagPart2 = 'U2FsdGVkX1/oCOrv2BF34XQbx7f34cYJ8aA71tr8cl8=';
const encryptedFlagPart3 = 'U2FsdGVkX197aFEtB5VUIBcswkWs4GiFPal6425rsTU=';
console.log(CryptoJS.AES.decrypt(encryptedFlagPart2, key).toString(CryptoJS.enc.Utf8));
console.log(CryptoJS.AES.decrypt(encryptedFlagPart3, key).toString(CryptoJS.enc.Utf8));
};
document.head.appendChild(script);

decrypted flags:

Encrypted flagPart2: U2FsdGVkX1/oCOrv2BF34XQbx7f34cYJ8aA71tr8cl8=
Decrypted: br0w53r5_4r3_
Encrypted flagPart3: U2FsdGVkX197aFEtB5VUIBcswkWs4GiFPal6425rsTU=
Decrypted: c0mpl1c473d

Resulting flag:

Terminal window
swampCTF{w3b_br0w53r5_4r3_c0mpl1c473d}

Blue

#CTF/DFIR#Azure

Challenge Description

The SwampCTF team is trying to move our infrastructure to the cloud. For now, we’ve made a storage account called swampctf on Azure. Can you test our security by looking for a flag?The SwampCTF team is trying to move our infrastructure to the cloud. For now, we’ve made a storage account called swampctf on Azure. Can you test our security by looking for a flag?

Solution

Enumerating the azure file resources leads us to https://swampctf.blob.core.windows.net

Then fuzz for containers https://swampctf.blob.core.windows.net/FUZZ?comp=list

Visit: https://swampctf.blob.core.windows.net/test/flag_020525.txt for the flag

References

Hidden Message Board

#CTF/Web#javascript

Solution

<div style="display: none;">Need to remove flagstuff. code: G1v3M3Th3Fl@g!!!!</div>

Looking the source code we notice a function named checkcode which prints out the flag if proper attribute is set:

function App() {
_s();
const defaultValue = "";
const [currentMessage, setMessageBoxValue] = react__WEBPACK_IMPORTED_MODULE_2___default().useState(defaultValue);
const [flagGoesHere, setFlagValue] = (0,react__WEBPACK_IMPORTED_MODULE_2__.useState)("");
const divRef = react__WEBPACK_IMPORTED_MODULE_2___default().useRef(null);
const [lotteryNumber, setLotteryNumber] = (0,react__WEBPACK_IMPORTED_MODULE_2__.useState)(5);
const [totalNumbers, setTotalNumber] = (0,react__WEBPACK_IMPORTED_MODULE_2__.useState)(100);
var printFlagSetup = document.getElementById("flagstuff");
console.log("Flag Will Be Checked");
function addNewMessages(event) {
event.preventDefault();
if (currentMessage != "") {
if (printFlagSetup != undefined) {
printFlagSetup.setAttribute("code", "");
}
addNewMessageChance();
divRef.current.innerHTML = "<b>[swampctfcontestant]: </b>" + currentMessage + "<br>" + divRef.current.innerHTML;
addNewMessageChance();
setMessageBoxValue(defaultValue);
}
}
function addNewMessageChance() {
var willTypeMessage = Math.floor(Math.random() * totalNumbers);
if (willTypeMessage <= lotteryNumber) {
divRef.current.innerHTML = (0,_Messages_tsx__WEBPACK_IMPORTED_MODULE_3__.returnRandomResponses)() + divRef.current.innerHTML;
willTypeMessage = Math.floor(Math.random() * 100);
}
}
function updateMessageBox(newTextBoxValue) {
setMessageBoxValue(newTextBoxValue);
addNewMessageChance();
}
async function checkCode() {
if (printFlagSetup != undefined) {
console.log(printFlagSetup.getAttribute("code"));
if (printFlagSetup.getAttribute("code") === "G1v3M3Th3Fl@g!!!!") {
const flag = await (0,_Messages_tsx__WEBPACK_IMPORTED_MODULE_3__.getFlag)();
setFlagValue("[flag]: " + flag);
}
}
}
checkCode();
return
...
);

set code attribute to whatever is expected:

document.getElementById("flagstuff").setAttribute("code","G1v3M3Th3Fl@g!!!!");

And get the flag:

Homework Help

#CTF/DFIR#autopsy

I accidently lost some of my class notes! Can you help me recover it?

Challenge Description

I accidently lost some of my class notes! Can you help me recover it? (Note: Unzipped size is 4GB)

Solution

Run autopsy on .vhd file

From the extracted docx file

Muddy Water

#CTF/DFIR#tshark#PCAP/analysis#hashcat

We caught a threat actor, called MuddyWater, bruteforcing a login for our Domain Controller. We have a packet capture of the intrusion. Can you figure out which account they logged in to and what the password is?

Challenge Description

We caught a threat actor, called MuddyWater, bruteforcing a login for our Domain Controller. We have a packet capture of the intrustion. Can you figure out which account they logged in to and what the password is? Flag format is swampCTF{<username>:<password>}

Solution

get the ips

Terminal window
tshark -nr muddywater.pcap -Y "smb2" -T fields -e ip.src -e ip.dst | sort | uniq -c
13670 192.168.122.1 192.168.122.73 18223 192.168.122.73 192.168.122.1

filter successfull auth

Terminal window
tshark -nr muddywater.pcap -Y "((ip.src == 192.168.122.1 || ip.src == 192.168.122.73) && (ip.dst == 192.168.122.1 || ip.dst == 192.168.122.73)) && smb2.cmd == 1 && smb2.nt_status == 0x0"

get the stream index

Terminal window
tshark -nr muddywater.pcap -Y "frame.number == 72069" -V -T json > frame-72069.json

Looking for NTLM authentication flow

Terminal window
tshark -nr muddywater.pcap -Y "tcp.stream eq 6670"
<...>
72064 65.215194 192.168.122.1 192.168.122.73 SMB2 212 Session Setup Request, NTLMSSP_NEGOTIATE 72065 65.215719 192.168.122.73 192.168.122.1 SMB2 401 Session Setup Response, Error: STATUS_MORE_PROCESSING_REQUIRED, NTLMSSP_CHALLENGE 72069 65.220368 192.168.122.1 192.168.122.73 SMB2 546 Session Setup Request, NTLMSSP_AUTH, User: DESKTOP-0TNOE4V\hackbackzip
<...>

Build hashcat compatible hash for cracking: username::domain:challenge:NTLM_response

Terminal window
tshark -nr muddywater.pcap -Y "frame.number == 72064 || frame.number == 72065 || frame.number == 72069" -O smb2,ntlmssp -T fields -e ntlmssp.auth.username -e ntlmssp.auth.domain -e ntlmssp.ntlmserverchallenge -e ntlmssp.ntlmv2_response.ntproofstr -e ntlmssp.ntlmv2_response
d102444d56e078f4 hackbackzip DESKTOP-0TNOE4V eb1b0afc1eef819c1dccd514c9623201 eb1b0afc1eef819c1dccd514c962320101010000000000006f233d3d9f9edb01755959535466696d0000000002001e004400450053004b0054004f0050002d00300054004e004f0045003400560001001e004400450053004b0054004f0050002d00300054004e004f0045003400560004001e004400450053004b0054004f0050002d00300054004e004f0045003400560003001e004400450053004b0054004f0050002d00300054004e004f00450034005600070008006f233d3d9f9edb010900280063006900660073002f004400450053004b0054004f0050002d00300054004e004f004500340056000000000000000000

crack the hash

Terminal window
hashcat -a 0 -m 5600 ntlm.hash rockyou.txt
HACKBACKZIP::DESKTOP-0TNOE4V:d102444d56e078f4:eb1b0afc1eef819c1dccd514c9623201:01010000000000006f233d3d9f9edb01755959535466696d0000000002001e004400450053004b0054004f0050002d00300054004e004f0045003400560001001e004400450053004b0054004f0050002d00300054004e004f0045003400560004001e004400450053004b0054004f0050002d00300054004e004f0045003400560003001e004400450053004b0054004f0050002d00300054004e004f00450034005600070008006f233d3d9f9edb010900280063006900660073002f004400450053004b0054004f0050002d00300054004e004f004500340056000000000000000000:pikeplace

Planetary Storage

#CTF/DFIR#levelDB

My friend found this strang file while perusing his computer, but we can't read it. Can you figure out what it is and get the information from it?

Challenge Description

My friend found this strange file while perusing his computer, but we can’t read it. Can you figure out what it is and get the information from it? Difficulty: Easy/Medium The flag is in the standard format.

Solution

Terminal window
$ LevelDBDumper -d challenge -o dumped

dumped data

"[{""payload"":""eyJrZXkiOiJcIjMzNTc5M2Q1LTRhYzEtNDgyMy05MmM3LWZkM2I1YTZhMmEwN1wiIiwib3AiOiJQVVQiLCJ2YWx1ZSI6ImV5SmtZWFJoSWpwYkluTjNZVzF3UTFSR2V6RndaalV0WWpRMU0yUXRaRFEzTkdJME5UTjlJbDBzSW1sa0lqb2lYQ0l6TXpVM09UTmtOUzAwWVdNeExUUTRNak10T1RKak55MW1aRE5pTldFMllUSmhNRGRjSWlKOSJ9"",""id"":""/orbitdb/bafyreiejrtaennxufa3wvkdvyoj6ywq6nid3lukdqcnx2fc33tckzjzbke/ctf"",""next"":[{""/"":""bafyreibbadm2ajrr6io6ufqidibrpdjfpdyfobp2aqvmcprqu5yrk7mq6q""}],""refs"":[{""/"":""bafyreiesvykh6wt7hn4fry4mphv6ckxr5wq3c2fecvcjbqs4scbkizc6jm""},{""/"":""bafyreihq7osywkglsjxn5lmbegtc7izqmb66atx5trkrpcmlvtcyrr6nuy""},{""/"":""bafyreiab6do7qxgjipiypoj754vicpuscejf43eguvo2ykb2igoyrtkl64""}],""v"":2,""key"":""BJx/DXfZOVG6YkoHDGQvNQVMBaoeaEdEvcKFJP0PM1m3h9/o8lJgnTQkqGCAKovuOCovsDHQ5JOVs7qpJm3V8Ks="",""sig"":""MEQCIF5FwOBiQKgEI7njg6He6iAlwNc+Gj8+PAll5o1PCGhKAiBlnXg9+hinX6AGB2r0uXoJ3q9Tbe6azh9euPx40G8uqw=="",""identity"":{""id"":""02020192715ea41d7eaaceb4bd19516d0d4f1e8a2e81903480083dbdbe99dfefc9"",""publicKey"":""BJx/DXfZOVG6YkoHDGQvNQVMBaoeaEdEvcKFJP0PM1m3h9/o8lJgnTQkqGCAKovuOCovsDHQ5JOVs7qpJm3V8Ks="",""signatures"":{""id"":""MEQCIGx+GRqmTfPqcUL28aG2p1Q2TNEfZ9QlCgB8WU4my68UAiBZClP9WMe385COJ0WuNnXRj7BIolRC2v6vhLqUt3Yk/w=="",""publicKey"":""MEQCIFC+7AikjMLabNvdHiHh7rwrFTbystu6xc2r1h/1Zr4jAiBFxjxIMNjfI5J996HDYEQd+fnaKDi5GlNw5hgl+RwEOg==""},""type"":""orbitdb"",""Provider"":null},""hash"":{""/"":""bafyreihq6d33ifjj6jbmjptygyksgwzcrjm5kxarbbp6djbzqx2exij27u""},""clock"":{""id"":""BJx/DXfZOVG6YkoHDGQvNQVMBaoeaEdEvcKFJP0PM1m3h9/o8lJgnTQkqGCAKovuOCovsDHQ5JOVs7qpJm3V8Ks="",""time"":7}}]"

Decode base64 payload

Terminal window
echo 'eyJrZXkiOiJcIjMzNTc5M2Q1LTRhYzEtNDgyMy05MmM3LWZkM2I1YTZhMmEwN1wiIiwib3AiOiJQVVQiLCJ2YWx1ZSI6ImV5SmtZWFJoSWpwYkluTjNZVzF3UTFSR2V6RndaalV0WWpRMU0yUXRaRFEzTkdJME5UTjlJbDBzSW1sa0lqb2lYQ0l6TXpVM09UTmtOUzAwWVdNeExUUTRNak10T1RKak55MW1aRE5pTldFMllUSmhNRGRjSWlKOSJ9' | base64 -d
{"key":"\"335793d5-4ac1-4823-92c7-fd3b5a6a2a07\"","op":"PUT","value":"eyJkYXRhIjpbInN3YW1wQ1RGezFwZjUtYjQ1M2QtZDQ3NGI0NTN9Il0sImlkIjoiXCIzMzU3OTNkNS00YWMxLTQ4MjMtOTJjNy1mZDNiNWE2YTJhMDdcIiJ9"}%
echo 'eyJkYXRhIjpbInN3YW1wQ1RGezFwZjUtYjQ1M2QtZDQ3NGI0NTN9Il0sImlkIjoiXCIzMzU3OTNkNS00YWMxLTQ4MjMtOTJjNy1mZDNiNWE2YTJhMDdcIiJ9' | base64 -d
{"data":["swampCTF{1pf5-b453d-d474b453}"],"id":"\"335793d5-4ac1-4823-92c7-fd3b5a6a2a07\""}

Preferential Treatment

#CTF/DFIR#wireshark#gpp-decrypt#PCAP/analysis

We have an old Windows Server 2008 instance that we lost the password for. Can you see if you can find one in this packet capture?

Challenge Description

We have an old Windows Server 2008 instance that we lost the password for. Can you see if you can find one in this packet capture?

Solution

conversation -> tcp 1 -> follow stream

Decrypt cpassword with gpp-password

Terminal window
gpp-decrypt dAw7VQvfj9rs53A8t4PudTVf85Ca5cmC1Xjx6TpI/cS8WD4D8DXbKiWIZslihdJw3Rf+ijboX7FgLW7pF0K6x7dfhQ8gxLq34ENGjN8eTOI=
swampCTF{4v3r463_w1nd0w5_53cur17y}